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

Last change on this file since 11152 was 9931, checked in by kjdon, 19 years ago

getting collectionmeta from teh colinforesponse now, not using a get_info via the protocol. this means that collmeta will be read from the config file not from the database - it will not require rebuilding for changes to take effect.

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