root/gsdl/trunk/src/recpt/collectoraction.cpp @ 15597

Revision 15597, 50.8 KB (checked in by mdewsnip, 12 years ago)

Removed "gdbm" from a couple of comments.

  • Property svn:keywords set to Author Date Id Revision
Line 
1/**********************************************************************
2 *
3 * collectoraction.cpp --
4 * Copyright (C) 2000  The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26#include "gsdl_modules_cfg.h"
27#ifdef GSDL_USE_COLLECTOR_ACTION
28
29// note that the collectoraction relies on having direct access to a
30// collections configuration file. this breaks the separation between
31// receptionist and collection server and so is not suitable (at least
32// in its current form) for use when collection servers are separate
33// from the receptionist (e.g. when using the CORBA protocol).
34
35// following line required to get fstream.filedesc() on darwin (Mac OS X)
36#define _STREAM_COMPAT  1
37// required for utsname on solaris???
38#define _XOPEN_SOURCE 1
39#define _XOPEN_SOURCE_EXTENDED 1
40
41#include "collectoraction.h"
42#include "OIDtools.h"
43#include "fileutil.h"
44#include "cfgread.h"
45#include "gsdltools.h"
46#include "gsdltimes.h"
47#include "argdb.h"
48#include "cgiutils.h"
49#include <stdio.h>
50#include <fcntl.h>
51#include <sys/stat.h>
52
53#if !defined (__WIN32__)
54#include <sys/utsname.h>
55#include <unistd.h>
56#endif
57
58collectoraction::collectoraction ()
59  : wizardaction()
60{
61  macro_prefix = "bc1";
62
63  do_mkcol = false;
64  badsources = false;
65  failedsources.erase(failedsources.begin(), failedsources.end());
66
67  cgiarginfo arg_ainfo;
68  arg_ainfo.shortname = "a";
69  arg_ainfo.longname = "action";
70  arg_ainfo.multiplechar = true;
71  arg_ainfo.defaultstatus = cgiarginfo::weak;
72  arg_ainfo.argdefault = "collector";
73  arg_ainfo.savedarginfo = cgiarginfo::must;
74  argsinfo.addarginfo (NULL, arg_ainfo);
75
76  arg_ainfo.shortname = "p";
77  arg_ainfo.longname = "page";
78  arg_ainfo.multiplechar = true;
79  arg_ainfo.defaultstatus = cgiarginfo::weak;
80  arg_ainfo.argdefault = "intro";
81  arg_ainfo.savedarginfo = cgiarginfo::must;
82  argsinfo.addarginfo (NULL, arg_ainfo);
83
84  // temporary directory name for this collector
85  // session
86  arg_ainfo.shortname = "bc1tmp";
87  arg_ainfo.longname = "collector specific";
88  arg_ainfo.multiplechar = true;
89  arg_ainfo.defaultstatus = cgiarginfo::weak;
90  arg_ainfo.argdefault = g_EmptyText;
91  arg_ainfo.savedarginfo = cgiarginfo::must;
92  argsinfo.addarginfo (NULL, arg_ainfo);
93
94  arg_ainfo.shortname = "bc1fullname";
95  arg_ainfo.longname = "collector specific";
96  arg_ainfo.multiplechar = true;
97  arg_ainfo.defaultstatus = cgiarginfo::weak;
98  arg_ainfo.argdefault = g_EmptyText;
99  arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
100  argsinfo.addarginfo (NULL, arg_ainfo);
101
102  arg_ainfo.shortname = "bc1dirname";
103  arg_ainfo.longname = "collector specific";
104  arg_ainfo.multiplechar = true;
105  arg_ainfo.defaultstatus = cgiarginfo::weak;
106  arg_ainfo.argdefault = g_EmptyText;
107  arg_ainfo.savedarginfo = cgiarginfo::must;
108  argsinfo.addarginfo (NULL, arg_ainfo);
109
110  arg_ainfo.shortname = "bc1contactemail";
111  arg_ainfo.longname = "collector specific";
112  arg_ainfo.multiplechar = true;
113  arg_ainfo.defaultstatus = cgiarginfo::weak;
114  arg_ainfo.argdefault = g_EmptyText;
115  arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
116  argsinfo.addarginfo (NULL, arg_ainfo);
117
118  arg_ainfo.shortname = "bc1aboutdesc";
119  arg_ainfo.longname = "collector specific";
120  arg_ainfo.multiplechar = true;
121  arg_ainfo.defaultstatus = cgiarginfo::weak;
122  arg_ainfo.argdefault = g_EmptyText;
123  arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
124  argsinfo.addarginfo (NULL, arg_ainfo);
125
126  arg_ainfo.shortname = "bc1clone";
127  arg_ainfo.longname = "collector specific";
128  arg_ainfo.multiplechar = false;
129  arg_ainfo.defaultstatus = cgiarginfo::weak;
130  arg_ainfo.argdefault = "0";
131  arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
132  argsinfo.addarginfo (NULL, arg_ainfo);
133
134  arg_ainfo.shortname = "bc1clonecol";
135  arg_ainfo.longname = "collector specific";
136  arg_ainfo.multiplechar = true;
137  arg_ainfo.defaultstatus = cgiarginfo::weak;
138  arg_ainfo.argdefault = g_EmptyText;
139  arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
140  argsinfo.addarginfo (NULL, arg_ainfo);
141
142  // set when cloning option has changed
143  arg_ainfo.shortname = "bc1clonechanged";
144  arg_ainfo.longname = "collector specific";
145  arg_ainfo.multiplechar = false;
146  arg_ainfo.defaultstatus = cgiarginfo::weak;
147  arg_ainfo.argdefault = "0";
148  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
149  argsinfo.addarginfo (NULL, arg_ainfo);
150
151  // only set when one of the fields was changed in
152  // the "collection info" page
153  arg_ainfo.shortname = "bc1infochanged";
154  arg_ainfo.longname = "collector specific";
155  arg_ainfo.multiplechar = false;
156  arg_ainfo.defaultstatus = cgiarginfo::weak;
157  arg_ainfo.argdefault = "0";
158  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
159  argsinfo.addarginfo (NULL, arg_ainfo);
160
161  // only set when cfg file is altered from within
162  // "configure collection" page
163  arg_ainfo.shortname = "bc1cfgchanged";
164  arg_ainfo.longname = "collector specific";
165  arg_ainfo.multiplechar = false;
166  arg_ainfo.defaultstatus = cgiarginfo::weak;
167  arg_ainfo.argdefault = "0";
168  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
169  argsinfo.addarginfo (NULL, arg_ainfo);
170
171  arg_ainfo.shortname = "cfgfile";
172  arg_ainfo.longname = "configuration file contents";
173  arg_ainfo.multiplechar = true;
174  arg_ainfo.defaultstatus = cgiarginfo::weak;
175  arg_ainfo.argdefault = g_EmptyText;
176  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
177  argsinfo.addarginfo (NULL, arg_ainfo);
178
179  arg_ainfo.shortname = "bc1dodelete";
180  arg_ainfo.longname = "collector specific";
181  arg_ainfo.multiplechar = false;
182  arg_ainfo.defaultstatus = cgiarginfo::weak;
183  arg_ainfo.argdefault = "0";
184  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
185  argsinfo.addarginfo (NULL, arg_ainfo);
186
187  // will be set if we arrived at the "configure collection" page
188  // via the "changing an existing collection" page
189  arg_ainfo.shortname = "bc1econf";
190  arg_ainfo.longname = "collector specific";
191  arg_ainfo.multiplechar = false;
192  arg_ainfo.defaultstatus = cgiarginfo::weak;
193  arg_ainfo.argdefault = "0";
194  arg_ainfo.savedarginfo = cgiarginfo::must;
195  argsinfo.addarginfo (NULL, arg_ainfo);
196
197  // will be set if we arrived at the "source data" page
198  // via the "changing an existing collection" page
199  arg_ainfo.shortname = "bc1esrce";
200  arg_ainfo.longname = "collector specific";
201  arg_ainfo.multiplechar = false;
202  arg_ainfo.defaultstatus = cgiarginfo::weak;
203  arg_ainfo.argdefault = "0";
204  arg_ainfo.savedarginfo = cgiarginfo::must;
205  argsinfo.addarginfo (NULL, arg_ainfo);
206
207  arg_ainfo.shortname = "bc1inputnum";
208  arg_ainfo.longname = "collector specific";
209  arg_ainfo.multiplechar = true;
210  arg_ainfo.defaultstatus = cgiarginfo::weak;
211  arg_ainfo.argdefault = "3";
212  arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
213  argsinfo.addarginfo (NULL, arg_ainfo);
214
215  arg_ainfo.shortname = "bc1input";
216  arg_ainfo.longname = "collector specific";
217  arg_ainfo.multiplechar = true;
218  arg_ainfo.multiplevalue = true;
219  arg_ainfo.defaultstatus = cgiarginfo::weak;
220  arg_ainfo.argdefault = g_EmptyText;
221  arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
222  argsinfo.addarginfo (NULL, arg_ainfo);
223
224  arg_ainfo.shortname = "bc1inputtype";
225  arg_ainfo.longname = "collector specific";
226  arg_ainfo.multiplechar = true;
227  arg_ainfo.multiplevalue = true;
228  arg_ainfo.defaultstatus = cgiarginfo::weak;
229  arg_ainfo.argdefault = g_EmptyText;
230  arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
231  argsinfo.addarginfo (NULL, arg_ainfo);
232
233  // will be set when we've just come from the "source data" page
234  arg_ainfo.shortname = "bc1fromsrce";
235  arg_ainfo.longname = "collector specific";
236  arg_ainfo.multiplechar = false;
237  arg_ainfo.multiplevalue = false;
238  arg_ainfo.defaultstatus = cgiarginfo::weak;
239  arg_ainfo.argdefault = "0";
240  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
241  argsinfo.addarginfo (NULL, arg_ainfo);
242}
243
244collectoraction::~collectoraction () {
245}
246
247
248
249bool collectoraction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args,
250                     recptprotolistclass * /*protos*/, ostream &logout) {
251
252  text_t &current_page = args["p"];
253
254  // note that the "bildstatus" and "bildframe1" pages don't actually do anything
255  // functional so we don't need to worry about authenticating them (it's the
256  // underlying "bild" page that does the building (and creates the frameset))
257  // This helps us overcome a bit of a problem we have with multiple pages trying
258  // to read from the key.db database at the same time.
259  if (current_page != "intro" && current_page != "bildstatus" && current_page != "bildframe1") {
260    // authenticate the user if authentication is available
261    args["uan"] = 1;
262    args["ug"] = "all-collections-editor";
263  }
264 
265  if (current_page == "new" || current_page == "existing") {
266
267    // assign (and create) a temporary directory
268    if (assign_tmpname (args, logout)==false) {
269      // there was an error creating the tmp dir
270      message="tmpfail";
271      return true; // true because we could still parse the arguments
272    }
273
274    // clean up any old builds left laying about in the tmp directory
275    // (note that it's possible this could take some time if there's a huge
276    // partially built collecton laying about so we'll make it an asynchronous
277    // system call)
278    gsdl_system ("perl -S cleantmp.pl", false, logout);
279  }
280
281  if (current_page != "intro" && current_page != "bildstatus" &&
282      current_page != "bildframe1" && current_page != "new") {
283    // update arguments that were saved to the harddrive
284    text_tmap saved_args;
285    saved_args["bc1fullname"] = g_EmptyText;
286    saved_args["bc1contactemail"] = g_EmptyText;
287    saved_args["bc1aboutdesc"] = g_EmptyText;
288    saved_args["bc1clone"] = g_EmptyText;
289    saved_args["bc1clonecol"] = g_EmptyText;
290    saved_args["bc1inputnum"] = g_EmptyText;
291    saved_args["bc1input"] = g_EmptyText;
292    saved_args["bc1inputtype"] = g_EmptyText;
293
294    // update the argdb database with any arguments that were set
295    // by previous page
296    text_tmap::iterator here = saved_args.begin();
297    text_tmap::iterator end = saved_args.end();
298    while (here != end) {
299      if (args.lookupcgiarg((*here).first).source != cgiarg_t::default_arg) {
300    (*here).second = args[(*here).first];
301      }
302      ++here;
303    }
304
305    text_t argfile = filename_cat(gsdlhome, "tmp", args["bc1tmp"], "argdb.db");
306    argdb *args_on_disk = new argdb(argfile);
307    if (!args_on_disk->update_args(saved_args)) {
308      // error
309      logout << "collectoraction: argdb::update_args failed (" << argfile << ")\n";
310    }
311
312    // update args from argdb
313    saved_args.erase(saved_args.begin(), saved_args.end());
314    if (!args_on_disk->get_args(saved_args)) {
315      // error
316      logout << "collectoraction: argdb::get_args failed (" << argfile << ")\n";
317    }
318    delete args_on_disk;
319    here = saved_args.begin();
320    end = saved_args.end();
321    while (here != end) {
322      if (!(*here).second.empty()) {
323    args[(*here).first] = (*here).second;
324      }
325      ++here;
326    }
327  }
328
329  if (args["bc1infochanged"] == "1") {
330   
331    if (args["bc1dirname"].empty()) {
332      // we've just come from the "collection information" page for the
333      // first time so we'll need to create the collection with mkcol.pl
334      // and set up bc1dirname - we do this part here instead of in do_action
335      // because the bc1dirname argument must be set to its new value before
336      // the compressedoptions macros are set.
337      args["bc1dirname"] = get_directory_name (args["bc1fullname"]);
338
339      text_t createfile = filename_cat (gsdlhome, "tmp", args["bc1tmp"], ".create");
340      if (!file_exists (createfile)) {
341    // we could do the mkcol.pl here but I guess it's nicer to do it in do_action()
342    do_mkcol = true;
343      } else {
344    // .create file already exists but bc1dirname wasn't set ... this should only be
345    // able to occur when the "reload" (and possibly the "back" and "forward" buttons)
346    // have been used to get us here.
347    // we'll check that the bc1dirname directory exists (in case of the unlikely
348    // possibility that get_directory_name returned a different value this time
349    // than it did originally).
350    text_t coldir = filename_cat (get_collectdir(args), args["bc1dirname"]);
351    if (!directory_exists (coldir)) {
352      message = "reloaderror";
353      return true;
354    }
355      }
356    } else {
357      // "collection information" has been changed after collection already exists
358      // so we'll need to update the cfg file.
359      update_cfgfile_partial (args, false, logout);
360    }
361  }
362
363  if (args["bc1cfgchanged"] == "1") {
364    // configuration file has been changed from the "configure collection"
365    // page. we need to update the file on disk and catch bc1 arguments up
366    // with changes.
367    update_cfgfile_complete (args, logout);
368  }
369 
370  if (args["bc1clonechanged"] == "1") {
371    // cloning option has been changed on "source data" page. if it was turned
372    // on we want to create a new collect.cfg file using the bc1clonecol cfg file
373    // as a model (we'll save the old file as collect.cfg.org). if cloning was
374    // turned off we'll revert to using the collect.cfg.org file (which will need
375    // updating in case the bc1 arguments have been altered since cloning was
376    // turned on).
377    update_cfgfile_clone (args, logout);
378
379    // if cloning has just been turned on we'll also copy the rest of the files
380    // (excluding collect.cfg which we've already done) from the cloned collections
381    // etc directory to the new collection.
382    if (args["bc1clone"] == "1") {
383      text_t clone_etc = filename_cat(gsdlhome, "collect", args["bc1clonecol"], "etc");
384      text_t new_etc = filename_cat(get_collectdir(args), args["bc1dirname"], "etc");
385      text_tarray files;
386
387      if (read_dir (clone_etc, files)) {
388    text_tarray::const_iterator here = files.begin();
389    text_tarray::const_iterator end = files.end();
390    while (here != end) {
391      if (*here != "collect.cfg" && *here != "collect.cfg.org") {
392        file_copy (filename_cat(clone_etc, *here), filename_cat(new_etc, *here));
393      }
394      ++here;
395    }
396      } else {
397    outconvertclass text_t2ascii;
398    logout <<text_t2ascii << "collectoraction::check_cgiargs couldn't read from "
399           << clone_etc << " directory\n";
400      }
401    }
402  }
403 
404  if (current_page == "bildstatus" || current_page == "bildcancel") {
405    // if .final file exists then build has finished
406    text_t fbld = filename_cat (gsdlhome, "tmp", args["bc1tmp"], args["bc1dirname"] + ".bld.final");
407    if (file_exists (fbld)) {
408      char *fbldc = fbld.getcstr();
409      ifstream fbld_in (fbldc);
410      if (fbld_in) {
411    failcode = fbld_in.get();
412    fbld_in.close();
413    if (failcode == '0') {
414      // success - we need to create and configure a collection server for the
415      // newly built collection (for fastcgi and local library where
416      // initialization isn't going to be redone when the user clicks the
417      // "view your new collection" button
418      create_colserver (args["bc1dirname"], logout);
419      current_page = "bilddone";
420    }
421    else current_page = "bildfail";
422      } else {
423    // assume build failed (we shouldn't get here though ... right?)
424    current_page = "bildfail";
425      }
426      delete []fbldc;
427    }
428  }
429
430  if (args["bc1fromsrce"] == "1") {
431
432    // we've just come from the "source data" page so we need to check that
433    // input sources are valid
434    if (!check_sources(args, logout)) {
435      args["p"] = "srce";
436    }
437  }
438
439  return true;
440}
441
442void collectoraction::update_cfgfile_clone (cgiargsclass &args, ostream &logout) {
443
444  text_t tmpdir = filename_cat(gsdlhome, "tmp", args["bc1tmp"]);
445  text_t cfgfile = filename_cat(tmpdir, args["bc1dirname"], "etc", "collect.cfg");
446  if (!file_exists (cfgfile)) {
447    message = "tmpfail";
448    return;
449  }
450
451  text_t cfgfile_org = filename_cat (tmpdir, "collect.cfg.org");
452
453  if (args["bc1clone"] == "1") {
454    // cloning was turned on
455
456    text_t cfgfile_clone = filename_cat(gsdlhome, "collect", args["bc1clonecol"], "etc", "collect.cfg");
457    if (file_exists (cfgfile_clone)) {
458      // if .org file doesn't exist already create it
459      if (!file_exists (cfgfile_org)) {
460    if (!file_copy (cfgfile, cfgfile_org)) {
461      message = "tmpfail";
462      return;
463    }
464      }
465      // copy clone collections cfg file to new collection
466      if (!file_copy (cfgfile_clone, cfgfile)) {
467    message = "tmpfail";
468    return;
469      }
470      // update the new cfg file
471      update_cfgfile_partial (args, true, logout);
472     
473    } else {
474      // can't clone non-existant or read-protected collection
475      message = "clonefail";
476    }
477
478  } else {
479    // cloning has been turned off having been on at some point. the .org file
480    // should exist, if it doesn't we'll bail out and leave the user with the
481    // cloned copy
482    if (file_exists (cfgfile_org)) {
483      // copy original back again and update it with any recent changes
484      if (file_copy (cfgfile_org, cfgfile)) {
485    update_cfgfile_partial (args, false, logout);
486      } else {
487    message = "tmpfail";
488      }
489    }
490  }
491}
492
493// update configuration file on disk to match bc1 arguments
494// there's a special case if the clone option is true as certain parts of a
495// config file should not be cloned (e.g. the iconcollection stuff)
496void collectoraction::update_cfgfile_partial (cgiargsclass &args, bool clone, ostream &logout) {
497
498  text_t cfgfile = filename_cat(get_collectdir(args), args["bc1dirname"], "etc", "collect.cfg");
499  char *cfgfilec = cfgfile.getcstr();
500
501#if defined (__WIN32__)
502  // make sure collect.cfg isn't read-only
503  _chmod (cfgfilec, _S_IREAD | _S_IWRITE);
504#endif
505
506  vector<text_tarray> cfgarray;
507
508  // read in cfg file
509  ifstream cfg_in (cfgfilec);
510  if (cfg_in) {
511    text_tarray cfgline;
512    while (read_cfg_line(cfg_in, cfgline) >= 0) {
513      if (cfgline.size () >= 2) {
514    if (cfgline[0] == "creator" || cfgline[0] == "maintainer") {
515      cfgline[1] = args["bc1contactemail"];
516    } else if (cfgline[0] == "collectionmeta") {
517      if (cfgline[1] == "collectionname") {
518        cfgline[2] = args["bc1fullname"];
519      } else if (cfgline[1] == "collectionextra") {
520        cfgline[2] = carriage_replace (args["bc1aboutdesc"], 0);
521      } else if (clone && (cfgline[1] == "iconcollection" ||
522                   cfgline[1] == "iconcollectionsmall")) {
523        cfgline[2] = g_EmptyText;
524      }
525    }
526      }
527      cfgarray.push_back (cfgline);
528    }
529    cfg_in.close();
530   
531    // now write cfg file back out
532    int fd=open(cfgfilec, O_WRONLY | O_CREAT | O_TRUNC
533#if defined(__WIN32__)
534        | O_BINARY
535#endif
536        );
537
538    if (fd != -1) {
539      // lock the file
540      int lock_val = 1;
541      GSDL_LOCK_FILE (fd);
542      if (lock_val != 0) {
543    logout << "Error: Couldn't lock file " << cfgfilec << "\n";
544    close(fd);
545    message = "tmpfail";
546   
547      } else {
548
549    vector<text_tarray>::const_iterator this_line = cfgarray.begin();
550    vector<text_tarray>::const_iterator end_line = cfgarray.end();
551    while (this_line != end_line) {
552      write_cfg_line (fd, *this_line);
553      ++this_line;
554    }
555    GSDL_UNLOCK_FILE (fd);
556    close(fd);
557      }
558
559    } else {
560      logout << "collectoraction::update_cfgfile_partial: unable to open "
561         << cfgfilec << " for output\n";
562      message = "tmpfail";
563    }
564   
565  } else {
566    logout << "collectoraction::update_cfgfile_partial: unable to open "
567       << cfgfilec << " for input\n";
568    message = "tmpfail";
569  }
570
571  delete []cfgfilec;
572}
573
574// replace configuration file on disk with that in the cfgfile argument and
575// catch other bc1 arguments up with those the new cfgfile contains
576void collectoraction::update_cfgfile_complete (cgiargsclass &args, ostream &logout) {
577
578  text_t cfgfile = filename_cat(get_collectdir(args), args["bc1dirname"], "etc", "collect.cfg");
579  char *cfgfilec = cfgfile.getcstr();
580
581#ifdef __WIN32__
582  // make sure collect.cfg isn't read-only
583  _chmod (cfgfilec, _S_IREAD | _S_IWRITE);
584#endif
585
586  int fd=open(cfgfilec, O_WRONLY | O_CREAT | O_TRUNC
587#if defined(__WIN32__)
588          | O_BINARY
589#endif
590          );
591
592  if (fd) {
593    // lock the file
594    int lock_val = 1;
595    GSDL_LOCK_FILE (fd);
596    if (lock_val != 0) {
597      logout << "Error: Couldn't lock file " << cfgfilec << "\n";
598      close(fd);
599      message = "tmpfail";
600     
601    } else {
602     
603      outconvertclass text_t2ascii;
604      text_t2ascii.setinput(&args["cfgfile"]);
605      size_t buffersize=args["cfgfile"].size();
606      char *buffer=new char[buffersize];
607      buffer[0]='\n'; // just in case something goes wrong...
608      size_t num_chars;
609      convertclass::status_t status;
610      text_t2ascii.convert(buffer, buffersize, num_chars, status);
611      // ignore status - assume it is "finished" as buffer is big enough
612      write(fd, buffer, num_chars);
613      GSDL_UNLOCK_FILE (fd);
614      close(fd);
615      delete []buffer;
616     
617      // now that we've written the file we'll read it back again and
618      // update our bc1 arguments
619      ifstream cfg_in (cfgfilec);
620      if (cfg_in) {
621    text_tarray cfgline;
622    while (read_cfg_line(cfg_in, cfgline) >= 0) {
623      if (cfgline.size () >= 2) {
624        if (cfgline[0] == "creator") {
625          args["bc1contactemail"] = cfgline[1];
626        } else if (cfgline[0] == "collectionmeta") {
627          if (cfgline[1] == "collectionname") {
628        args["bc1fullname"] = cfgline[2];
629          } else if (cfgline[1] == "collectionextra") {
630        args["bc1aboutdesc"] = carriage_replace (cfgline[2], 1);
631          }
632        }
633      }
634    }
635    cfg_in.close();
636      } else {
637    logout << "collectoraction::update_cfgfile_complete: unable to open "
638           << cfgfilec << " for input\n";
639    message = "tmpfail";
640      }
641    }
642  } else {
643    logout << "collectoraction::update_cfgfile_complete: unable to open "
644       << cfgfilec << " for output\n";
645    message = "tmpfail";
646  }
647
648  delete []cfgfilec;
649}
650
651
652// return html for buttons used in collector bar
653// color may be "green", "grey", or "yellow"
654// type may be:
655//   "info" --> "collection information" button
656//   "srce" --> "source data" button
657//   "conf" --> "configure collection" button
658//   "bild" --> "build collection" button
659//   "view" --> "view collection" button
660// if enabled is true button will be flashy rollover type and
661// will be hyperlinked
662
663// Wendy left a comment suggesting this be move, but where to
664// was not specified.  Into wizardaction.cpp?
665
666// set the _fullnamemenu_ macro (and _warnindex_ and _selectedindex_ if
667// we're on the "srce" page)
668void collectoraction::set_fullnamemenu (displayclass &disp, cgiargsclass &args,
669                    recptprotolistclass *protos, ostream &logout) {
670
671  if (recpt == NULL) {
672    logout << "ERROR (collectoraction::set_fullnamemenu): This action does not contain\n"
673       << "       information about any receptionists. The method set_receptionist was\n"
674       << "       probably not called from the module which instantiated this action.\n";
675    return;
676  }
677
678  text_t &current_page = args["p"];
679  text_t currentname = args[macro_prefix+"dirname"];
680  if (current_page == "srce") currentname = args[macro_prefix + "clonecol"];
681
682  text_tarray dirnames;
683  text_tarray fullnames;
684  vector<bool> write_protected;
685  bool is_selected = false;
686  int selected_index = 0;
687  int index = 0;
688
689  recptprotolistclass::iterator rprotolist_here = protos->begin();
690  recptprotolistclass::iterator rprotolist_end = protos->end();
691  while (rprotolist_here != rprotolist_end) {
692    if ((*rprotolist_here).p != NULL) {
693
694      // don't include z39.50 collections
695      comerror_t err = noError;
696      if ((*rprotolist_here).p->get_protocol_name (err) == "z3950proto") {
697    ++rprotolist_here;
698    continue;
699      }
700
701      text_tarray collist;
702      (*rprotolist_here).p->get_collection_list (collist, err, logout);
703      if (err == noError) {
704    text_tarray::iterator collist_here = collist.begin();
705    text_tarray::iterator collist_end = collist.end();
706    while (collist_here != collist_end) {
707      ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr ((*rprotolist_here).p, *collist_here, logout);
708      if (cinfo != NULL) {
709        text_t collectionname = cinfo->get_collectionmeta("collectionname", args["l"]);
710        if (collectionname.empty()) {
711          collectionname = *collist_here;
712        }
713        dirnames.push_back(*collist_here);
714        fullnames.push_back(collectionname);
715        // check to see if the collection is writable
716        if (collection_protected (*collist_here)) write_protected.push_back(true);
717        else write_protected.push_back(false);
718
719        if (*collist_here == currentname) {
720          is_selected = true;
721          selected_index = index;       
722        }
723        ++index;
724      }
725      ++collist_here;
726    }
727      }
728    }
729    ++rprotolist_here;
730  }
731
732  bool first = true;
733
734  text_t warnindex;
735  text_t fullnamemenu = "<select name=\""+macro_prefix+"dirname\" onChange=\"menuchange();\">\n";
736
737  if (current_page == "srce") {
738    fullnamemenu = "<select name=\""+macro_prefix+"clonecol\" onChange=\"menuchange();\">\n";
739    fullnamemenu += "<option value=defaultstructure";
740    if (!is_selected) fullnamemenu += " selected>";
741    else fullnamemenu.push_back('>');
742    fullnamemenu += "_collector:textdefaultstructure_\n";
743  }
744
745  fullnamemenu += "<option value=\"\"></option>\n";
746
747  for (int i = 0; i < index; ++i) {
748    // don't want write protected collections in list on "change existing
749    // collection" page
750    if (write_protected[i] && current_page == "existing") continue;
751    fullnamemenu += "<option value=\"" + dirnames[i] + "\"";
752    if ((i == 0 && !is_selected && current_page != "srce") ||
753    (is_selected && i == selected_index)) {
754      fullnamemenu += " selected";
755      ++selected_index;
756      is_selected = false;
757    }
758    fullnamemenu.push_back ('>');
759    fullnamemenu += fullnames[i];
760    fullnamemenu.push_back ('\n');
761   
762    // add to Warnindex if collection uses any dubious plugins
763    // (if creating clone collection list)
764    if (current_page == "srce") {
765      if (first) warnindex += "0,";
766      else warnindex.push_back(',');
767      if (uses_weird_plugin (dirnames[i])) {
768    warnindex += text_t (1);
769      } else {
770    warnindex += text_t (0);
771      }
772    }
773    first = false;
774  }
775  fullnamemenu += "</select>\n";
776  text_t action_name = get_action_name();
777  disp.setmacro ("fullnamemenu", action_name, fullnamemenu);
778  if (current_page == "srce") {
779    disp.setmacro ("warnindex",action_name , warnindex);
780    disp.setmacro ("selectedindex", action_name, text_t(selected_index));
781  }
782}
783
784
785// set _sourcelist_ and _badsources_ macros
786void collectoraction::set_inputsourceboxes (displayclass &disp, cgiargsclass &args,
787                        ostream &logout) {
788 
789  if (badsources) disp.setmacro ("badsources", "collector", "1");
790
791  text_t sourcelist = get_source_box(args["bc1input"], args["bc1inputnum"].getint(),
792                     args["bc1inputtype"]);
793
794  disp.setmacro("sourcelist", "collector", sourcelist);
795
796  // reset badsources and failedsources variables
797  badsources = false;
798  failedsources.erase(failedsources.begin(), failedsources.end());
799}
800
801text_t collectoraction::get_source_box (text_t inputarglist, int numboxes,
802                    text_t inputtypelist) {
803
804  text_tarray inputvalues;
805  splitchar (inputarglist.begin(), inputarglist.end(), ',', inputvalues);
806  // remove any empty values from the end of the array
807  if (inputvalues.size()) {
808    text_tarray::iterator l = inputvalues.end() - 1;
809    text_tarray::iterator b = inputvalues.begin();
810    while ((*l).empty() && l >= b) {
811      --l;
812    }
813    inputvalues.erase(l+1, inputvalues.end());
814  }
815
816  text_tarray inputtypes;
817  splitchar (inputtypelist.begin(), inputtypelist.end(), ',', inputtypes);
818
819  int numvalues = inputvalues.size();
820  int numtypes = inputtypes.size();
821
822  text_t last = "file://";
823  text_t rv;
824  for (int i = 0; i < numboxes; ++i) {
825    rv += "<nobr><select name=\"bc1inputtype\">\n";
826    rv += "<option value=\"file://\"";
827    if ((i < numtypes && inputtypes[i] == "file://") ||
828    (numboxes == 3 && i == 0 && numvalues == 0) ||
829    (i >= 3 && i >= numvalues && last == "file://")) {
830      rv += " selected";
831      last = "file://";
832    }
833    rv += ">file://\n";
834    rv += "<option value=\"http://\"";
835    if ((i < numtypes && inputtypes[i] == "http://") ||
836    (numboxes == 3 && i == 1 && numvalues == 0) ||
837    (i >= 3 && i >= numvalues && last == "http://")) {
838      rv += " selected";
839      last = "http://";
840    }
841    rv += ">http://\n";
842    rv += "<option value=\"ftp://\"";
843    if ((i < numtypes && inputtypes[i] == "ftp://") ||
844    (numboxes == 3 && i == 2 && numvalues == 0) ||
845    (i >= 3 && i >= numvalues && last == "ftp://")) {
846      rv += " selected";
847      last = "ftp://";
848    }
849    rv += ">ftp://\n";
850    rv += "</select>\n";
851    rv += "<input type=text name=\"bc1input\" value=\"";
852    if (i < numvalues) {
853      rv += dm_safe(decode_commas(inputvalues[i]));
854    }
855    rv += "\" size=50>";
856    if (badsources) {
857      if ((i < numvalues) && (!inputvalues[i].empty())) {
858    if (failedsources[decode_commas(inputvalues[i])] == "1") {
859      rv += "_iconcross_";
860    } else {
861      rv += "_icontick_";
862    }
863      } else {
864    rv += "_iconblank_";
865      }
866    }
867    if (i+1 == numboxes) {
868      if (!badsources) rv += "_iconblank_";
869      rv += "_imagemore_</nobr><br>";
870    } else {
871      rv += "</nobr><br>\n";
872    }
873  }
874 
875  return rv;
876}
877
878// set the _cfgfile_ macro
879void collectoraction::set_cfgfile (displayclass &disp, cgiargsclass &args, ostream &logout) {
880
881  text_t &collection = args["bc1dirname"];
882  if (collection.empty()) {
883    message = "nocollection";
884    return;
885  }
886
887  // read in collect.cfg     
888  text_t cfgfile = filename_cat(get_collectdir(args), collection, "etc", "collect.cfg"); 
889  char *cfgfilec = cfgfile.getcstr();
890
891#ifdef GSDL_USE_IOS_H
892  ifstream cfg_ifs (cfgfilec, ios::in | ios::nocreate);
893#else
894  ifstream cfg_ifs (cfgfilec, ios::in);
895#endif
896 
897  if (cfg_ifs) { 
898    // read in collect.cfg     
899    text_t cfgtext;
900    char c;
901    cfg_ifs.get(c);
902    while (!cfg_ifs.eof ()) {
903      cfgtext.push_back(c);
904      cfg_ifs.get(c);
905    }
906    cfg_ifs.close();
907   
908    // define it as a macro
909    disp.setmacro("cfgfile", "collector", dm_safe(cfgtext));
910
911  } else {
912    logout << "collectoraction::set_cfgfile: couldn't open configuration file ("
913       << cfgfilec << ") for reading\n";
914    message = "tmpfail";
915  }   
916  delete []cfgfilec;
917}
918
919
920void collectoraction::define_internal_macros (displayclass &disp, cgiargsclass &args,
921                          recptprotolistclass *protos, ostream &logout) {
922
923  // define_internal_macros sets the following macros:
924  // _collectorbar_
925  // _pagescriptextra_
926  // _fullnamemenu_ -- if displaying the "source data" page or the "changing existing
927  //                   collection" page
928  // _cfgfile_ -- if displaying the "configure collection" page
929  // _statusline_ -- if displaying the bildstatus page
930  // _header_ -- may be set for pages that require it
931  // _textfailmsg_ -- set to different messages depending on failcode returned
932  //                  by build script (if build fails)
933  // _faillog_ - set to last 6 lines of .bld file if build failed
934  // _gsdlhome_ - the gsdlhome path (dm_safe)
935  // _sourcelist_ -- "input source" text boxes
936  // _badsources_ -- will be set to "1" if we've come from the
937  //                 "source data" page and there's a problem
938  //                 with the input sources
939
940  text_t &collector_page = args["p"];
941  int esrce = args["bc1esrce"].getint();
942  int econf = args["bc1econf"].getint();
943
944  // set _pagescriptextra_ macro to _cpagescriptextra_
945  disp.setmacro ("pagescriptextra", "collector", "_" + collector_page + "scriptextra_");
946
947  if (collector_page == "bildstatus" || collector_page == "bilddone" ||
948      collector_page == "bildfail" || collector_page == "bildframe1") {
949    disp.setmacro ("header", "collector", "_" + collector_page + "header_");
950  }
951
952  // set the collectorbar macro
953  text_t collectorbar = "<table class=wizardbar border=0 cellspacing=4 cellpadding=0><tr>\n";
954
955  if (collector_page == "new") {
956    collectorbar += "<td>_icongreyarrow_</td>\n";
957    collectorbar += get_button (args,collector_page, "green", "info", true);
958    collectorbar += "<td>_icongreyarrow_</td>\n";
959    collectorbar += get_button (args,collector_page, "grey", "srce", false);
960    collectorbar += "<td>_icongreyarrow_</td>\n";
961    collectorbar += get_button (args,collector_page, "grey", "conf", false);
962    collectorbar += "<td>_icongreyarrow_</td>\n";
963    collectorbar += get_button (args,collector_page, "grey", "bild", false);
964    collectorbar += "<td>_icongreyarrow_</td>\n";
965    collectorbar += get_button (args,collector_page, "grey", "view", false);
966
967  } else if (collector_page == "info") {
968    collectorbar += "<td>_icongreyarrow_</td>\n";
969    collectorbar += get_button (args,collector_page, "yellow", "info", false);
970    collectorbar += "<td>_icongreyarrow_</td>\n";
971    collectorbar += get_button (args,collector_page, "green", "srce", true);
972    collectorbar += "<td>_icongreyarrow_</td>\n";
973    collectorbar += get_button (args,collector_page, "grey", "conf", false);
974    collectorbar += "<td>_icongreyarrow_</td>\n";
975    collectorbar += get_button (args,collector_page, "grey", "bild", false);
976    collectorbar += "<td>_icongreyarrow_</td>\n";
977    collectorbar += get_button (args,collector_page, "grey", "view", false);
978    collectorbar += "</tr><tr><td></td><td align=center>_icongreyuparrow_</td><td colspan=8></td>\n";
979
980  } else if (collector_page == "srce") {
981    collectorbar += "<td>_icongreyarrow_</td>\n";
982    if (esrce == 1) {
983      // if we came from the "change an existing collection" page previous button(s)
984      // are disabled
985      collectorbar += get_button (args,collector_page, "grey", "info", false);
986    } else {
987      collectorbar += get_button (args,collector_page, "yellow", "info", true);
988    }
989    collectorbar += "<td>_icongreyarrow_</td>\n";
990    collectorbar += get_button (args,collector_page, "yellow", "srce", false);
991    collectorbar += "<td>_icongreyarrow_</td>\n";
992    collectorbar += get_button (args,collector_page, "green", "conf", true);
993    collectorbar += "<td>_icongreyarrow_</td>\n";
994    collectorbar += get_button (args,collector_page, "green", "bild", true);
995    collectorbar += "<td>_icongreyarrow_</td>\n";
996    collectorbar += get_button (args,collector_page, "grey", "view", false);
997    collectorbar += "</tr><tr><td colspan=3></td><td align=center>_icongreyuparrow_</td><td colspan=6></td>\n";
998
999  } else if (collector_page == "conf") {
1000    collectorbar += "<td>_icongreyarrow_</td>\n";
1001    // disable appropriate buttons if we came from "change an existing collection"
1002    // page
1003    if (esrce == 1 || econf == 1) {
1004      collectorbar += get_button (args,collector_page, "grey", "info", false);
1005    } else {
1006      collectorbar += get_button (args,collector_page, "yellow", "info", true);
1007    }
1008    collectorbar += "<td>_icongreyarrow_</td>\n";
1009    if (econf == 1) {
1010      collectorbar += get_button (args,collector_page, "grey", "srce", false);
1011    } else {
1012      collectorbar += get_button (args,collector_page, "yellow", "srce", true);
1013    }
1014    collectorbar += "<td>_icongreyarrow_</td>\n";
1015    collectorbar += get_button (args,collector_page, "yellow", "conf", false);
1016    collectorbar += "<td>_icongreyarrow_</td>\n";
1017    collectorbar += get_button (args,collector_page, "green", "bild", true);
1018    collectorbar += "<td>_icongreyarrow_</td>\n";
1019    collectorbar += get_button (args,collector_page, "grey", "view", false);
1020    collectorbar += "</tr><tr><td colspan=5></td><td align=center>_icongreyuparrow_</td><td colspan=4></td>\n";
1021
1022  } else if (collector_page == "bilddone") {
1023    collectorbar += "<td>_icongreyarrow_</td>\n";
1024    // all previous buttons grey after build was completed
1025    collectorbar += get_button (args,collector_page, "grey", "info", false);
1026    collectorbar += "<td>_icongreyarrow_</td>\n";
1027    collectorbar += get_button (args,collector_page, "grey", "srce", false);
1028    collectorbar += "<td>_icongreyarrow_</td>\n";
1029    collectorbar += get_button (args,collector_page, "grey", "conf", false);
1030    collectorbar += "<td>_icongreyarrow_</td>\n";
1031    collectorbar += get_button (args,collector_page, "yellow", "bild", false);
1032    collectorbar += "<td>_icongreyarrow_</td>\n";
1033    collectorbar += get_button (args,collector_page, "green", "view", true);
1034    collectorbar += "</tr><tr><td colspan=7></td><td align=center>_icongreyuparrow_</td><td colspan=2></td>\n";
1035
1036  } else if (collector_page == "bildcancel" || collector_page == "bildfail") {
1037    collectorbar += "<td>_icongreyarrow_</td>\n";
1038    // disable appropriate buttons if we came from "change an existing collection"
1039    // page
1040    if (esrce == 1 || econf == 1) {
1041      collectorbar += get_button (args,collector_page, "grey", "info", false);
1042    } else {
1043      collectorbar += get_button (args,collector_page, "yellow", "info", true);
1044    }
1045    collectorbar += "<td>_icongreyarrow_</td>\n";
1046    if (econf == 1) {
1047      collectorbar += get_button (args,collector_page, "grey", "srce", false);
1048    } else {
1049      collectorbar += get_button (args,collector_page, "yellow", "srce", true);
1050    }
1051    collectorbar += "<td>_icongreyarrow_</td>\n";
1052    collectorbar += get_button (args,collector_page, "yellow", "conf", true);
1053    collectorbar += "<td>_icongreyarrow_</td>\n";
1054    collectorbar += get_button (args,collector_page, "yellow", "bild", true);
1055    collectorbar += "<td>_icongreyarrow_</td>\n";
1056    collectorbar += get_button (args,collector_page, "grey", "view", false);
1057  }
1058
1059  collectorbar += "</tr></table>\n";
1060  disp.setmacro ("collectorbar", "collector", collectorbar);
1061
1062  if (collector_page == "bildfail") {
1063
1064    text_t textfailmsg = "_textfailmsg";
1065    textfailmsg.push_back(failcode);
1066    textfailmsg.push_back('_');
1067    disp.setmacro("textfailmsg", "collector", textfailmsg);
1068
1069    text_t bldlog = filename_cat(gsdlhome, "tmp", args["bc1tmp"], args["bc1dirname"] + ".bld");
1070    text_t rawlog = file_tail (bldlog, 6, 0);
1071    // we'll shove in some <br> tags where \n's occur
1072    text_t faillog;
1073    text_t::const_iterator here = rawlog.begin();
1074    text_t::const_iterator end = rawlog.end();
1075    while (here != end) {
1076      if (*here == '\n') faillog += "<br>";
1077      faillog.push_back (*here);
1078      ++here;
1079    }
1080    disp.setmacro ("faillog", "collector", dm_safe(faillog));
1081  }
1082
1083  if (collector_page == "srce" || collector_page == "existing")
1084    set_fullnamemenu (disp, args, protos, logout);
1085  if (collector_page == "conf")
1086    set_cfgfile (disp, args, logout);
1087  if (collector_page == "bildstatus")
1088    set_statusline (disp, args, logout);
1089  if (collector_page == "srce") {
1090    set_inputsourceboxes (disp, args, logout);
1091  }
1092
1093  disp.setmacro ("gsdlhome", "collector", dm_safe(gsdlhome));
1094}
1095
1096
1097bool collectoraction::do_action (cgiargsclass &args, recptprotolistclass * /*protos*/,
1098                 browsermapclass * /*browsers*/, displayclass &disp,
1099                 outconvertclass &outconvert, ostream &textout,
1100                 ostream &logout) {
1101
1102  // make sure the collector is enabled
1103  if (disabled) {
1104    textout << outconvert
1105        << "<html>\n"
1106        << "<head>\n"
1107        << "<title>Collector disabled</title>\n"
1108        << "</head>\n"
1109        << "<body bgcolor=\"#ffffff\" text=\"#000000\" link=\"#006666\" "
1110        << "alink=\"#cc9900\" vlink=\"#666633\">\n"
1111        << "<h2>Facility disabled</h2>\n"
1112        << "Sorry, the Collector end-user collection building facility is currently disabled\n"
1113        << "\n</body>\n"
1114        << "</html>\n";
1115    return true;
1116  }
1117
1118  text_t &collector_page = args["p"];
1119  text_t &collection = args["bc1dirname"];
1120
1121  // make sure we have perl (we won't bother with this check for the
1122  // building status pages to avoid slowing things down unneccessarily)
1123  if (collector_page != "bildstatus" && collector_page != "bildframe1" && !perl_ok(logout)) {
1124    textout << outconvert
1125        << "<html>\n"
1126        << "<head>\n"
1127        << "<title>Perl not found</title>\n"
1128        << "</head>\n"
1129        << "<body bgcolor=\"#ffffff\" text=\"#000000\" link=\"#006666\" "
1130        << "alink=\"#cc9900\" vlink=\"#666633\">\n"
1131        << "<h2>Perl not found</h2>\n"
1132        << "Greenstone could not detect perl on this system. It is therefore not\n"
1133        << "possible to build a Greenstone collection, either from the Collector or the \n"
1134        << "command-line tools, or to use the Collector for any other task.\n"
1135        << "<p>Please refer to the Greenstone Installer's Guide for details on\n"
1136        << "installing perl on your system.\n"
1137        << "\n</body>\n"
1138        << "</html>\n";
1139    return true;
1140
1141  }
1142
1143  if (collector_page == "bild") {
1144    // do the work (download, import, build)
1145    gsdl_build (args, logout);
1146
1147    if (message.empty()) {
1148      // bild page is a frameset so we don't want headers and stuff
1149      textout << outconvert << disp << ("_collector:bildcontent_\n");
1150    }
1151  }
1152
1153  if (do_mkcol == true) {
1154    // execute mkcol.pl (do_mkcol is set from within check_cgiargs)
1155    gsdl_mkcol (args, logout);
1156    do_mkcol = false; // reset for fast-cgi
1157  }
1158
1159  if (args["bc1dodelete"] == "1") {
1160    // delete bcidirname collection
1161    if (collection_protected (collection)) {
1162      message = "delinvalid";
1163   
1164    } else {
1165
1166      const recptconf &rcinfo = recpt->get_configinfo ();
1167      bool emailuserevents = rcinfo.EmailUserEvents;
1168
1169      // get collection maintainer email from collect.cfg before we
1170      // delete it
1171      text_t colmaintainer;
1172      text_t cfgfile = filename_cat(gsdlhome, "collect", collection, "etc", "collect.cfg");
1173      char *cfgfilec = cfgfile.getcstr();
1174      ifstream cfg_in (cfgfilec);
1175      delete []cfgfilec;
1176      if (cfg_in) {
1177    text_tarray cfgline;
1178    while (read_cfg_line(cfg_in, cfgline) >= 0) {
1179      if (cfgline.size () == 2 && cfgline[0] == "maintainer") {
1180        colmaintainer = cfgline[1];
1181        break;
1182      }
1183    }
1184    cfg_in.close();
1185      }
1186      if (colmaintainer.empty()) {
1187    logout << outconvert
1188           << "collectoraction::do_action WARNING: Collection being deleted ("
1189           << collection << ") has no maintainer address. EmailUserEvents "
1190           << "disabled\n";
1191    emailuserevents = false;
1192      }
1193     
1194      // first we need to free up the collection's collection server
1195      // we must do this for the local library (and I guess when using
1196      // fastcgi too) as you can't delete the database file while it's
1197      // being kept open by the collection server
1198      remove_colservr (collection, logout);
1199
1200      text_t delete_cmd = "perl -S delcol.pl -f " + collection;
1201      int rv = gsdl_system (delete_cmd, true, logout);
1202      if (rv != 0) {
1203    // deletion failed -- permissions?
1204    message = "delpermission";
1205      } else {
1206    message = "delsuccess";
1207      }
1208
1209      // log the event
1210      if (rcinfo.LogEvents == CollectorEvents || rcinfo.LogEvents == AllEvents) {
1211   
1212    text_t eventlog = filename_cat (gsdlhome, "etc", "events.txt");
1213    char *eventlogt = eventlog.getcstr();
1214    ofstream eventl (eventlogt, ios::app);
1215    delete []eventlogt;
1216
1217    if (eventl) {
1218      eventl << outconvert << "[Collector Event]\n"
1219         << "Date: " << get_date (true) << "\n"
1220         << "Greenstone Username: " << args["un"] << "\n"
1221         << "Collection: " << collection << "\n"
1222         << "Collection Maintainer: " << colmaintainer << "\n"
1223         << "GSDLHOME: " << gsdlhome << "\n";
1224
1225      if (message == "delsuccess") {
1226        eventl << outconvert
1227           << "The " << collection << " collection was successfully deleted\n\n";
1228      } else {
1229        eventl << outconvert
1230           << "Attempt to delete the " << collection << " collection failed\n\n";
1231      }
1232      eventl.close();
1233
1234    } else {
1235      logout << outconvert << "collectoraction::do_action ERROR: Couldn't open "
1236         << "event log file " << eventlog << " for appending during collection "
1237         << "deletion. LogEvents disabled\n";
1238    }
1239      }
1240     
1241      if (rcinfo.EmailEvents == CollectorEvents || rcinfo.EmailEvents == AllEvents || emailuserevents) {
1242    // use sendmail.pl perl script to send email events
1243    text_t tmpmailfile = filename_cat (gsdlhome, "tmp", args["bc1tmp"], "event.txt");
1244    char *tmpmailfilec = tmpmailfile.getcstr();
1245    ofstream tmpfile (tmpmailfilec);
1246    delete []tmpmailfilec;
1247    if (tmpfile) {
1248      tmpfile << outconvert << "[Collector Event]\n"
1249              << "Date: " << get_date (true) << "\n"
1250          << "Greenstone Username: " << args["un"] << "\n"
1251          << "Collection: " << collection << "\n"
1252          << "Collection Maintainer: " << colmaintainer << "\n"
1253          << "GSDLHOME: " << gsdlhome << "\n";
1254      if (message == "delsuccess") {
1255        tmpfile << outconvert
1256            << "The " << collection << " collection was successfully deleted\n\n";
1257      } else {
1258        tmpfile << outconvert
1259            << "Attempt to delete the " << collection << " collection failed\n\n";
1260      }
1261      tmpfile.close();
1262      text_t to;
1263      if (rcinfo.EmailEvents == CollectorEvents || rcinfo.EmailEvents == AllEvents) to += rcinfo.maintainer;
1264      if (emailuserevents) {
1265        if (!to.empty()) to.push_back (',');
1266        to += colmaintainer;
1267      }
1268      text_t sendmail_cmd = "perl -S sendmail.pl -to \"" + to + "\" -from \"" + rcinfo.maintainer;
1269      sendmail_cmd += "\" -smtp \"" + rcinfo.MailServer + "\" -subject \"Greenstone Collector Event\"";
1270      sendmail_cmd += " -msgfile \"" + tmpmailfile + "\"";
1271
1272      gsdl_system (sendmail_cmd, false, logout);
1273     
1274    } else {
1275      logout << outconvert << "collectoraction::do_action ERROR: Couldn't open "
1276         << "temporary event log file " << tmpmailfile << " during collection "
1277         << "deletion. EmailEvents and EmailUserEvents disabled\n";
1278    }
1279      }
1280    }
1281  }
1282 
1283  if (collector_page == "bildcancel" || collector_page == "bildfail") {
1284    // cancel the build (we'll also use the cancel_build script to tidy
1285    // up if the build failed)
1286    gsdl_cancel_build (args, logout);
1287  }
1288
1289  if (collector_page == "expt") {
1290
1291    // export the collection - we'll do a synchronous system call to
1292    // exportcol.pl as that's the easiest way to do it. if it becomes a
1293    // problem that it's taking too long to export a large collection then
1294    // we may have to revisit this.
1295    text_t tmpfile = filename_cat (gsdlhome, "tmp", collection + "_export.txt");
1296    text_t export_cmd = "perl -S exportcol.pl -out \"" + tmpfile + "\" " + collection;
1297    gsdl_system (export_cmd, true, logout);
1298    if (file_exists (tmpfile)) {
1299      text_t returnline = file_tail (tmpfile, 1, 0);
1300      if (returnline.size() > 23 && (substr(returnline.begin(), returnline.begin()+23) == "exportcol.pl succeeded:")) {
1301    // success
1302    message = "exptsuccess";
1303      } else {
1304    message = "exptfail";
1305      }
1306    } else {
1307      message = "exptfail";
1308    }
1309  }
1310
1311  if (message.empty()) {
1312    if (collector_page != "bild") {
1313      // output page ("bild" page was already output above)
1314      textout << outconvert << disp << ("_collector:header_\n")
1315          << ("_collector:" + collector_page + "content_\n")
1316          << ("_collector:footer_\n");
1317    }
1318  } else {
1319    // message was set somewhere (probably an error), output message page
1320    textout << outconvert << disp << ("_collector:header_\n")
1321        << ("_collector:" + message + "content_\n")
1322        << ("_collector:footer_\n");
1323    message.clear();
1324  }
1325  return true;
1326}
1327
1328void collectoraction::gsdl_mkcol (cgiargsclass &args, ostream &logout) {
1329
1330  text_t tmpdir = filename_cat (gsdlhome, "tmp", args["bc1tmp"]);
1331  if (!directory_exists (tmpdir)) {
1332    message = "tmpfail";
1333    cerr << "WE CANNOT CREATE THE DIRECTORY!!! " << endl;
1334    return;
1335  }
1336
1337  text_t &collection = args["bc1dirname"];
1338  if (collection.empty()) {
1339    message = "nocollection";
1340    return;
1341  }
1342
1343  // check for a .create file - if it exists then we've already created the collection
1344  text_t createfile = filename_cat (tmpdir, ".create");
1345  if (file_exists (createfile)) {
1346    return;
1347  }
1348
1349  // set up options
1350  text_t options = "-quiet -creator \"" + args["bc1contactemail"] + "\"";
1351  options += " -title \"" + args["bc1fullname"] + "\"";
1352  options += " -about \"" + carriage_replace (args["bc1aboutdesc"] + "_collectorextra_", 0) + "\"";
1353  options += " -collectdir \"" + remove_trailing_slashes(tmpdir) + "\" ";
1354
1355  text_t optionfile = filename_cat (tmpdir, "mkcol.opt");
1356  char *optionfilec = optionfile.getcstr();
1357  ofstream ofile_out (optionfilec);
1358  delete []optionfilec;
1359  if (!ofile_out) {
1360    message = "tmpfail";
1361    return;
1362  }
1363  outconvertclass text_t2ascii;
1364  ofile_out << text_t2ascii << options << "\n";
1365  ofile_out.close();
1366
1367  // run mkcol.pl
1368  text_t mkcol_cmd = "perl -S mkcol.pl -optionfile \"" + optionfile;
1369  mkcol_cmd += "\" " + collection;
1370
1371
1372  gsdl_system (mkcol_cmd, true, logout);
1373
1374  // make sure it went ok
1375  text_t cfgfile = filename_cat (tmpdir, collection, "etc", "collect.cfg");
1376  if (!file_writable (cfgfile)) {
1377    message = "mkcolfail";
1378  } else {
1379    // create the .create file (this file is just a place holder to let any future
1380    // pages know that the collection already exists).
1381    char *createfilec = createfile.getcstr();
1382    ofstream cfile_out (createfilec);
1383    delete []createfilec;
1384    if (cfile_out) {
1385      cfile_out << "collection created\n";
1386      cfile_out.close();
1387    } else {
1388      message = "tmpfail";
1389      return;
1390    }
1391  }
1392}
1393
1394
1395bool collectoraction::check_sources (cgiargsclass &args, ostream &logout) {
1396
1397  bool found = false;
1398
1399  text_tarray inputvalues;
1400  splitchar (args["bc1input"].begin(), args["bc1input"].end(), ',', inputvalues);
1401
1402  text_tarray inputtypes;
1403  splitchar (args["bc1inputtype"].begin(), args["bc1inputtype"].end(), ',', inputtypes);
1404
1405  int numvalues = inputvalues.size();
1406  int numtypes = inputtypes.size();
1407
1408  for (int i = 0; i < numvalues; ++i) {
1409    text_t value = format_url(decode_commas(inputvalues[i]));
1410    text_t type = "file://"; // default
1411    if (!value.empty()) {
1412      found = true;
1413      if (i >= numtypes || inputtypes[i].empty()) {
1414    logout << "collectoraction::check_sources: WARNING type not set\n";
1415      } else {
1416    type = inputtypes[i];
1417      }
1418      if (type == "file://") {
1419    if (!file_exists(value) && !directory_exists(value)) {
1420      failedsources[decode_commas(inputvalues[i])] = "1";
1421      badsources = true;
1422    }
1423      } else if (type == "http://") {
1424    if (gsdl_system ("perl -S ping.pl -quiet http://" + value, true, logout)) {
1425      failedsources[decode_commas(inputvalues[i])] = "1";
1426      badsources = true;
1427    }
1428      } else if (type == "ftp://") {
1429    if (gsdl_system ("perl -S ping.pl -quiet ftp://" + value, true, logout)) {
1430      failedsources[decode_commas(inputvalues[i])] = "1";
1431      badsources = true;
1432    }
1433      }
1434    }
1435  }
1436
1437  // set badsources if there weren't any sources at all
1438  if (!found) badsources = true;
1439
1440  if (badsources) return false;
1441  return true;
1442}
1443
1444text_t collectoraction::get_button(cgiargsclass &args, const text_t &thispage,
1445                   const text_t &color,
1446                   const text_t &type, bool enabled)
1447{
1448
1449  if ((color != "green" && color != "grey" && color != "yellow") ||
1450      (type != "info" && type != "srce" && type != "conf" && type != "bild" && type != "view"))
1451    return g_EmptyText;
1452
1453  text_t href = "_http"+type+"_";
1454  text_t target = "";
1455
1456  if (thispage == "info" || thispage == "srce" || thispage == "conf" ||
1457      thispage == "bildcancel" || thispage == "bildfail") {
1458    // call the check submit macro instead of linking directly to the page
1459    href="\"javascript:check_submit('"+type+"');\"";
1460  } else if (type == "view") {
1461    // view button is special case as it needs a target=_top
1462    target = " target=_top";
1463  }
1464
1465  text_t tdclass = "wizardbar"+color;
1466  if (enabled) {
1467    // link to the appropriate page
1468    return "<td class="+tdclass+"><a href="+href+target+">_text"+type+"_</a></td>";
1469  }
1470  else {
1471    // just display the text
1472    return "<td class="+tdclass+">_text"+type+"_</td>";
1473  }
1474}
1475
1476#endif //GSDL_USE_COLLECTOR_ACTION
Note: See TracBrowser for help on using the browser.