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

Last change on this file since 2908 was 2908, checked in by sjboddie, 22 years ago

Added bin\windows\perl\bin to path on Windows as perl may now be packaged
up with Greenstone distributions.

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