source: trunk/gsdl/src/recpt/collectoraction.cpp@ 2774

Last change on this file since 2774 was 2774, checked in by sjboddie, 23 years ago

Tidied up the collector's error handling. Hopefully the situation where the
status page loops continuously after an error will now be rare (it can
still happen if perl or one of the third party converters hangs though)

  • Property svn:keywords set to Author Date Id Revision
File size: 66.0 KB
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// note that the collectoraction relies on having direct access to a
27// collections configuration file. this breaks the separation between
28// receptionist and collection server and so is not suitable (at least
29// in its current form) for use when collection servers are separate
30// from the receptionist (e.g. when using the CORBA protocol).
31
32// following line required to get fstream.filedesc() on darwin (Mac OS X)
33#define _STREAM_COMPAT 1
34// required for utsname on solaris???
35#define _XOPEN_SOURCE 1
36#define _XOPEN_SOURCE_EXTENDED 1
37
38#include "collectoraction.h"
39#include "OIDtools.h"
40#include "fileutil.h"
41#include "cfgread.h"
42#include "gsdltools.h"
43#include "gsdltimes.h"
44#include "nullproto.h"
45#include "argdb.h"
46#include "cgiutils.h"
47
48#if !defined (__WIN32__)
49#include <sys/utsname.h>
50#include <unistd.h>
51#endif
52
53collectoraction::collectoraction () {
54
55 recpt = NULL;
56 disabled = true;
57 do_mkcol = false;
58 badsources = false;
59 failedsources.erase(failedsources.begin(), failedsources.end());
60 gsdlosc = NULL;
61 gsdlhomec = NULL;
62 pathc = NULL;
63
64 cgiarginfo arg_ainfo;
65 arg_ainfo.shortname = "a";
66 arg_ainfo.longname = "action";
67 arg_ainfo.multiplechar = true;
68 arg_ainfo.defaultstatus = cgiarginfo::weak;
69 arg_ainfo.argdefault = "collector";
70 arg_ainfo.savedarginfo = cgiarginfo::must;
71 argsinfo.addarginfo (NULL, arg_ainfo);
72
73 arg_ainfo.shortname = "p";
74 arg_ainfo.longname = "page";
75 arg_ainfo.multiplechar = true;
76 arg_ainfo.defaultstatus = cgiarginfo::weak;
77 arg_ainfo.argdefault = "intro";
78 arg_ainfo.savedarginfo = cgiarginfo::must;
79 argsinfo.addarginfo (NULL, arg_ainfo);
80
81 // temporary directory name for this collector
82 // session
83 arg_ainfo.shortname = "bc1tmp";
84 arg_ainfo.longname = "collector specific";
85 arg_ainfo.multiplechar = true;
86 arg_ainfo.defaultstatus = cgiarginfo::weak;
87 arg_ainfo.argdefault = "";
88 arg_ainfo.savedarginfo = cgiarginfo::must;
89 argsinfo.addarginfo (NULL, arg_ainfo);
90
91 arg_ainfo.shortname = "bc1fullname";
92 arg_ainfo.longname = "collector specific";
93 arg_ainfo.multiplechar = true;
94 arg_ainfo.defaultstatus = cgiarginfo::weak;
95 arg_ainfo.argdefault = "";
96 arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
97 argsinfo.addarginfo (NULL, arg_ainfo);
98
99 arg_ainfo.shortname = "bc1dirname";
100 arg_ainfo.longname = "collector specific";
101 arg_ainfo.multiplechar = true;
102 arg_ainfo.defaultstatus = cgiarginfo::weak;
103 arg_ainfo.argdefault = "";
104 arg_ainfo.savedarginfo = cgiarginfo::must;
105 argsinfo.addarginfo (NULL, arg_ainfo);
106
107 arg_ainfo.shortname = "bc1contactemail";
108 arg_ainfo.longname = "collector specific";
109 arg_ainfo.multiplechar = true;
110 arg_ainfo.defaultstatus = cgiarginfo::weak;
111 arg_ainfo.argdefault = "";
112 arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
113 argsinfo.addarginfo (NULL, arg_ainfo);
114
115 arg_ainfo.shortname = "bc1aboutdesc";
116 arg_ainfo.longname = "collector specific";
117 arg_ainfo.multiplechar = true;
118 arg_ainfo.defaultstatus = cgiarginfo::weak;
119 arg_ainfo.argdefault = "";
120 arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
121 argsinfo.addarginfo (NULL, arg_ainfo);
122
123 arg_ainfo.shortname = "bc1clone";
124 arg_ainfo.longname = "collector specific";
125 arg_ainfo.multiplechar = false;
126 arg_ainfo.defaultstatus = cgiarginfo::weak;
127 arg_ainfo.argdefault = "0";
128 arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
129 argsinfo.addarginfo (NULL, arg_ainfo);
130
131 arg_ainfo.shortname = "bc1clonecol";
132 arg_ainfo.longname = "collector specific";
133 arg_ainfo.multiplechar = true;
134 arg_ainfo.defaultstatus = cgiarginfo::weak;
135 arg_ainfo.argdefault = "";
136 arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
137 argsinfo.addarginfo (NULL, arg_ainfo);
138
139 // set when cloning option has changed
140 arg_ainfo.shortname = "bc1clonechanged";
141 arg_ainfo.longname = "collector specific";
142 arg_ainfo.multiplechar = false;
143 arg_ainfo.defaultstatus = cgiarginfo::weak;
144 arg_ainfo.argdefault = "0";
145 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
146 argsinfo.addarginfo (NULL, arg_ainfo);
147
148 // only set when one of the fields was changed in
149 // the "collection info" page
150 arg_ainfo.shortname = "bc1infochanged";
151 arg_ainfo.longname = "collector specific";
152 arg_ainfo.multiplechar = false;
153 arg_ainfo.defaultstatus = cgiarginfo::weak;
154 arg_ainfo.argdefault = "0";
155 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
156 argsinfo.addarginfo (NULL, arg_ainfo);
157
158 // only set when cfg file is altered from within
159 // "configure collection" page
160 arg_ainfo.shortname = "bc1cfgchanged";
161 arg_ainfo.longname = "collector specific";
162 arg_ainfo.multiplechar = false;
163 arg_ainfo.defaultstatus = cgiarginfo::weak;
164 arg_ainfo.argdefault = "0";
165 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
166 argsinfo.addarginfo (NULL, arg_ainfo);
167
168 arg_ainfo.shortname = "cfgfile";
169 arg_ainfo.longname = "configuration file contents";
170 arg_ainfo.multiplechar = true;
171 arg_ainfo.defaultstatus = cgiarginfo::weak;
172 arg_ainfo.argdefault = "";
173 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
174 argsinfo.addarginfo (NULL, arg_ainfo);
175
176 arg_ainfo.shortname = "bc1dodelete";
177 arg_ainfo.longname = "collector specific";
178 arg_ainfo.multiplechar = false;
179 arg_ainfo.defaultstatus = cgiarginfo::weak;
180 arg_ainfo.argdefault = "0";
181 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
182 argsinfo.addarginfo (NULL, arg_ainfo);
183
184 // will be set if we arrived at the "configure collection" page
185 // via the "changing an existing collection" page
186 arg_ainfo.shortname = "bc1econf";
187 arg_ainfo.longname = "collector specific";
188 arg_ainfo.multiplechar = false;
189 arg_ainfo.defaultstatus = cgiarginfo::weak;
190 arg_ainfo.argdefault = "0";
191 arg_ainfo.savedarginfo = cgiarginfo::must;
192 argsinfo.addarginfo (NULL, arg_ainfo);
193
194 // will be set if we arrived at the "source data" page
195 // via the "changing an existing collection" page
196 arg_ainfo.shortname = "bc1esrce";
197 arg_ainfo.longname = "collector specific";
198 arg_ainfo.multiplechar = false;
199 arg_ainfo.defaultstatus = cgiarginfo::weak;
200 arg_ainfo.argdefault = "0";
201 arg_ainfo.savedarginfo = cgiarginfo::must;
202 argsinfo.addarginfo (NULL, arg_ainfo);
203
204 arg_ainfo.shortname = "bc1inputnum";
205 arg_ainfo.longname = "collector specific";
206 arg_ainfo.multiplechar = true;
207 arg_ainfo.defaultstatus = cgiarginfo::weak;
208 arg_ainfo.argdefault = "3";
209 arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
210 argsinfo.addarginfo (NULL, arg_ainfo);
211
212 arg_ainfo.shortname = "bc1input";
213 arg_ainfo.longname = "collector specific";
214 arg_ainfo.multiplechar = true;
215 arg_ainfo.multiplevalue = true;
216 arg_ainfo.defaultstatus = cgiarginfo::weak;
217 arg_ainfo.argdefault = "";
218 arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
219 argsinfo.addarginfo (NULL, arg_ainfo);
220
221 arg_ainfo.shortname = "bc1inputtype";
222 arg_ainfo.longname = "collector specific";
223 arg_ainfo.multiplechar = true;
224 arg_ainfo.multiplevalue = true;
225 arg_ainfo.defaultstatus = cgiarginfo::weak;
226 arg_ainfo.argdefault = "";
227 arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
228 argsinfo.addarginfo (NULL, arg_ainfo);
229
230 // will be set when we've just come from the "source data" page
231 arg_ainfo.shortname = "bc1fromsrce";
232 arg_ainfo.longname = "collector specific";
233 arg_ainfo.multiplechar = false;
234 arg_ainfo.multiplevalue = false;
235 arg_ainfo.defaultstatus = cgiarginfo::weak;
236 arg_ainfo.argdefault = "0";
237 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
238 argsinfo.addarginfo (NULL, arg_ainfo);
239}
240
241collectoraction::~collectoraction () {
242 if (gsdlosc != NULL) delete gsdlosc;
243 if (gsdlhomec != NULL) delete gsdlhomec;
244 if (pathc != NULL) delete pathc;
245}
246
247
248void collectoraction::configure (const text_t &key, const text_tarray &cfgline) {
249 if ((key == "collector") && (cfgline.size() == 1) &&
250 (cfgline[0] == "true" || cfgline[0] == "on" || cfgline[0] == "enabled")) {
251 disabled = false;
252 } else {
253 // call the parent class to deal with the things which
254 // are not dealt with here
255 action::configure (key, cfgline);
256 }
257}
258
259
260bool collectoraction::init (ostream & /*logout*/) {
261
262 // set up GSDLOS, GSDLHOME and PATH environment variables
263 text_t gsdlos, path;
264 unsigned int path_separator = ':';
265#if defined (__WIN32__)
266 gsdlos = "windows";
267 path_separator = ';';
268#else
269 struct utsname *buf = new struct utsname();
270 int i = uname (buf);
271 if (i == -1) gsdlos = "linux"; // uname failed
272 else gsdlos.setcstr (buf->sysname);
273 delete buf;
274 lc (gsdlos);
275#endif
276
277 pathc = getenv ("PATH");
278 path = filename_cat (gsdlhome, "bin", gsdlos);
279 path.push_back (path_separator);
280 path += filename_cat (gsdlhome, "bin", "script");
281 if (pathc != NULL) {
282 path.push_back (path_separator);
283 path += pathc;
284 }
285 path = "PATH=" + path;
286
287 gsdlos = "GSDLOS=" + gsdlos;
288 text_t setgsdlhome = "GSDLHOME=" + gsdlhome;
289
290 // these will be cleaned up in the destructor
291 gsdlosc = gsdlos.getcstr();
292 gsdlhomec = setgsdlhome.getcstr();
293 pathc = path.getcstr();
294
295 putenv (gsdlosc);
296 putenv (gsdlhomec);
297 putenv (pathc);
298
299 return true;
300}
301
302bool collectoraction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args,
303 ostream &logout) {
304
305 text_t &current_page = args["p"];
306
307 // note that the "bildstatus" and "bildframe1" pages don't actually do anything
308 // functional so we don't need to worry about authenticating them (it's the
309 // underlying "bild" page that does the building (and creates the frameset))
310 // This helps us overcome a bit of a problem we have with multiple pages trying
311 // to read from the key.db database at the same time.
312 if (current_page != "intro" && current_page != "bildstatus" && current_page != "bildframe1") {
313 // authenticate the user if authentication is available
314 args["uan"] = 1;
315 args["ug"] = "colbuilder";
316 }
317
318 if (current_page == "new" || current_page == "existing") {
319
320 // assign (and create) a temporary directory
321 assign_tmpname (args, logout);
322
323 // clean up any old builds left laying about in the tmp directory
324 // (note that it's possible this could take some time if there's a huge
325 // partially built collection laying about so we'll make it an asynchronous
326 // system call)
327 gsdl_system ("perl -S cleantmp.pl", false, logout);
328 }
329
330 if (current_page != "intro" && current_page != "bildstatus" &&
331 current_page != "bildframe1" && current_page != "new") {
332 // update arguments that were saved to the harddrive
333 text_tmap saved_args;
334 saved_args["bc1fullname"] = "";
335 saved_args["bc1contactemail"] = "";
336 saved_args["bc1aboutdesc"] = "";
337 saved_args["bc1clone"] = "";
338 saved_args["bc1clonecol"] = "";
339 saved_args["bc1inputnum"] = "";
340 saved_args["bc1input"] = "";
341 saved_args["bc1inputtype"] = "";
342
343 // update the argdb database with any arguments that were set
344 // by previous page
345 text_tmap::iterator here = saved_args.begin();
346 text_tmap::iterator end = saved_args.end();
347 while (here != end) {
348 if (args.lookupcgiarg((*here).first).source != cgiarg_t::default_arg) {
349 (*here).second = args[(*here).first];
350 }
351 here++;
352 }
353
354 argdb *args_on_disk = new argdb(filename_cat(gsdlhome, "tmp", args["bc1tmp"], "argdb.db"));
355 if (!args_on_disk->update_args(saved_args)) {
356 // error
357
358 }
359
360 // update args from argdb
361 saved_args.erase(saved_args.begin(), saved_args.end());
362 if (!args_on_disk->get_args(saved_args)) {
363 // error
364
365 }
366 delete args_on_disk;
367 here = saved_args.begin();
368 end = saved_args.end();
369 while (here != end) {
370 if (!(*here).second.empty()) {
371 args[(*here).first] = (*here).second;
372 }
373 here ++;
374 }
375 }
376
377 if (args["bc1infochanged"] == "1") {
378
379 if (args["bc1dirname"].empty()) {
380 // we've just come from the "collection information" page for the
381 // first time so we'll need to create the collection with mkcol.pl
382 // and set up bc1dirname - we do this part here instead of in do_action
383 // because the bc1dirname argument must be set to its new value before
384 // the compressedoptions macros are set.
385 args["bc1dirname"] = get_directory_name (args["bc1fullname"]);
386
387 text_t createfile = filename_cat (gsdlhome, "tmp", args["bc1tmp"], ".create");
388 if (!file_exists (createfile)) {
389 // we could do the mkcol.pl here but I guess it's nicer to do it in do_action()
390 do_mkcol = true;
391 } else {
392 // .create file already exists but bc1dirname wasn't set ... this should only be
393 // able to occur when the "reload" (and possibly the "back" and "forward" buttons)
394 // have been used to get us here.
395 // we'll check that the bc1dirname directory exists (in case of the unlikely
396 // possibility that get_directory_name returned a different value this time
397 // than it did originally).
398 text_t coldir = filename_cat (get_collectdir(args), args["bc1dirname"]);
399 if (!directory_exists (coldir)) {
400 message = "reloaderror";
401 return true;
402 }
403 }
404 } else {
405 // "collection information" has been changed after collection already exists
406 // so we'll need to update the cfg file.
407 update_cfgfile_partial (args, false, logout);
408 }
409 }
410
411 if (args["bc1cfgchanged"] == "1") {
412 // configuration file has been changed from the "configure collection"
413 // page. we need to update the file on disk and catch bc1 arguments up
414 // with changes.
415 update_cfgfile_complete (args, logout);
416 }
417
418 if (args["bc1clonechanged"] == "1") {
419 // cloning option has been changed on "source data" page. if it was turned
420 // on we want to create a new collect.cfg file using the bc1clonecol cfg file
421 // as a model (we'll save the old file as collect.cfg.org). if cloning was
422 // turned off we'll revert to using the collect.cfg.org file (which will need
423 // updating in case the bc1 arguments have been altered since cloning was
424 // turned on).
425 update_cfgfile_clone (args, logout);
426
427 // if cloning has just been turned on we'll also copy the rest of the files
428 // (excluding collect.cfg which we've already done) from the cloned collections
429 // etc directory to the new collection.
430 if (args["bc1clone"] == "1") {
431 text_t clone_etc = filename_cat(gsdlhome, "collect", args["bc1clonecol"], "etc");
432 text_t new_etc = filename_cat(get_collectdir(args), args["bc1dirname"], "etc");
433 text_tarray files;
434
435 if (read_dir (clone_etc, files)) {
436 text_tarray::const_iterator here = files.begin();
437 text_tarray::const_iterator end = files.end();
438 while (here != end) {
439 if (*here != "collect.cfg" && *here != "collect.cfg.org") {
440 file_copy (filename_cat(clone_etc, *here), filename_cat(new_etc, *here));
441 }
442 here ++;
443 }
444 } else {
445 outconvertclass text_t2ascii;
446 logout <<text_t2ascii << "collectoraction::check_cgiargs couldn't read from "
447 << clone_etc << " directory\n";
448 }
449 }
450 }
451
452 if (current_page == "bildstatus" || current_page == "bildcancel") {
453 // if .final file exists then build has finished
454 text_t fbld = filename_cat (gsdlhome, "tmp", args["bc1tmp"], args["bc1dirname"] + ".bld.final");
455 if (file_exists (fbld)) {
456 char *fbldc = fbld.getcstr();
457 ifstream fbld_in (fbldc);
458 if (fbld_in) {
459 failcode = fbld_in.get();
460 fbld_in.close();
461 if (failcode == '0') {
462 // success - we need to create and configure a collection server for the
463 // newly built collection (for fastcgi and local library where
464 // initialization isn't going to be redone when the user clicks the
465 // "view your new collection" button
466 create_colserver (args["bc1dirname"], logout);
467 current_page = "bilddone";
468 }
469 else current_page = "bildfail";
470 } else {
471 // assume build failed (we shouldn't get here though ... right?)
472 current_page = "bildfail";
473 }
474 delete fbldc;
475 }
476 }
477
478 if (args["bc1fromsrce"] == "1") {
479
480 // we've just come from the "source data" page so we need to check that
481 // input sources are valid
482 if (!check_sources(args, logout)) {
483 args["p"] = "srce";
484 }
485 }
486
487 return true;
488}
489
490void collectoraction::update_cfgfile_clone (cgiargsclass &args, ostream &logout) {
491
492 text_t tmpdir = filename_cat(gsdlhome, "tmp", args["bc1tmp"]);
493 text_t cfgfile = filename_cat(tmpdir, args["bc1dirname"], "etc", "collect.cfg");
494 if (!file_exists (cfgfile)) {
495 message = "tmpfail";
496 return;
497 }
498
499 text_t cfgfile_org = filename_cat (tmpdir, "collect.cfg.org");
500
501 if (args["bc1clone"] == "1") {
502 // cloning was turned on
503
504 text_t cfgfile_clone = filename_cat(gsdlhome, "collect", args["bc1clonecol"], "etc", "collect.cfg");
505 if (file_exists (cfgfile_clone)) {
506 // if .org file doesn't exist already create it
507 if (!file_exists (cfgfile_org)) {
508 if (!file_copy (cfgfile, cfgfile_org)) {
509 message = "tmpfail";
510 return;
511 }
512 }
513 // copy clone collections cfg file to new collection
514 if (!file_copy (cfgfile_clone, cfgfile)) {
515 message = "tmpfail";
516 return;
517 }
518 // update the new cfg file
519 update_cfgfile_partial (args, true, logout);
520
521 } else {
522 // can't clone non-existant or read-protected collection
523 message = "clonefail";
524 }
525
526 } else {
527 // cloning has been turned off having been on at some point. the .org file
528 // should exist, if it doesn't we'll bail out and leave the user with the
529 // cloned copy
530 if (file_exists (cfgfile_org)) {
531 // copy original back again and update it with any recent changes
532 if (file_copy (cfgfile_org, cfgfile)) {
533 update_cfgfile_partial (args, false, logout);
534 } else {
535 message = "tmpfail";
536 }
537 }
538 }
539}
540
541// update configuration file on disk to match bc1 arguments
542// there's a special case if the clone option is true as certain parts of a
543// config file should not be cloned (e.g. the iconcollection stuff)
544void collectoraction::update_cfgfile_partial (cgiargsclass &args, bool clone, ostream &logout) {
545
546 text_t cfgfile = filename_cat(get_collectdir(args), args["bc1dirname"], "etc", "collect.cfg");
547 char *cfgfilec = cfgfile.getcstr();
548
549#if defined (__WIN32__)
550 // make sure collect.cfg isn't read-only
551 _chmod (cfgfilec, _S_IREAD | _S_IWRITE);
552#endif
553
554 vector<text_tarray> cfgarray;
555
556 // read in cfg file
557 ifstream cfg_in (cfgfilec);
558 if (cfg_in) {
559 text_tarray cfgline;
560 while (read_cfg_line(cfg_in, cfgline) >= 0) {
561 if (cfgline.size () >= 2) {
562 if (cfgline[0] == "creator" || cfgline[0] == "maintainer") {
563 cfgline[1] = args["bc1contactemail"];
564 } else if (cfgline[0] == "collectionmeta") {
565 if (cfgline[1] == "collectionname") {
566 cfgline[2] = args["bc1fullname"];
567 } else if (cfgline[1] == "collectionextra") {
568 cfgline[2] = carriage_replace (args["bc1aboutdesc"], 0);
569 } else if (clone && (cfgline[1] == "iconcollection" ||
570 cfgline[1] == "iconcollectionsmall")) {
571 cfgline[2] = "";
572 }
573 }
574 }
575 cfgarray.push_back (cfgline);
576 }
577 cfg_in.close();
578
579 // now write cfg file back out
580#ifdef __WIN32__
581 ofstream cfg_out (cfgfilec, ios::binary);
582#else
583 ofstream cfg_out (cfgfilec);
584#endif
585 if (cfg_out) {
586 // lock the file
587 int fd = GSDL_GET_FILEDESC(cfg_out);
588 int lock_val = 1;
589 GSDL_LOCK_FILE (fd);
590 if (lock_val != 0) {
591 logout << "Error: Couldn't lock file " << cfgfilec << "\n";
592 cfg_out.close();
593 message = "tmpfail";
594
595 } else {
596
597 vector<text_tarray>::const_iterator this_line = cfgarray.begin();
598 vector<text_tarray>::const_iterator end_line = cfgarray.end();
599 while (this_line != end_line) {
600 write_cfg_line (cfg_out, *this_line);
601 this_line ++;
602 }
603 GSDL_UNLOCK_FILE (fd);
604 cfg_out.close();
605 }
606
607 } else {
608 logout << "collectoraction::update_cfgfile_partial: unable to open "
609 << cfgfilec << " for output\n";
610 message = "tmpfail";
611 }
612
613 } else {
614 logout << "collectoraction::update_cfgfile_partial: unable to open "
615 << cfgfilec << " for input\n";
616 message = "tmpfail";
617 }
618
619 delete cfgfilec;
620}
621
622// replace configuration file on disk with that in the cfgfile argument and
623// catch other bc1 arguments up with those the new cfgfile contains
624void collectoraction::update_cfgfile_complete (cgiargsclass &args, ostream &logout) {
625
626 text_t cfgfile = filename_cat(get_collectdir(args), args["bc1dirname"], "etc", "collect.cfg");
627 char *cfgfilec = cfgfile.getcstr();
628
629#ifdef __WIN32__
630 // make sure collect.cfg isn't read-only
631 _chmod (cfgfilec, _S_IREAD | _S_IWRITE);
632 ofstream cfg_out (cfgfilec, ios::binary);
633#else
634 ofstream cfg_out (cfgfilec);
635#endif
636
637 if (cfg_out) {
638 // lock the file
639 int fd = GSDL_GET_FILEDESC(cfg_out);
640 int lock_val = 1;
641 GSDL_LOCK_FILE (fd);
642 if (lock_val != 0) {
643 logout << "Error: Couldn't lock file " << cfgfilec << "\n";
644 cfg_out.close();
645 message = "tmpfail";
646
647 } else {
648
649 outconvertclass text_t2ascii;
650 cfg_out << text_t2ascii << args["cfgfile"];
651 GSDL_UNLOCK_FILE (fd);
652 cfg_out.close();
653
654 // now that we've written the file we'll read it back again and
655 // update our bc1 arguments
656 ifstream cfg_in (cfgfilec);
657 if (cfg_in) {
658 text_tarray cfgline;
659 while (read_cfg_line(cfg_in, cfgline) >= 0) {
660 if (cfgline.size () >= 2) {
661 if (cfgline[0] == "creator") {
662 args["bc1contactemail"] = cfgline[1];
663 } else if (cfgline[0] == "collectionmeta") {
664 if (cfgline[1] == "collectionname") {
665 args["bc1fullname"] = cfgline[2];
666 } else if (cfgline[1] == "collectionextra") {
667 args["bc1aboutdesc"] = carriage_replace (cfgline[2], 1);
668 }
669 }
670 }
671 }
672 cfg_in.close();
673 } else {
674 logout << "collectoraction::update_cfgfile_complete: unable to open "
675 << cfgfilec << " for input\n";
676 message = "tmpfail";
677 }
678 }
679 } else {
680 logout << "collectoraction::update_cfgfile_complete: unable to open "
681 << cfgfilec << " for output\n";
682 message = "tmpfail";
683 }
684
685 delete cfgfilec;
686}
687
688void collectoraction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
689 response_t &response,text_t &response_data,
690 ostream &/*logout*/) {
691 response = content;
692 response_data = "text/html";
693}
694
695// return html for buttons used in collector bar
696// color may be "green", "grey", or "yellow"
697// type may be:
698// "info" --> "collection information" button
699// "srce" --> "source data" button
700// "conf" --> "configure collection" button
701// "bild" --> "build collection" button
702// "view" --> "view collection" button
703// if enabled is true button will be flashy rollover type and
704// will be hyperlinked
705
706text_t collectoraction::get_button (const text_t &thispage, const text_t &color,
707 const text_t &type, bool enabled) {
708
709 if ((color != "green" && color != "grey" && color != "yellow") ||
710 (type != "info" && type != "srce" && type != "conf" && type != "bild" && type != "view"))
711 return "";
712
713 text_t prefix = "gc";
714 if (color == "grey") prefix = "nc";
715 else if (color == "yellow") prefix = "yc";
716
717 text_t httpicon = "httpicon" + prefix + type;
718
719 if (enabled) {
720 text_t gsmacro = "_gsimage_";
721 if (thispage == "info" || thispage == "srce" || thispage == "conf" ||
722 thispage == "bildcancel" || thispage == "bildfail") {
723 gsmacro = "_gsjimage_";
724 } else if (type == "view") {
725 // view button is special case as it needs a target=_top
726 gsmacro = "_gstimage_";
727 }
728 return "<td>" + gsmacro + "(_collector:http" + type + "_,_collector:" + httpicon +
729 "of_,_collector:" + httpicon + "on_," + type + ",_collector:text" + type + "_)</td>\n";
730 } else {
731 return "<td>_icon" + prefix + type + "of_</td>\n";
732 }
733}
734
735// set the _fullnamemenu_ macro (and _warnindex_ and _selectedindex_ if
736// we're on the "srce" page)
737void collectoraction::set_fullnamemenu (displayclass &disp, cgiargsclass &args,
738 recptprotolistclass *protos, ostream &logout) {
739
740 if (recpt == NULL) {
741 logout << "ERROR (collectoraction::set_fullnamemenu): This action does not contain\n"
742 << " information about any receptionists. The method set_receptionist was\n"
743 << " probably not called from the module which instantiated this action.\n";
744 return;
745 }
746
747 text_t &current_page = args["p"];
748 text_t currentname = args["bc1dirname"];
749 if (current_page == "srce") currentname = args["bc1clonecol"];
750
751 text_tarray dirnames;
752 text_tarray fullnames;
753 vector<bool> write_protected;
754 bool is_selected = false;
755 int selected_index = 0;
756 int index = 0;
757
758 recptprotolistclass::iterator rprotolist_here = protos->begin();
759 recptprotolistclass::iterator rprotolist_end = protos->end();
760 while (rprotolist_here != rprotolist_end) {
761 if ((*rprotolist_here).p != NULL) {
762
763 // don't include z39.50 collections
764 comerror_t err = noError;
765 if ((*rprotolist_here).p->get_protocol_name (err) == "z3950proto") {
766 rprotolist_here ++;
767 continue;
768 }
769
770 text_tarray collist;
771 (*rprotolist_here).p->get_collection_list (collist, err, logout);
772 if (err == noError) {
773 text_tarray::iterator collist_here = collist.begin();
774 text_tarray::iterator collist_end = collist.end();
775 FilterResponse_t response;
776 text_tset metadata;
777 metadata.insert ("collectionname");
778 while (collist_here != collist_end) {
779 ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr ((*rprotolist_here).p, *collist_here, logout);
780 if (cinfo != NULL) {
781 text_t collectionname = *collist_here;
782 if (!cinfo->collectionmeta["collectionname"].empty()) {
783 // get collection name from the collection cfg file
784 collectionname = cinfo->collectionmeta["collectionname"];
785 } else if (get_info ("collection", *collist_here, metadata, false,
786 (*rprotolist_here).p, response, logout)) {
787 // get collection name from gdbm file
788 collectionname = response.docInfo[0].metadata["collectionname"].values[0];
789 }
790 dirnames.push_back(*collist_here);
791 fullnames.push_back(collectionname);
792 // check to see if the collection is writable
793 if (collection_protected (*collist_here)) write_protected.push_back(true);
794 else write_protected.push_back(false);
795
796 if (*collist_here == currentname) {
797 is_selected = true;
798 selected_index = index;
799 }
800 index ++;
801 }
802 collist_here ++;
803 }
804 }
805 }
806 rprotolist_here ++;
807 }
808
809 bool first = true;
810 text_t warnindex;
811 text_t fullnamemenu = "<select name=\"bc1dirname\">\n";
812 if (current_page == "srce") {
813 fullnamemenu = "<select name=\"bc1clonecol\" onChange=\"menuchange();\">\n";
814 fullnamemenu += "<option value=defaultstructure";
815 if (!is_selected) fullnamemenu += " selected>";
816 else fullnamemenu.push_back('>');
817 fullnamemenu += "default structure\n";
818 }
819 for (int i = 0; i < index; i ++) {
820 // don't want write protected collections in list on "change existing
821 // collection" page
822 if (write_protected[i] && current_page == "existing") continue;
823 fullnamemenu += "<option value=\"" + dirnames[i] + "\"";
824 if ((i == 0 && !is_selected && current_page != "srce") ||
825 (is_selected && i == selected_index)) {
826 fullnamemenu += " selected";
827 selected_index++;
828 is_selected = false;
829 }
830 fullnamemenu.push_back ('>');
831 fullnamemenu += fullnames[i];
832 fullnamemenu.push_back ('\n');
833
834 // add to Warnindex if collection uses any dubious plugins
835 // (if creating clone collection list)
836 if (current_page == "srce") {
837 if (first) warnindex += "0,";
838 else warnindex.push_back(',');
839 if (uses_weird_plugin (dirnames[i])) {
840 warnindex += text_t (1);
841 } else {
842 warnindex += text_t (0);
843 }
844 }
845 first = false;
846 }
847 fullnamemenu += "</select>\n";
848
849 disp.setmacro ("fullnamemenu", "collector", fullnamemenu);
850 if (current_page == "srce") {
851 disp.setmacro ("warnindex", "collector", warnindex);
852 disp.setmacro ("selectedindex", "collector", text_t(selected_index));
853 }
854}
855
856// set _sourcelist_ and _badsources_ macros
857void collectoraction::set_inputsourceboxes (displayclass &disp, cgiargsclass &args,
858 ostream &logout) {
859
860 if (badsources) disp.setmacro ("badsources", "collector", "1");
861
862 text_t sourcelist = get_source_box(args["bc1input"], args["bc1inputnum"].getint(),
863 args["bc1inputtype"]);
864
865 disp.setmacro("sourcelist", "collector", sourcelist);
866
867 // reset badsources and failedsources variables
868 badsources = false;
869 failedsources.erase(failedsources.begin(), failedsources.end());
870}
871
872text_t collectoraction::get_source_box (text_t inputarglist, int numboxes,
873 text_t inputtypelist) {
874
875 text_tarray inputvalues;
876 splitchar (inputarglist.begin(), inputarglist.end(), ',', inputvalues);
877 // remove any empty values from the end of the array
878 if (inputvalues.size()) {
879 text_tarray::iterator l = inputvalues.end() - 1;
880 text_tarray::iterator b = inputvalues.begin();
881 while ((*l).empty() && l >= b) {
882 l--;
883 }
884 inputvalues.erase(l+1, inputvalues.end());
885 }
886
887 text_tarray inputtypes;
888 splitchar (inputtypelist.begin(), inputtypelist.end(), ',', inputtypes);
889
890 int numvalues = inputvalues.size();
891 int numtypes = inputtypes.size();
892
893 text_t last = "file://";
894 text_t rv;
895 for (int i = 0; i < numboxes; i++) {
896 rv += "<nobr><select name=\"bc1inputtype\">\n";
897 rv += "<option value=\"file://\"";
898 if ((i < numtypes && inputtypes[i] == "file://") ||
899 (numboxes == 3 && i == 0 && numvalues == 0) ||
900 (i >= 3 && i >= numvalues && last == "file://")) {
901 rv += " selected";
902 last = "file://";
903 }
904 rv += ">file://\n";
905 rv += "<option value=\"http://\"";
906 if ((i < numtypes && inputtypes[i] == "http://") ||
907 (numboxes == 3 && i == 1 && numvalues == 0) ||
908 (i >= 3 && i >= numvalues && last == "http://")) {
909 rv += " selected";
910 last = "http://";
911 }
912 rv += ">http://\n";
913 rv += "<option value=\"ftp://\"";
914 if ((i < numtypes && inputtypes[i] == "ftp://") ||
915 (numboxes == 3 && i == 2 && numvalues == 0) ||
916 (i >= 3 && i >= numvalues && last == "ftp://")) {
917 rv += " selected";
918 last = "ftp://";
919 }
920 rv += ">ftp://\n";
921 rv += "</select>\n";
922 rv += "<input type=text name=\"bc1input\" value=\"";
923 if (i < numvalues) {
924 rv += dm_safe(decode_commas(inputvalues[i]));
925 }
926 rv += "\" size=50>";
927 if (badsources) {
928 if ((i < numvalues) && (!inputvalues[i].empty())) {
929 if (failedsources[decode_commas(inputvalues[i])] == "1") {
930 rv += "_iconcross_";
931 } else {
932 rv += "_icontick_";
933 }
934 } else {
935 rv += "_iconblank_";
936 }
937 }
938 if (i+1 == numboxes) {
939 if (!badsources) rv += "_iconblank_";
940 rv += "_imagemore_</nobr><br>";
941 } else {
942 rv += "</nobr><br>\n";
943 }
944 }
945
946 return rv;
947}
948
949// set the _cfgfile_ macro
950void collectoraction::set_cfgfile (displayclass &disp, cgiargsclass &args, ostream &logout) {
951
952 text_t &collection = args["bc1dirname"];
953 if (collection.empty()) {
954 message = "nocollection";
955 return;
956 }
957
958 // read in collect.cfg
959 text_t cfgfile = filename_cat(get_collectdir(args), collection, "etc", "collect.cfg");
960 char *cfgfilec = cfgfile.getcstr();
961
962#ifdef GSDL_USE_IOS_H
963 ifstream cfg_ifs (cfgfilec, ios::in | ios::nocreate);
964#else
965 ifstream cfg_ifs (cfgfilec, ios::in);
966#endif
967
968 if (cfg_ifs) {
969 // read in collect.cfg
970 text_t cfgtext;
971 char c;
972 cfg_ifs.get(c);
973 while (!cfg_ifs.eof ()) {
974 cfgtext.push_back(c);
975 cfg_ifs.get(c);
976 }
977 cfg_ifs.close();
978
979 // define it as a macro
980 disp.setmacro("cfgfile", "collector", dm_safe(cfgtext));
981
982 } else {
983 logout << "collectoraction::set_cfgfile: couldn't open configuration file ("
984 << cfgfilec << ") for reading\n";
985 message = "tmpfail";
986 }
987 delete cfgfilec;
988}
989
990// set the _statusline_ macro
991void collectoraction::set_statusline (displayclass &disp, cgiargsclass &args, ostream & /*logout*/) {
992
993 // the build command creates .bld.download, .bld.import, and .bld.build files (in that
994 // order) and deletes them (also in that order) when each stage is complete. the .bld
995 // file is the concatenation of all these files.
996 text_t bld_file = filename_cat (gsdlhome, "tmp", args["bc1tmp"], args["bc1dirname"] + ".bld");
997 text_t statusline;
998
999 if (file_exists (bld_file + ".download")) {
1000 statusline = "Downloading files ...<br>\n";
1001 statusline += file_tail (bld_file + ".download", 1, 0);
1002 } else if (file_exists (bld_file + ".import")) {
1003 statusline = "Importing collection ...<br>\n";
1004 statusline += file_tail (bld_file + ".import", 1, 0);
1005 } else if (file_exists (bld_file + ".build")) {
1006 statusline = "Building collection ...<br>\n";
1007 statusline += file_tail (bld_file + ".build", 1, 0);
1008 } else {
1009 statusline += "creating collection ...<br>\n";
1010 statusline += file_tail (bld_file, 1, 0);
1011 }
1012
1013 disp.setmacro ("statusline", "collector", dm_safe(statusline));
1014
1015}
1016
1017void collectoraction::define_internal_macros (displayclass &disp, cgiargsclass &args,
1018 recptprotolistclass *protos, ostream &logout) {
1019
1020 // define_internal_macros sets the following macros:
1021 // _collectorbar_
1022 // _pagescriptextra_
1023 // _fullnamemenu_ -- if displaying the "source data" page or the "changing existing
1024 // collection" page
1025 // _cfgfile_ -- if displaying the "configure collection" page
1026 // _statusline_ -- if displaying the bildstatus page
1027 // _header_ -- may be set for pages that require it
1028 // _textfailmsg_ -- set to different messages depending on failcode returned
1029 // by build script (if build fails)
1030 // _faillog_ - set to last 6 lines of .bld file if build failed
1031 // _gsdlhome_ - the gsdlhome path (dm_safe)
1032
1033 // _sourcelist_ -- "input source" text boxes
1034 // _badsources_ -- will be set to "1" if we've come from the
1035 // "source data" page and there's a problem
1036 // with the input sources
1037
1038 text_t &collector_page = args["p"];
1039 int esrce = args["bc1esrce"].getint();
1040 int econf = args["bc1econf"].getint();
1041
1042 // set _pagescriptextra_ macro to _cpagescriptextra_
1043 disp.setmacro ("pagescriptextra", "collector", "_" + collector_page + "scriptextra_");
1044
1045 if (collector_page == "bildstatus" || collector_page == "bilddone" ||
1046 collector_page == "bildfail" || collector_page == "bildframe1") {
1047 disp.setmacro ("header", "collector", "_" + collector_page + "header_");
1048 }
1049
1050 // set the collectorbar macro
1051 text_t collectorbar = "<table border=0 cellspacing=4 cellpadding=0><tr>\n";
1052
1053 if (collector_page == "new") {
1054 collectorbar += "<td>_icongreyarrow_</td>\n";
1055 collectorbar += get_button (collector_page, "green", "info", true);
1056 collectorbar += "<td>_icongreyarrow_</td>\n";
1057 collectorbar += get_button (collector_page, "grey", "srce", false);
1058 collectorbar += "<td>_icongreyarrow_</td>\n";
1059 collectorbar += get_button (collector_page, "grey", "conf", false);
1060 collectorbar += "<td>_icongreyarrow_</td>\n";
1061 collectorbar += get_button (collector_page, "grey", "bild", false);
1062 collectorbar += "<td>_icongreyarrow_</td>\n";
1063 collectorbar += get_button (collector_page, "grey", "view", false);
1064
1065 } else if (collector_page == "info") {
1066 collectorbar += "<td>_icongreyarrow_</td>\n";
1067 collectorbar += get_button (collector_page, "yellow", "info", false);
1068 collectorbar += "<td>_icongreyarrow_</td>\n";
1069 collectorbar += get_button (collector_page, "green", "srce", true);
1070 collectorbar += "<td>_icongreyarrow_</td>\n";
1071 collectorbar += get_button (collector_page, "grey", "conf", false);
1072 collectorbar += "<td>_icongreyarrow_</td>\n";
1073 collectorbar += get_button (collector_page, "grey", "bild", false);
1074 collectorbar += "<td>_icongreyarrow_</td>\n";
1075 collectorbar += get_button (collector_page, "grey", "view", false);
1076 collectorbar += "</tr><tr><td></td><td align=center>_icongreyuparrow_</td><td colspan=8></td>\n";
1077
1078 } else if (collector_page == "srce") {
1079 collectorbar += "<td>_icongreyarrow_</td>\n";
1080 if (esrce == 1) {
1081 // if we came from the "change an existing collection" page previous button(s)
1082 // are disabled
1083 collectorbar += get_button (collector_page, "grey", "info", false);
1084 } else {
1085 collectorbar += get_button (collector_page, "yellow", "info", true);
1086 }
1087 collectorbar += "<td>_icongreyarrow_</td>\n";
1088 collectorbar += get_button (collector_page, "yellow", "srce", false);
1089 collectorbar += "<td>_icongreyarrow_</td>\n";
1090 collectorbar += get_button (collector_page, "green", "conf", true);
1091 collectorbar += "<td>_icongreyarrow_</td>\n";
1092 collectorbar += get_button (collector_page, "green", "bild", true);
1093 collectorbar += "<td>_icongreyarrow_</td>\n";
1094 collectorbar += get_button (collector_page, "grey", "view", false);
1095 collectorbar += "</tr><tr><td colspan=3></td><td align=center>_icongreyuparrow_</td><td colspan=6></td>\n";
1096
1097 } else if (collector_page == "conf") {
1098 collectorbar += "<td>_icongreyarrow_</td>\n";
1099 // disable appropriate buttons if we came from "change an existing collection"
1100 // page
1101 if (esrce == 1 || econf == 1) {
1102 collectorbar += get_button (collector_page, "grey", "info", false);
1103 } else {
1104 collectorbar += get_button (collector_page, "yellow", "info", true);
1105 }
1106 collectorbar += "<td>_icongreyarrow_</td>\n";
1107 if (econf == 1) {
1108 collectorbar += get_button (collector_page, "grey", "srce", false);
1109 } else {
1110 collectorbar += get_button (collector_page, "yellow", "srce", true);
1111 }
1112 collectorbar += "<td>_icongreyarrow_</td>\n";
1113 collectorbar += get_button (collector_page, "yellow", "conf", false);
1114 collectorbar += "<td>_icongreyarrow_</td>\n";
1115 collectorbar += get_button (collector_page, "green", "bild", true);
1116 collectorbar += "<td>_icongreyarrow_</td>\n";
1117 collectorbar += get_button (collector_page, "grey", "view", false);
1118 collectorbar += "</tr><tr><td colspan=5></td><td align=center>_icongreyuparrow_</td><td colspan=4></td>\n";
1119
1120 } else if (collector_page == "bilddone") {
1121 collectorbar += "<td>_icongreyarrow_</td>\n";
1122 // all previous buttons grey after build was completed
1123 collectorbar += get_button (collector_page, "grey", "info", false);
1124 collectorbar += "<td>_icongreyarrow_</td>\n";
1125 collectorbar += get_button (collector_page, "grey", "srce", false);
1126 collectorbar += "<td>_icongreyarrow_</td>\n";
1127 collectorbar += get_button (collector_page, "grey", "conf", false);
1128 collectorbar += "<td>_icongreyarrow_</td>\n";
1129 collectorbar += get_button (collector_page, "yellow", "bild", false);
1130 collectorbar += "<td>_icongreyarrow_</td>\n";
1131 collectorbar += get_button (collector_page, "green", "view", true);
1132 collectorbar += "</tr><tr><td colspan=7></td><td align=center>_icongreyuparrow_</td><td colspan=2></td>\n";
1133
1134 } else if (collector_page == "bildcancel" || collector_page == "bildfail") {
1135 collectorbar += "<td>_icongreyarrow_</td>\n";
1136 // disable appropriate buttons if we came from "change an existing collection"
1137 // page
1138 if (esrce == 1 || econf == 1) {
1139 collectorbar += get_button (collector_page, "grey", "info", false);
1140 } else {
1141 collectorbar += get_button (collector_page, "yellow", "info", true);
1142 }
1143 collectorbar += "<td>_icongreyarrow_</td>\n";
1144 if (econf == 1) {
1145 collectorbar += get_button (collector_page, "grey", "srce", false);
1146 } else {
1147 collectorbar += get_button (collector_page, "yellow", "srce", true);
1148 }
1149 collectorbar += "<td>_icongreyarrow_</td>\n";
1150 collectorbar += get_button (collector_page, "yellow", "conf", true);
1151 collectorbar += "<td>_icongreyarrow_</td>\n";
1152 collectorbar += get_button (collector_page, "yellow", "bild", true);
1153 collectorbar += "<td>_icongreyarrow_</td>\n";
1154 collectorbar += get_button (collector_page, "grey", "view", false);
1155 }
1156
1157 if (collector_page == "bildfail") {
1158
1159 text_t textfailmsg = "_textfailmsg";
1160 textfailmsg.push_back(failcode);
1161 textfailmsg.push_back('_');
1162 disp.setmacro("textfailmsg", "collector", textfailmsg);
1163
1164 text_t bldlog = filename_cat(gsdlhome, "tmp", args["bc1tmp"], args["bc1dirname"] + ".bld");
1165 text_t rawlog = file_tail (bldlog, 6, 0);
1166 // we'll shove in some <br> tags where \n's occur
1167 text_t faillog;
1168 text_t::const_iterator here = rawlog.begin();
1169 text_t::const_iterator end = rawlog.end();
1170 while (here != end) {
1171 if (*here == '\n') faillog += "<br>";
1172 faillog.push_back (*here);
1173 here ++;
1174 }
1175 disp.setmacro ("faillog", "collector", dm_safe(faillog));
1176 }
1177
1178 collectorbar += "</tr></table>\n";
1179 disp.setmacro ("collectorbar", "collector", collectorbar);
1180
1181 if (collector_page == "srce" || collector_page == "existing")
1182 set_fullnamemenu (disp, args, protos, logout);
1183 if (collector_page == "conf")
1184 set_cfgfile (disp, args, logout);
1185 if (collector_page == "bildstatus")
1186 set_statusline (disp, args, logout);
1187 if (collector_page == "srce") {
1188 set_inputsourceboxes (disp, args, logout);
1189 }
1190
1191 disp.setmacro ("gsdlhome", "collector", dm_safe(gsdlhome));
1192}
1193
1194bool collectoraction::do_action (cgiargsclass &args, recptprotolistclass * /*protos*/,
1195 browsermapclass * /*browsers*/, displayclass &disp,
1196 outconvertclass &outconvert, ostream &textout,
1197 ostream &logout) {
1198
1199 // make sure the collector is enabled
1200 if (disabled) {
1201 textout << outconvert
1202 << "<html>\n"
1203 << "<head>\n"
1204 << "<title>Collector disabled</title>\n"
1205 << "</head>\n"
1206 << "<body bgcolor=\"#ffffff\" text=\"#000000\" link=\"#006666\" "
1207 << "alink=\"#cc9900\" vlink=\"#666633\">\n"
1208 << "<h2>Facility disabled</h2>\n"
1209 << "Sorry, the Collector end-user collection building facility is currently disabled\n"
1210 << "\n</body>\n"
1211 << "</html>\n";
1212 return true;
1213 }
1214
1215 text_t &collector_page = args["p"];
1216 text_t &collection = args["bc1dirname"];
1217
1218 // make sure we have perl (we won't bother with this check for the
1219 // building status pages to avoid slowing things down unneccessarily)
1220 if (collector_page != "bildstatus" && collector_page != "bildframe1" && !perl_ok(logout)) {
1221 textout << outconvert
1222 << "<html>\n"
1223 << "<head>\n"
1224 << "<title>Perl not found</title>\n"
1225 << "</head>\n"
1226 << "<body bgcolor=\"#ffffff\" text=\"#000000\" link=\"#006666\" "
1227 << "alink=\"#cc9900\" vlink=\"#666633\">\n"
1228 << "<h2>Perl not found</h2>\n"
1229 << "Greenstone could not detect perl on this system. It is therefore not\n"
1230 << "possible to build a Greenstone collection, either from the Collector or the \n"
1231 << "command-line tools, or to use the Collector for any other task.\n"
1232 << "<p>Please refer to the Greenstone Installer's Guide for details on\n"
1233 << "installing perl on your system.\n"
1234 << "\n</body>\n"
1235 << "</html>\n";
1236 return true;
1237
1238 }
1239
1240 if (collector_page == "bild") {
1241 // do the work (download, import, build)
1242 gsdl_build (args, logout);
1243
1244 if (message.empty()) {
1245 // bild page is a frameset so we don't want headers and stuff
1246 textout << outconvert << disp << ("_collector:bildcontent_\n");
1247 }
1248 }
1249
1250 if (do_mkcol == true) {
1251 // execute mkcol.pl (do_mkcol is set from within check_cgiargs)
1252 gsdl_mkcol (args, logout);
1253 do_mkcol = false; // reset for fast-cgi
1254 }
1255
1256 if (args["bc1dodelete"] == "1") {
1257 // delete bcidirname collection
1258 if (collection_protected (collection)) {
1259 message = "delinvalid";
1260
1261 } else {
1262
1263 const recptconf &rcinfo = recpt->get_configinfo ();
1264 bool emailuserevents = rcinfo.EmailUserEvents;
1265
1266 // get collection maintainer email from collect.cfg before we
1267 // delete it
1268 text_t colmaintainer;
1269 text_t cfgfile = filename_cat(gsdlhome, "collect", collection, "etc", "collect.cfg");
1270 char *cfgfilec = cfgfile.getcstr();
1271 ifstream cfg_in (cfgfilec);
1272 delete cfgfilec;
1273 if (cfg_in) {
1274 text_tarray cfgline;
1275 while (read_cfg_line(cfg_in, cfgline) >= 0) {
1276 if (cfgline.size () == 2 && cfgline[0] == "maintainer") {
1277 colmaintainer = cfgline[1];
1278 break;
1279 }
1280 }
1281 cfg_in.close();
1282 }
1283 if (colmaintainer.empty()) {
1284 logout << outconvert
1285 << "collectoraction::do_action WARNING: Collection being deleted ("
1286 << collection << ") has no maintainer address. EmailUserEvents "
1287 << "disabled\n";
1288 emailuserevents = false;
1289 }
1290
1291 // first we need to free up the collection's collection server
1292 // we must do this for the local library (and I guess when using
1293 // fastcgi too) as you can't delete the gdbm file while it's
1294 // being kept open by the collection server
1295 remove_colservr (collection, logout);
1296
1297 text_t delete_cmd = "perl -S delcol.pl -f " + collection;
1298 int rv = gsdl_system (delete_cmd, true, logout);
1299 if (rv != 0) {
1300 // deletion failed -- permissions?
1301 message = "delpermission";
1302 } else {
1303 message = "delsuccess";
1304 }
1305
1306 // log the event
1307 if (rcinfo.LogEvents == CollectorEvents || rcinfo.LogEvents == AllEvents) {
1308
1309 text_t eventlog = filename_cat (gsdlhome, "etc", "events.txt");
1310 char *eventlogt = eventlog.getcstr();
1311 ofstream eventl (eventlogt, ios::app);
1312 delete eventlogt;
1313
1314 if (eventl) {
1315 eventl << outconvert << "[Collector Event]\n"
1316 << "Date: " << get_date (true) << "\n"
1317 << "Greenstone Username: " << args["un"] << "\n"
1318 << "Collection: " << collection << "\n"
1319 << "Collection Maintainer: " << colmaintainer << "\n"
1320 << "GSDLHOME: " << gsdlhome << "\n";
1321
1322 if (message == "delsuccess") {
1323 eventl << outconvert
1324 << "The " << collection << " collection was successfully deleted\n\n";
1325 } else {
1326 eventl << outconvert
1327 << "Attempt to delete the " << collection << " collection failed\n\n";
1328 }
1329 eventl.close();
1330
1331 } else {
1332 logout << outconvert << "collectoraction::do_action ERROR: Couldn't open "
1333 << "event log file " << eventlog << " for appending during collection "
1334 << "deletion. LogEvents disabled\n";
1335 }
1336 }
1337
1338 if (rcinfo.EmailEvents == CollectorEvents || rcinfo.EmailEvents == AllEvents || emailuserevents) {
1339 // use sendmail.pl perl script to send email events
1340 text_t tmpmailfile = filename_cat (gsdlhome, "tmp", args["bc1tmp"], "event.txt");
1341 char *tmpmailfilec = tmpmailfile.getcstr();
1342 ofstream tmpfile (tmpmailfilec);
1343 delete tmpmailfilec;
1344 if (tmpfile) {
1345 tmpfile << outconvert << "[Collector Event]\n"
1346 << "Date: " << get_date (true) << "\n"
1347 << "Greenstone Username: " << args["un"] << "\n"
1348 << "Collection: " << collection << "\n"
1349 << "Collection Maintainer: " << colmaintainer << "\n"
1350 << "GSDLHOME: " << gsdlhome << "\n";
1351 if (message == "delsuccess") {
1352 tmpfile << outconvert
1353 << "The " << collection << " collection was successfully deleted\n\n";
1354 } else {
1355 tmpfile << outconvert
1356 << "Attempt to delete the " << collection << " collection failed\n\n";
1357 }
1358 tmpfile.close();
1359 text_t to;
1360 if (rcinfo.EmailEvents == CollectorEvents || rcinfo.EmailEvents == AllEvents) to += rcinfo.maintainer;
1361 if (emailuserevents) {
1362 if (!to.empty()) to.push_back (',');
1363 to += colmaintainer;
1364 }
1365 text_t sendmail_cmd = "perl -S sendmail.pl -to \"" + to + "\" -from \"" + rcinfo.maintainer;
1366 sendmail_cmd += "\" -smtp \"" + rcinfo.MailServer + "\" -subject \"Greenstone Collector Event\"";
1367 sendmail_cmd += " -msgfile \"" + tmpmailfile + "\"";
1368
1369 gsdl_system (sendmail_cmd, false, logout);
1370
1371 } else {
1372 logout << outconvert << "collectoraction::do_action ERROR: Couldn't open "
1373 << "temporary event log file " << tmpmailfile << " during collection "
1374 << "deletion. EmailEvents and EmailUserEvents disabled\n";
1375 }
1376 }
1377 }
1378 }
1379
1380 if (collector_page == "bildcancel" || collector_page == "bildfail") {
1381 // cancel the build (we'll also use the cancel_build script to tidy
1382 // up if the build failed)
1383 gsdl_cancel_build (args, logout);
1384 }
1385
1386 if (collector_page == "expt") {
1387
1388 // export the collection - we'll do a synchronous system call to
1389 // exportcol.pl as that's the easiest way to do it. if it becomes a
1390 // problem that it's taking too long to export a large collection then
1391 // we may have to revisit this.
1392 text_t tmpfile = filename_cat (gsdlhome, "tmp", collection + "_export.txt");
1393 text_t export_cmd = "perl -S exportcol.pl -out \"" + tmpfile + "\" " + collection;
1394 gsdl_system (export_cmd, true, logout);
1395 if (file_exists (tmpfile)) {
1396 text_t returnline = file_tail (tmpfile, 1, 0);
1397 if (returnline.size() > 23 && (substr(returnline.begin(), returnline.begin()+23) == "exportcol.pl succeeded:")) {
1398 // success
1399 message = "exptsuccess";
1400 } else {
1401 message = "exptfail";
1402 }
1403 } else {
1404 message = "exptfail";
1405 }
1406 }
1407
1408 if (message.empty()) {
1409 if (collector_page != "bild") {
1410 // output page ("bild" page was already output above)
1411 textout << outconvert << disp << ("_collector:header_\n")
1412 << ("_collector:" + collector_page + "content_\n")
1413 << ("_collector:footer_\n");
1414 }
1415 } else {
1416 // message was set somewhere (probably an error), output message page
1417 textout << outconvert << disp << ("_collector:header_\n")
1418 << ("_collector:" + message + "content_\n")
1419 << ("_collector:footer_\n");
1420 message.clear();
1421 }
1422 return true;
1423}
1424
1425// if sw = 0 replace all carriage returns in intext with the string "\n"
1426// else replace all occurances of "\n" with a carriage return
1427text_t collectoraction::carriage_replace (const text_t &intext, int sw) {
1428
1429 text_t outtext;
1430 text_t::const_iterator here = intext.begin();
1431 text_t::const_iterator end = intext.end();
1432 while (here != end) {
1433 if (sw == 0) {
1434 if (*here == '\n') {
1435 if ((here+1) != end && *(here+1) == '\r') here ++;
1436 outtext += "\\n";
1437 } else if (*here == '\r') {
1438 if ((here+1) != end && *(here+1) == '\n') here ++;
1439 outtext += "\\n";
1440 } else {
1441 outtext.push_back (*here);
1442 }
1443 } else if (*here == '\\' && (here+1) != end && *(here+1) == 'n') {
1444 outtext.push_back ('\n');
1445 here ++;
1446 } else {
1447 outtext.push_back (*here);
1448 }
1449 here ++;
1450 }
1451 return outtext;
1452}
1453
1454// create a short directory name from fullname
1455text_t collectoraction::get_directory_name (const text_t &fullname) {
1456
1457 text_t shortname;
1458 if (fullname.empty()) {
1459 shortname = "coll";
1460
1461 } else {
1462
1463 // first make all lowercase and remove any dodgy characters
1464 // (i.e. anything not [a-z]
1465 text_t::const_iterator here = fullname.begin();
1466 text_t::const_iterator end = fullname.end();
1467 while (here != end) {
1468 if ((*here >= 'A' && *here <= 'Z') || (*here >= 'a' && *here <= 'z') ||
1469 (*here == ' ')) {
1470 if (*here >= 'A' && *here <= 'Z') shortname.push_back (*here+32);
1471 else if (*here == ' ') {
1472 while ((*(here+1)) == ' ') here ++;
1473 shortname.push_back (*here);
1474 } else shortname.push_back (*here);
1475 }
1476 here ++;
1477 }
1478
1479 text_tarray words;
1480 splitchar (shortname.begin(), shortname.end(), ' ', words);
1481 int num_words = words.size();
1482
1483 if (num_words == 0) {
1484 shortname = "coll";
1485
1486 } else {
1487
1488 shortname.clear();
1489 int use_words = (num_words <= 6) ? num_words : 6;
1490 int substr_len = 6 / use_words;
1491
1492 for (int i = 0; i < use_words; i++) {
1493 if (words[i].size() < substr_len) shortname += words[i];
1494 else shortname += substr (words[i].begin(), words[i].begin()+substr_len);
1495 }
1496 }
1497 }
1498
1499 // check to see if shortname is unique
1500 text_t fulldirname = filename_cat (gsdlhome, "collect", shortname);
1501 if (directory_exists (fulldirname)) {
1502 int version = 0;
1503 text_t newname;
1504 do {
1505 version ++;
1506 newname = shortname;
1507 newname.push_back ('v');
1508 newname.appendint (version);
1509 fulldirname = filename_cat (gsdlhome, "collect", newname);
1510 } while (directory_exists (fulldirname));
1511
1512 shortname = newname;
1513 }
1514
1515 return shortname;
1516}
1517
1518// tests if collection is write protected (currently just checks if
1519// collect.cfg file is writable
1520bool collectoraction::collection_protected (const text_t &collection) {
1521 text_t cfgfile = filename_cat(gsdlhome, "collect", collection, "etc", "collect.cfg");
1522 if (file_writable(cfgfile)) return false;
1523 return true;
1524}
1525
1526// assigns a temporary directory name for this collector session
1527// and creates temporary directory
1528void collectoraction::assign_tmpname (cgiargsclass &args, ostream &logout) {
1529
1530 int i = 0;
1531 text_t tmpname = "tbuild";
1532 while (directory_exists (filename_cat (gsdlhome, "tmp", tmpname + text_t(i)))) {
1533 i++;
1534 }
1535 tmpname.appendint (i);
1536
1537 text_t fulltmpdir = filename_cat (gsdlhome, "tmp", tmpname);
1538 if (!mk_dir (fulltmpdir)) {
1539 outconvertclass text_t2ascii;
1540 logout << text_t2ascii << "collectoraction::assign_tmpname unable to create directory ("
1541 << fulltmpdir << ")\n";
1542 }
1543
1544 args["bc1tmp"] = tmpname;
1545}
1546
1547void collectoraction::gsdl_mkcol (cgiargsclass &args, ostream &logout) {
1548
1549 text_t tmpdir = filename_cat (gsdlhome, "tmp", args["bc1tmp"]);
1550 if (!directory_exists (tmpdir)) {
1551 message = "tmpfail";
1552 return;
1553 }
1554
1555 text_t &collection = args["bc1dirname"];
1556 if (collection.empty()) {
1557 message = "nocollection";
1558 return;
1559 }
1560
1561 // check for a .create file - if it exists then we've already created the collection
1562 text_t createfile = filename_cat (tmpdir, ".create");
1563 if (file_exists (createfile)) {
1564 return;
1565 }
1566
1567 // set up options
1568 text_t options = "-quiet -creator \"" + args["bc1contactemail"] + "\"";
1569 options += " -title \"" + args["bc1fullname"] + "\"";
1570 options += " -about \"" + carriage_replace (args["bc1aboutdesc"] + "_collectorextra_", 0) + "\"";
1571 options += " -collectdir \"" + remove_trailing_slashes(tmpdir) + "\" ";
1572
1573 text_t optionfile = filename_cat (tmpdir, "mkcol.opt");
1574 char *optionfilec = optionfile.getcstr();
1575 ofstream ofile_out (optionfilec);
1576 delete optionfilec;
1577 if (!ofile_out) {
1578 message = "tmpfail";
1579 return;
1580 }
1581 outconvertclass text_t2ascii;
1582 ofile_out << text_t2ascii << options << "\n";
1583 ofile_out.close();
1584
1585 // run mkcol.pl
1586 text_t mkcol_cmd = "perl -S mkcol.pl -optionfile \"" + optionfile;
1587 mkcol_cmd += "\" " + collection;
1588 gsdl_system (mkcol_cmd, true, logout);
1589
1590 // make sure it went ok
1591 text_t cfgfile = filename_cat (tmpdir, collection, "etc", "collect.cfg");
1592 if (!file_writable (cfgfile)) {
1593 message = "mkcolfail";
1594 } else {
1595 // create the .create file (this file is just a place holder to let any future
1596 // pages know that the collection already exists).
1597 char *createfilec = createfile.getcstr();
1598 ofstream cfile_out (createfilec);
1599 delete createfilec;
1600 if (cfile_out) {
1601 cfile_out << "collection created\n";
1602 cfile_out.close();
1603 } else {
1604 message = "tmpfail";
1605 return;
1606 }
1607 }
1608}
1609
1610void collectoraction::gsdl_build (cgiargsclass &args, ostream &logout) {
1611
1612 outconvertclass text_t2ascii;
1613
1614 text_t tmpdir = filename_cat (gsdlhome, "tmp", args["bc1tmp"]);
1615 if (!directory_exists (tmpdir)) {
1616 message = "tmpfail";
1617 return;
1618 }
1619
1620 text_t &collection = args["bc1dirname"];
1621 if (collection.empty()) {
1622 message = "nocollection";
1623 return;
1624 }
1625
1626 // check for a .build file - if it exists then we've already built
1627 // the collection (or are in the process of building it)
1628 text_t buildfile = filename_cat (tmpdir, ".build");
1629 if (file_exists (buildfile)) {
1630 return;
1631 } else {
1632 // create the .build file (this file is just a place holder to let any future
1633 // pages know that we've already been here)
1634 char *buildfilec = buildfile.getcstr();
1635 ofstream bfile_out (buildfilec);
1636 delete buildfilec;
1637 if (bfile_out) {
1638 bfile_out << "collection building\n";
1639 bfile_out.close();
1640 } else {
1641 message = "tmpfail";
1642 return;
1643 }
1644 }
1645
1646 const recptconf &rcinfo = recpt->get_configinfo ();
1647
1648 // create the event header file if LogEvents, EmailEvents or
1649 // EmailUserEvents options are turned on.
1650 bool logevents =
1651 (rcinfo.LogEvents == CollectorEvents || rcinfo.LogEvents == AllEvents ||
1652 rcinfo.EmailEvents == CollectorEvents || rcinfo.EmailEvents == AllEvents ||
1653 rcinfo.EmailUserEvents);
1654 text_t ehead_file = filename_cat (tmpdir, "ehead.txt");
1655 if (logevents) {
1656 if (!create_event_header_file (ehead_file, args, logout)) {
1657 logevents = false;
1658 }
1659 }
1660
1661 // set up build options
1662 text_t options = "-make_writable -remove_import -out \"";
1663 options += filename_cat (tmpdir, collection + ".bld");
1664 options += "\" -collectdir \"" + get_collectdir (args) + "\"";
1665
1666 if (args["bc1esrce"] == 1) {
1667 // we're adding data to an existing collection
1668 options += " -save_archives -append";
1669 }
1670
1671 text_tarray inputvalues, inputtypes;
1672 splitchar (args["bc1input"].begin(), args["bc1input"].end(), ',', inputvalues);
1673 splitchar (args["bc1inputtype"].begin(), args["bc1inputtype"].end(), ',', inputtypes);
1674 int numvalues = inputvalues.size();
1675 int numtypes = inputtypes.size();
1676 for (int i = 0; i < numvalues; i++) {
1677 if (!inputvalues[i].empty()) {
1678 text_t type = "file://"; // default
1679 if (i < numtypes) type = inputtypes[i];
1680 options += " -download \"" +
1681 remove_trailing_slashes(type + format_url(decode_commas(inputvalues[i]))) + "\"";
1682 }
1683 }
1684
1685 if (logevents) {
1686 if (rcinfo.LogEvents == CollectorEvents || rcinfo.LogEvents == AllEvents)
1687 options += " -log_events";
1688 if (rcinfo.EmailEvents == CollectorEvents || rcinfo.EmailEvents == AllEvents) {
1689 options += " -mail_server " + rcinfo.MailServer;
1690 options += " -email_events " + rcinfo.maintainer;
1691 if (rcinfo.EmailUserEvents) options += "," + args["bc1contactemail"];
1692 } else if (rcinfo.EmailUserEvents) {
1693 options += " -mail_server " + rcinfo.MailServer;
1694 options += " -email_events " + args["bc1contactemail"];
1695 }
1696 options += " -event_header " + ehead_file;
1697 }
1698
1699 text_t optionfile = filename_cat (tmpdir, "build.opt");
1700 char *optionfilec = optionfile.getcstr();
1701 ofstream ofile_out (optionfilec);
1702 delete optionfilec;
1703 if (!ofile_out) {
1704 message = "tmpfail";
1705 return;
1706 }
1707 ofile_out << text_t2ascii << options << "\n";
1708 ofile_out.close();
1709
1710 // if we're altering an existing collection we need to kill off
1711 // the existing collection server - we do this for the local library
1712 // (and any other persistent version of the library) as the existing
1713 // gdbm file can't be deleted while the collection server holds it open
1714 if ((args["bc1econf"] == 1) || (args["bc1esrce"] == 1)) {
1715 remove_colservr (collection, logout);
1716 }
1717
1718 // set up the build command - build.bat has some issues with quoting
1719 // on win2k when gsdlhome contains spaces so we'll avoid using
1720 // "perl -S" here in favor of calling the "build" perl script explicitly
1721 text_t build_cmd = "perl \"" + filename_cat (gsdlhome, "bin", "script", "build");
1722 build_cmd += "\" -optionfile \"" + optionfile + "\" " + collection;
1723 // run build command in background (i.e. asynchronously)
1724 gsdl_system (build_cmd, false, logout);
1725}
1726
1727void collectoraction::gsdl_cancel_build (cgiargsclass &args, ostream &logout) {
1728 // I really wanted to do what this perl script does from within the library
1729 // c++ code. I ran into some problems though (like how do you write a portable
1730 // "rm -r" in c++?). One day I'll spend some time sorting it out ... maybe.
1731 text_t cancel_cmd = "perl -S cancel_build.pl -collectdir \"";
1732 cancel_cmd += filename_cat (gsdlhome, "tmp", args["bc1tmp"]) + "\" ";
1733 cancel_cmd += args["bc1dirname"];
1734 // To be on the safe side we'll make this a synchronous call
1735 // so that all tidying up is done before the user has a chance
1736 // to do anything else (like start rebuilding their collection).
1737 // This means that for a big collection where there's lots of
1738 // stuff to delete etc. it might take a while before the "build
1739 // cancelled" page appears.
1740 gsdl_system (cancel_cmd, true, logout);
1741}
1742
1743text_t collectoraction::get_collectdir (cgiargsclass &args) {
1744
1745 if ((args["bc1econf"] == 1) || (args["bc1esrce"] == 1)) {
1746 // we're adding to a collection in place
1747 return filename_cat(gsdlhome, "collect");
1748
1749 } else {
1750 return filename_cat (gsdlhome, "tmp", args["bc1tmp"]);
1751 }
1752}
1753
1754// checks to see if any of the plugins in pluginset occur in
1755// collections configuration file
1756bool collectoraction::uses_weird_plugin (const text_t &collection) {
1757
1758 text_tset pluginset;
1759 pluginset.insert ("HBPlug");
1760
1761 text_t cfgfile_content;
1762 text_t cfgfile_name = filename_cat (gsdlhome, "collect", collection, "etc", "collect.cfg");
1763 text_t pluginstr, pluginname;
1764
1765 if (read_file (cfgfile_name, cfgfile_content)) {
1766 text_t::const_iterator here = cfgfile_content.begin();
1767 text_t::const_iterator end = cfgfile_content.end();
1768 while (here != end) {
1769 here = findchar (here, end, 'p');
1770 if (here == end) break;
1771 if ((here+6 < end) && (substr (here, here+6) == "plugin")) {
1772 getdelimitstr (here+6, end, '\n', pluginstr);
1773 text_t::const_iterator hp = pluginstr.begin();
1774 text_t::const_iterator ep = pluginstr.end();
1775 bool found = false;
1776 // remove any leading whitespace, trailing options etc.
1777 while (hp != ep) {
1778 if (*hp == '\t' || *hp == ' ' || *hp == '\n') {
1779 if (found) break;
1780 } else {
1781 pluginname.push_back (*hp);
1782 found = true;
1783 }
1784 hp ++;
1785 }
1786 text_tset::const_iterator it = pluginset.find (pluginname);
1787 if (it != pluginset.end()) return true; // found matching plugin
1788 pluginname.clear();
1789 }
1790 here ++;
1791 }
1792 }
1793 return false;
1794}
1795
1796// create and initialize a new collection server and
1797// add it to the null protocol.
1798void collectoraction::create_colserver (const text_t &collection, ostream &logout) {
1799
1800 recptprotolistclass *protos = recpt->get_recptprotolist_ptr();
1801 recptprotolistclass::iterator rprotolist_here = protos->begin();
1802 recptprotolistclass::iterator rprotolist_end = protos->end();
1803 while (rprotolist_here != rprotolist_end) {
1804 comerror_t err = noError;
1805 if ((*rprotolist_here).p != NULL) {
1806 if ((*rprotolist_here).p->get_protocol_name (err) == "nullproto") {
1807 // create collection server and add it to nullproto
1808 (*rprotolist_here).p->add_collection (collection, recpt, gsdlhome, gsdlhome);
1809 // make sure gsdlhome is configured
1810 text_tarray tmp;
1811 tmp.push_back (gsdlhome);
1812 (*rprotolist_here).p->configure ("gsdlhome", tmp, err);
1813 // re-initialize the null protocol
1814 if (!(*rprotolist_here).p->init (err, logout)) {
1815 logout << "collectoraction::create_colserver: nullproto init failed\n";
1816 }
1817 return;
1818 }
1819 }
1820 rprotolist_here ++;
1821 }
1822
1823 logout << "collectoraction::create_colserver: no valid nullproto found\n";
1824}
1825
1826// delete a collection server from the null protocol
1827void collectoraction::remove_colservr (const text_t &collection, ostream &logout) {
1828
1829 recpt->uncache_collection (collection);
1830
1831 recptprotolistclass *protos = recpt->get_recptprotolist_ptr();
1832 recptprotolistclass::iterator rprotolist_here = protos->begin();
1833 recptprotolistclass::iterator rprotolist_end = protos->end();
1834 while (rprotolist_here != rprotolist_end) {
1835 comerror_t err = noError;
1836 if ((*rprotolist_here).p != NULL) {
1837 if ((*rprotolist_here).p->get_protocol_name (err) == "nullproto") {
1838 (*rprotolist_here).p->remove_collection (collection, logout);
1839 return;
1840 }
1841 }
1842 rprotolist_here ++;
1843 }
1844
1845 logout << "collectoraction::create_colserver: no valid nullproto found\n";
1846}
1847
1848bool collectoraction::create_event_header_file (const text_t &filename, cgiargsclass &args,
1849 ostream &logout) {
1850
1851 outconvertclass text_t2ascii;
1852 char *filenamec = filename.getcstr();
1853 ofstream eheadfile (filenamec);
1854 delete filenamec;
1855
1856 if (eheadfile) {
1857 eheadfile << text_t2ascii << get_event_header (args);
1858 eheadfile.close();
1859 return true;
1860 }
1861
1862 logout << text_t2ascii << "collectoraction::create_event_header ERROR: Couldn't create "
1863 << "Event Header file " << filename << ". Event logging disabled\n";
1864 return false;
1865}
1866
1867text_t collectoraction::get_event_header (cgiargsclass &args) {
1868 text_t header = "Greenstone Username: " + args["un"] + "\n";
1869 header += "Collection: " + args["bc1dirname"] + "\n";
1870 header += "Collection Creator: " + args["bc1contactemail"] + "\n";
1871 header += "GSDLHOME: " + gsdlhome + "\n";
1872 header += "Build Location: " + get_collectdir(args) + "\n";
1873
1874 return header;
1875}
1876
1877bool collectoraction::check_sources (cgiargsclass &args, ostream &logout) {
1878
1879 bool found = false;
1880
1881 text_tarray inputvalues;
1882 splitchar (args["bc1input"].begin(), args["bc1input"].end(), ',', inputvalues);
1883
1884 text_tarray inputtypes;
1885 splitchar (args["bc1inputtype"].begin(), args["bc1inputtype"].end(), ',', inputtypes);
1886
1887 int numvalues = inputvalues.size();
1888 int numtypes = inputtypes.size();
1889
1890 for (int i = 0; i < numvalues; i++) {
1891 text_t value = format_url(decode_commas(inputvalues[i]));
1892 text_t type = "file://"; // default
1893 if (!value.empty()) {
1894 found = true;
1895 if (i >= numtypes || inputtypes[i].empty()) {
1896 logout << "collectoraction::check_sources: WARNING type not set\n";
1897 } else {
1898 type = inputtypes[i];
1899 }
1900 if (type == "file://") {
1901 if (!file_exists(value) && !directory_exists(value)) {
1902 failedsources[decode_commas(inputvalues[i])] = "1";
1903 badsources = true;
1904 }
1905 } else if (type == "http://") {
1906 if (gsdl_system ("perl -S ping.pl -quiet http://" + value, true, logout)) {
1907 failedsources[decode_commas(inputvalues[i])] = "1";
1908 badsources = true;
1909 }
1910 } else if (type == "ftp://") {
1911 if (gsdl_system ("perl -S ping.pl -quiet ftp://" + value, true, logout)) {
1912 failedsources[decode_commas(inputvalues[i])] = "1";
1913 badsources = true;
1914 }
1915 }
1916 }
1917 }
1918
1919 // set badsources if there weren't any sources at all
1920 if (!found) badsources = true;
1921
1922 if (badsources) return false;
1923 return true;
1924}
1925
1926// format_url simply strips "http://", "ftp://", or "file://" off the
1927// beginning of url if they're there
1928text_t collectoraction::format_url (const text_t &url) {
1929 text_t::const_iterator begin = url.begin();
1930 text_t::const_iterator end = url.end();
1931
1932 if (url.size() >= 7) {
1933 text_t prefix = substr(begin, begin+7);
1934 if (prefix == "http://" || prefix == "file://") {
1935 return substr(begin+7, end);
1936 }
1937 }
1938 if (url.size() >= 6) {
1939 if (substr(begin, begin+6) == "ftp://") {
1940 return substr(begin+6, end);
1941 }
1942 }
1943 return url;
1944}
1945
1946text_t collectoraction::remove_trailing_slashes (text_t str) {
1947
1948 while (*(str.end()-1) == '\\') {
1949 str.pop_back();
1950 }
1951 return str;
1952}
Note: See TracBrowser for help on using the repository browser.