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

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

fixed a bug in the recently added argdb stuff that caused problems when
attempting to make changes to an existing collection from within the
collector interface

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