source: main/trunk/greenstone2/runtime-src/src/recpt/collectoraction.cpp@ 21877

Last change on this file since 21877 was 21877, checked in by kjdon, 14 years ago

added ifndefs around the define _XOPEN_SOURCE. Adding in gsdlconf to gsdl_modules_cfg.h meant that XOPEN_SOURCE was already defined on linux and giving a compile warning.

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