source: gsdl/trunk/runtime-src/src/recpt/collectoraction.cpp@ 19062

Last change on this file since 19062 was 19062, checked in by kjdon, 15 years ago

all gdbm files (key, users, history, argdb) now use gdb extension instead of db

  • 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 "argdb.h"
48#include "cgiutils.h"
49#include <stdio.h>
50#include <fcntl.h>
51#include <sys/stat.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.gdb 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"] = "all-collections-editor";
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.gdb");
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(collecthome, 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(collecthome, 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 , 432 );
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 , 432 );
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(collecthome, 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 database 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.