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

Last change on this file since 11998 was 11998, checked in by davidb, 16 years ago

First cut at 'The Depositor' -- Greenstone support for institutional
repositories

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