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

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