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

Last change on this file since 30465 was 28948, checked in by ak19, 10 years ago

Another security commit surrounding cgiargs. Collectionaction updated.

  • Property svn:keywords set to Author Date Id Revision
File size: 51.6 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 text_t websafe = encodeForHTMLAttr(inputvalues[i]);
874 rv += dm_safe(decode_commas(websafe));
875 }
876 rv += "\" size=50>";
877 if (badsources) {
878 if ((i < numvalues) && (!inputvalues[i].empty())) {
879 if (failedsources[decode_commas(inputvalues[i])] == "1") {
880 rv += "_iconcross_";
881 } else {
882 rv += "_icontick_";
883 }
884 } else {
885 rv += "_iconblank_";
886 }
887 }
888 if (i+1 == numboxes) {
889 if (!badsources) rv += "_iconblank_";
890 rv += "_imagemore_</nobr><br>";
891 } else {
892 rv += "</nobr><br>\n";
893 }
894 }
895
896 return rv;
897}
898
899// set the _cfgfile_ macro
900void collectoraction::set_cfgfile (displayclass &disp, cgiargsclass &args, ostream &logout) {
901
902 text_t &collection = args["bc1dirname"];
903 if (collection.empty()) {
904 message = "nocollection";
905 return;
906 }
907
908 // read in collect.cfg
909 text_t cfgfile = filename_cat(get_collectdir(args), collection, "etc", "collect.cfg");
910 char *cfgfilec = cfgfile.getcstr();
911
912#ifdef GSDL_USE_IOS_H
913 ifstream cfg_ifs (cfgfilec, ios::in | ios::nocreate);
914#else
915 ifstream cfg_ifs (cfgfilec, ios::in);
916#endif
917
918 if (cfg_ifs) {
919 // read in collect.cfg
920 text_t cfgtext;
921 char c;
922 cfg_ifs.get(c);
923 while (!cfg_ifs.eof ()) {
924 cfgtext.push_back(c);
925 cfg_ifs.get(c);
926 }
927 cfg_ifs.close();
928
929 // define it as a macro
930 disp.setmacro("cfgfile", "collector", dm_safe(cfgtext));
931
932 } else {
933 logout << "collectoraction::set_cfgfile: couldn't open configuration file ("
934 << cfgfilec << ") for reading\n";
935 message = "tmpfail";
936 }
937 delete []cfgfilec;
938}
939
940
941void collectoraction::define_internal_macros (displayclass &disp, cgiargsclass &args,
942 recptprotolistclass *protos, ostream &logout) {
943
944 // define_internal_macros sets the following macros:
945 // _collectorbar_
946 // _pagescriptextra_
947 // _fullnamemenu_ -- if displaying the "source data" page or the "changing existing
948 // collection" page
949 // _cfgfile_ -- if displaying the "configure collection" page
950 // _statusline_ -- if displaying the bildstatus page
951 // _header_ -- may be set for pages that require it
952 // _textfailmsg_ -- set to different messages depending on failcode returned
953 // by build script (if build fails)
954 // _faillog_ - set to last 6 lines of .bld file if build failed
955 // _gsdlhome_ - the gsdlhome path (dm_safe)
956 // _sourcelist_ -- "input source" text boxes
957 // _badsources_ -- will be set to "1" if we've come from the
958 // "source data" page and there's a problem
959 // with the input sources
960
961 text_t &collector_page = args["p"];
962 int esrce = args["bc1esrce"].getint();
963 int econf = args["bc1econf"].getint();
964
965 // set _pagescriptextra_ macro to _cpagescriptextra_
966 disp.setmacro ("pagescriptextra", "collector", "_" + encodeForHTML(collector_page) + "scriptextra_");
967
968 if (collector_page == "bildstatus" || collector_page == "bilddone" ||
969 collector_page == "bildfail" || collector_page == "bildframe1") {
970 disp.setmacro ("header", "collector", "_" + encodeForHTML(collector_page) + "header_");
971 }
972
973 // set the collectorbar macro
974 text_t collectorbar = "<table class=wizardbar border=0 cellspacing=4 cellpadding=0><tr>\n";
975
976 if (collector_page == "new") {
977 collectorbar += "<td>_icongreyarrow_</td>\n";
978 collectorbar += get_button (args,collector_page, "green", "info", true);
979 collectorbar += "<td>_icongreyarrow_</td>\n";
980 collectorbar += get_button (args,collector_page, "grey", "srce", false);
981 collectorbar += "<td>_icongreyarrow_</td>\n";
982 collectorbar += get_button (args,collector_page, "grey", "conf", false);
983 collectorbar += "<td>_icongreyarrow_</td>\n";
984 collectorbar += get_button (args,collector_page, "grey", "bild", false);
985 collectorbar += "<td>_icongreyarrow_</td>\n";
986 collectorbar += get_button (args,collector_page, "grey", "view", false);
987
988 } else if (collector_page == "info") {
989 collectorbar += "<td>_icongreyarrow_</td>\n";
990 collectorbar += get_button (args,collector_page, "yellow", "info", false);
991 collectorbar += "<td>_icongreyarrow_</td>\n";
992 collectorbar += get_button (args,collector_page, "green", "srce", true);
993 collectorbar += "<td>_icongreyarrow_</td>\n";
994 collectorbar += get_button (args,collector_page, "grey", "conf", false);
995 collectorbar += "<td>_icongreyarrow_</td>\n";
996 collectorbar += get_button (args,collector_page, "grey", "bild", false);
997 collectorbar += "<td>_icongreyarrow_</td>\n";
998 collectorbar += get_button (args,collector_page, "grey", "view", false);
999 collectorbar += "</tr><tr><td></td><td align=center>_icongreyuparrow_</td><td colspan=8></td>\n";
1000
1001 } else if (collector_page == "srce") {
1002 collectorbar += "<td>_icongreyarrow_</td>\n";
1003 if (esrce == 1) {
1004 // if we came from the "change an existing collection" page previous button(s)
1005 // are disabled
1006 collectorbar += get_button (args,collector_page, "grey", "info", false);
1007 } else {
1008 collectorbar += get_button (args,collector_page, "yellow", "info", true);
1009 }
1010 collectorbar += "<td>_icongreyarrow_</td>\n";
1011 collectorbar += get_button (args,collector_page, "yellow", "srce", false);
1012 collectorbar += "<td>_icongreyarrow_</td>\n";
1013 collectorbar += get_button (args,collector_page, "green", "conf", true);
1014 collectorbar += "<td>_icongreyarrow_</td>\n";
1015 collectorbar += get_button (args,collector_page, "green", "bild", true);
1016 collectorbar += "<td>_icongreyarrow_</td>\n";
1017 collectorbar += get_button (args,collector_page, "grey", "view", false);
1018 collectorbar += "</tr><tr><td colspan=3></td><td align=center>_icongreyuparrow_</td><td colspan=6></td>\n";
1019
1020 } else if (collector_page == "conf") {
1021 collectorbar += "<td>_icongreyarrow_</td>\n";
1022 // disable appropriate buttons if we came from "change an existing collection"
1023 // page
1024 if (esrce == 1 || econf == 1) {
1025 collectorbar += get_button (args,collector_page, "grey", "info", false);
1026 } else {
1027 collectorbar += get_button (args,collector_page, "yellow", "info", true);
1028 }
1029 collectorbar += "<td>_icongreyarrow_</td>\n";
1030 if (econf == 1) {
1031 collectorbar += get_button (args,collector_page, "grey", "srce", false);
1032 } else {
1033 collectorbar += get_button (args,collector_page, "yellow", "srce", true);
1034 }
1035 collectorbar += "<td>_icongreyarrow_</td>\n";
1036 collectorbar += get_button (args,collector_page, "yellow", "conf", false);
1037 collectorbar += "<td>_icongreyarrow_</td>\n";
1038 collectorbar += get_button (args,collector_page, "green", "bild", true);
1039 collectorbar += "<td>_icongreyarrow_</td>\n";
1040 collectorbar += get_button (args,collector_page, "grey", "view", false);
1041 collectorbar += "</tr><tr><td colspan=5></td><td align=center>_icongreyuparrow_</td><td colspan=4></td>\n";
1042
1043 } else if (collector_page == "bilddone") {
1044 collectorbar += "<td>_icongreyarrow_</td>\n";
1045 // all previous buttons grey after build was completed
1046 collectorbar += get_button (args,collector_page, "grey", "info", false);
1047 collectorbar += "<td>_icongreyarrow_</td>\n";
1048 collectorbar += get_button (args,collector_page, "grey", "srce", false);
1049 collectorbar += "<td>_icongreyarrow_</td>\n";
1050 collectorbar += get_button (args,collector_page, "grey", "conf", false);
1051 collectorbar += "<td>_icongreyarrow_</td>\n";
1052 collectorbar += get_button (args,collector_page, "yellow", "bild", false);
1053 collectorbar += "<td>_icongreyarrow_</td>\n";
1054 collectorbar += get_button (args,collector_page, "green", "view", true);
1055 collectorbar += "</tr><tr><td colspan=7></td><td align=center>_icongreyuparrow_</td><td colspan=2></td>\n";
1056
1057 } else if (collector_page == "bildcancel" || collector_page == "bildfail") {
1058 collectorbar += "<td>_icongreyarrow_</td>\n";
1059 // disable appropriate buttons if we came from "change an existing collection"
1060 // page
1061 if (esrce == 1 || econf == 1) {
1062 collectorbar += get_button (args,collector_page, "grey", "info", false);
1063 } else {
1064 collectorbar += get_button (args,collector_page, "yellow", "info", true);
1065 }
1066 collectorbar += "<td>_icongreyarrow_</td>\n";
1067 if (econf == 1) {
1068 collectorbar += get_button (args,collector_page, "grey", "srce", false);
1069 } else {
1070 collectorbar += get_button (args,collector_page, "yellow", "srce", true);
1071 }
1072 collectorbar += "<td>_icongreyarrow_</td>\n";
1073 collectorbar += get_button (args,collector_page, "yellow", "conf", true);
1074 collectorbar += "<td>_icongreyarrow_</td>\n";
1075 collectorbar += get_button (args,collector_page, "yellow", "bild", true);
1076 collectorbar += "<td>_icongreyarrow_</td>\n";
1077 collectorbar += get_button (args,collector_page, "grey", "view", false);
1078 }
1079
1080 collectorbar += "</tr></table>\n";
1081 disp.setmacro ("collectorbar", "collector", collectorbar);
1082
1083 if (collector_page == "bildfail") {
1084
1085 text_t textfailmsg = "_textfailmsg";
1086 textfailmsg.push_back(failcode);
1087 textfailmsg.push_back('_');
1088 disp.setmacro("textfailmsg", "collector", textfailmsg);
1089
1090 text_t bldlog = filename_cat(gsdlhome, "tmp", args["bc1tmp"], args["bc1dirname"] + ".bld");
1091 text_t rawlog = file_tail (bldlog, 6, 0);
1092 // we'll shove in some <br> tags where \n's occur
1093 text_t faillog;
1094 text_t::const_iterator here = rawlog.begin();
1095 text_t::const_iterator end = rawlog.end();
1096 while (here != end) {
1097 if (*here == '\n') faillog += "<br>";
1098 faillog.push_back (*here);
1099 ++here;
1100 }
1101 disp.setmacro ("faillog", "collector", dm_safe(faillog));
1102 }
1103
1104 if (collector_page == "srce" || collector_page == "existing")
1105 set_fullnamemenu (disp, args, protos, logout);
1106 if (collector_page == "conf")
1107 set_cfgfile (disp, args, logout);
1108 if (collector_page == "bildstatus")
1109 set_statusline (disp, args, logout);
1110 if (collector_page == "srce") {
1111 set_inputsourceboxes (disp, args, logout);
1112 }
1113
1114 disp.setmacro ("gsdlhome", "collector", dm_safe(gsdlhome));
1115}
1116
1117
1118bool collectoraction::do_action (cgiargsclass &args, recptprotolistclass * /*protos*/,
1119 browsermapclass * /*browsers*/, displayclass &disp,
1120 outconvertclass &outconvert, ostream &textout,
1121 ostream &logout) {
1122
1123 // make sure the collector is enabled
1124 if (disabled) {
1125 textout << outconvert
1126 << "<html>\n"
1127 << "<head>\n"
1128 << "<title>Collector disabled</title>\n"
1129 << "</head>\n"
1130 << "<body bgcolor=\"#ffffff\" text=\"#000000\" link=\"#006666\" "
1131 << "alink=\"#cc9900\" vlink=\"#666633\">\n"
1132 << "<h2>Facility disabled</h2>\n"
1133 << "Sorry, the Collector end-user collection building facility is currently disabled\n"
1134 << "\n</body>\n"
1135 << "</html>\n";
1136 return true;
1137 }
1138
1139 text_t &collector_page = args["p"];
1140 text_t &collection = args["bc1dirname"];
1141
1142 // make sure we have perl (we won't bother with this check for the
1143 // building status pages to avoid slowing things down unneccessarily)
1144 if (collector_page != "bildstatus" && collector_page != "bildframe1" && !perl_ok(logout)) {
1145 textout << outconvert
1146 << "<html>\n"
1147 << "<head>\n"
1148 << "<title>Perl not found</title>\n"
1149 << "</head>\n"
1150 << "<body bgcolor=\"#ffffff\" text=\"#000000\" link=\"#006666\" "
1151 << "alink=\"#cc9900\" vlink=\"#666633\">\n"
1152 << "<h2>Perl not found</h2>\n"
1153 << "Greenstone could not detect perl on this system. It is therefore not\n"
1154 << "possible to build a Greenstone collection, either from the Collector or the \n"
1155 << "command-line tools, or to use the Collector for any other task.\n"
1156 << "<p>Please refer to the Greenstone Installer's Guide for details on\n"
1157 << "installing perl on your system.\n"
1158 << "\n</body>\n"
1159 << "</html>\n";
1160 return true;
1161
1162 }
1163
1164 if (collector_page == "bild") {
1165 // do the work (download, import, build)
1166 gsdl_build (args, logout);
1167
1168 if (message.empty()) {
1169 // bild page is a frameset so we don't want headers and stuff
1170 textout << outconvert << disp << ("_collector:bildcontent_\n");
1171 }
1172 }
1173
1174 if (do_mkcol == true) {
1175 // execute mkcol.pl (do_mkcol is set from within check_cgiargs)
1176 gsdl_mkcol (args, logout);
1177 do_mkcol = false; // reset for fast-cgi
1178 }
1179
1180 if (args["bc1dodelete"] == "1") {
1181 // delete bcidirname collection
1182 if (collection_protected (collection)) {
1183 message = "delinvalid";
1184
1185 } else {
1186
1187 const recptconf &rcinfo = recpt->get_configinfo ();
1188 bool emailuserevents = rcinfo.EmailUserEvents;
1189
1190 // get collection maintainer email from collect.cfg before we
1191 // delete it
1192 text_t colmaintainer;
1193 text_t cfgfile = filename_cat(collecthome, collection, "etc", "collect.cfg");
1194 char *cfgfilec = cfgfile.getcstr();
1195 ifstream cfg_in (cfgfilec);
1196 delete []cfgfilec;
1197 if (cfg_in) {
1198 text_tarray cfgline;
1199 while (read_cfg_line(cfg_in, cfgline) >= 0) {
1200 if (cfgline.size () == 2 && cfgline[0] == "maintainer") {
1201 colmaintainer = cfgline[1];
1202 break;
1203 }
1204 }
1205 cfg_in.close();
1206 }
1207 if (colmaintainer.empty()) {
1208 logout << outconvert
1209 << "collectoraction::do_action WARNING: Collection being deleted ("
1210 << collection << ") has no maintainer address. EmailUserEvents "
1211 << "disabled\n";
1212 emailuserevents = false;
1213 }
1214
1215 // first we need to free up the collection's collection server
1216 // we must do this for the local library (and I guess when using
1217 // fastcgi too) as you can't delete the database file while it's
1218 // being kept open by the collection server
1219 remove_colservr (collection, logout);
1220
1221 text_t delete_cmd = "perl -S delcol.pl -f " + collection;
1222 int rv = gsdl_system (delete_cmd, true, logout);
1223 if (rv != 0) {
1224 // deletion failed -- permissions?
1225 message = "delpermission";
1226 } else {
1227 message = "delsuccess";
1228 }
1229
1230 // log the event
1231 if (rcinfo.LogEvents == CollectorEvents || rcinfo.LogEvents == AllEvents) {
1232
1233 text_t eventlog = filename_cat (gsdlhome, "etc", "events.txt");
1234 char *eventlogt = eventlog.getcstr();
1235 ofstream eventl (eventlogt, ios::app);
1236 delete []eventlogt;
1237
1238 if (eventl) {
1239 eventl << outconvert << "[Collector Event]\n"
1240 << "Date: " << get_date (true) << "\n"
1241 << "Greenstone Username: " << args["un"] << "\n"
1242 << "Collection: " << collection << "\n"
1243 << "Collection Maintainer: " << colmaintainer << "\n"
1244 << "GSDLHOME: " << gsdlhome << "\n";
1245
1246 if (message == "delsuccess") {
1247 eventl << outconvert
1248 << "The " << collection << " collection was successfully deleted\n\n";
1249 } else {
1250 eventl << outconvert
1251 << "Attempt to delete the " << collection << " collection failed\n\n";
1252 }
1253 eventl.close();
1254
1255 } else {
1256 logout << outconvert << "collectoraction::do_action ERROR: Couldn't open "
1257 << "event log file " << eventlog << " for appending during collection "
1258 << "deletion. LogEvents disabled\n";
1259 }
1260 }
1261
1262 if (rcinfo.EmailEvents == CollectorEvents || rcinfo.EmailEvents == AllEvents || emailuserevents) {
1263 // use sendmail.pl perl script to send email events
1264 text_t tmpmailfile = filename_cat (gsdlhome, "tmp", args["bc1tmp"], "event.txt");
1265 char *tmpmailfilec = tmpmailfile.getcstr();
1266 ofstream tmpfile (tmpmailfilec);
1267 delete []tmpmailfilec;
1268 if (tmpfile) {
1269 tmpfile << outconvert << "[Collector Event]\n"
1270 << "Date: " << get_date (true) << "\n"
1271 << "Greenstone Username: " << args["un"] << "\n"
1272 << "Collection: " << collection << "\n"
1273 << "Collection Maintainer: " << colmaintainer << "\n"
1274 << "GSDLHOME: " << gsdlhome << "\n";
1275 if (message == "delsuccess") {
1276 tmpfile << outconvert
1277 << "The " << collection << " collection was successfully deleted\n\n";
1278 } else {
1279 tmpfile << outconvert
1280 << "Attempt to delete the " << collection << " collection failed\n\n";
1281 }
1282 tmpfile.close();
1283 text_t to;
1284 if (rcinfo.EmailEvents == CollectorEvents || rcinfo.EmailEvents == AllEvents) to += rcinfo.maintainer;
1285 if (emailuserevents) {
1286 if (!to.empty()) to.push_back (',');
1287 to += colmaintainer;
1288 }
1289 text_t sendmail_cmd = "perl -S sendmail.pl -to \"" + to + "\" -from \"" + rcinfo.maintainer;
1290 sendmail_cmd += "\" -smtp \"" + rcinfo.MailServer + "\" -subject \"Greenstone Collector Event\"";
1291 sendmail_cmd += " -msgfile \"" + tmpmailfile + "\"";
1292
1293 gsdl_system (sendmail_cmd, false, logout);
1294
1295 } else {
1296 logout << outconvert << "collectoraction::do_action ERROR: Couldn't open "
1297 << "temporary event log file " << tmpmailfile << " during collection "
1298 << "deletion. EmailEvents and EmailUserEvents disabled\n";
1299 }
1300 }
1301 }
1302 }
1303
1304 if (collector_page == "bildcancel" || collector_page == "bildfail") {
1305 // cancel the build (we'll also use the cancel_build script to tidy
1306 // up if the build failed)
1307 gsdl_cancel_build (args, logout);
1308 }
1309
1310 if (collector_page == "expt") {
1311
1312 // export the collection - we'll do a synchronous system call to
1313 // exportcol.pl as that's the easiest way to do it. if it becomes a
1314 // problem that it's taking too long to export a large collection then
1315 // we may have to revisit this.
1316 text_t tmpfile = filename_cat (gsdlhome, "tmp", collection + "_export.txt");
1317 text_t export_cmd = "perl -S exportcol.pl -out \"" + tmpfile + "\" " + collection;
1318 gsdl_system (export_cmd, true, logout);
1319 if (file_exists (tmpfile)) {
1320 text_t returnline = file_tail (tmpfile, 1, 0);
1321 if (returnline.size() > 23 && (substr(returnline.begin(), returnline.begin()+23) == "exportcol.pl succeeded:")) {
1322 // success
1323 message = "exptsuccess";
1324 } else {
1325 message = "exptfail";
1326 }
1327 } else {
1328 message = "exptfail";
1329 }
1330 }
1331
1332 if (message.empty()) {
1333 if (collector_page != "bild") {
1334 // output page ("bild" page was already output above)
1335 textout << outconvert << disp << ("_collector:header_\n")
1336 << ("_collector:" + encodeForHTML(collector_page) + "content_\n")
1337 << ("_collector:footer_\n");
1338 }
1339 } else {
1340 // message was set somewhere (probably an error), output message page
1341 textout << outconvert << disp << ("_collector:header_\n")
1342 << ("_collector:" + message + "content_\n")
1343 << ("_collector:footer_\n");
1344 message.clear();
1345 }
1346 return true;
1347}
1348
1349void collectoraction::gsdl_mkcol (cgiargsclass &args, ostream &logout) {
1350
1351 text_t tmpdir = filename_cat (gsdlhome, "tmp", args["bc1tmp"]);
1352 if (!directory_exists (tmpdir)) {
1353 message = "tmpfail";
1354 cerr << "WE CANNOT CREATE THE DIRECTORY!!! " << endl;
1355 return;
1356 }
1357
1358 text_t &collection = args["bc1dirname"];
1359 if (collection.empty()) {
1360 message = "nocollection";
1361 return;
1362 }
1363
1364 // check for a .create file - if it exists then we've already created the collection
1365 text_t createfile = filename_cat (tmpdir, ".create");
1366 if (file_exists (createfile)) {
1367 return;
1368 }
1369
1370 // set up options
1371 text_t options = "-quiet -creator \"" + args["bc1contactemail"] + "\"";
1372 options += " -title \"" + args["bc1fullname"] + "\"";
1373 options += " -about \"" + carriage_replace (args["bc1aboutdesc"] + "_collectorextra_", 0) + "\"";
1374 options += " -collectdir \"" + remove_trailing_slashes(tmpdir) + "\" ";
1375
1376 text_t optionfile = filename_cat (tmpdir, "mkcol.opt");
1377 char *optionfilec = optionfile.getcstr();
1378 ofstream ofile_out (optionfilec);
1379 delete []optionfilec;
1380 if (!ofile_out) {
1381 message = "tmpfail";
1382 return;
1383 }
1384 outconvertclass text_t2ascii;
1385 ofile_out << text_t2ascii << options << "\n";
1386 ofile_out.close();
1387
1388 // run mkcol.pl
1389 text_t mkcol_cmd = "perl -S mkcol.pl -optionfile \"" + optionfile;
1390 mkcol_cmd += "\" " + collection;
1391
1392
1393 gsdl_system (mkcol_cmd, true, logout);
1394
1395 // make sure it went ok
1396 text_t cfgfile = filename_cat (tmpdir, collection, "etc", "collect.cfg");
1397 if (!file_writable (cfgfile)) {
1398 message = "mkcolfail";
1399 } else {
1400 // create the .create file (this file is just a place holder to let any future
1401 // pages know that the collection already exists).
1402 char *createfilec = createfile.getcstr();
1403 ofstream cfile_out (createfilec);
1404 delete []createfilec;
1405 if (cfile_out) {
1406 cfile_out << "collection created\n";
1407 cfile_out.close();
1408 } else {
1409 message = "tmpfail";
1410 return;
1411 }
1412 }
1413}
1414
1415
1416bool collectoraction::check_sources (cgiargsclass &args, ostream &logout) {
1417
1418 bool found = false;
1419
1420 text_tarray inputvalues;
1421 splitchar (args["bc1input"].begin(), args["bc1input"].end(), ',', inputvalues);
1422
1423 text_tarray inputtypes;
1424 splitchar (args["bc1inputtype"].begin(), args["bc1inputtype"].end(), ',', inputtypes);
1425
1426 int numvalues = inputvalues.size();
1427 int numtypes = inputtypes.size();
1428
1429 for (int i = 0; i < numvalues; ++i) {
1430 text_t value = format_url(decode_commas(inputvalues[i]));
1431 text_t type = "file://"; // default
1432 if (!value.empty()) {
1433 found = true;
1434 if (i >= numtypes || inputtypes[i].empty()) {
1435 logout << "collectoraction::check_sources: WARNING type not set\n";
1436 } else {
1437 type = inputtypes[i];
1438 }
1439 if (type == "file://") {
1440 if (!file_exists(value) && !directory_exists(value)) {
1441 failedsources[decode_commas(inputvalues[i])] = "1";
1442 badsources = true;
1443 }
1444 } else if (type == "http://") {
1445 if (gsdl_system ("perl -S ping.pl -quiet http://" + value, true, logout)) {
1446 failedsources[decode_commas(inputvalues[i])] = "1";
1447 badsources = true;
1448 }
1449 } else if (type == "ftp://") {
1450 if (gsdl_system ("perl -S ping.pl -quiet ftp://" + value, true, logout)) {
1451 failedsources[decode_commas(inputvalues[i])] = "1";
1452 badsources = true;
1453 }
1454 }
1455 }
1456 }
1457
1458 // set badsources if there weren't any sources at all
1459 if (!found) badsources = true;
1460
1461 if (badsources) return false;
1462 return true;
1463}
1464
1465text_t collectoraction::get_button(cgiargsclass &args, const text_t &thispage,
1466 const text_t &color,
1467 const text_t &type, bool enabled)
1468{
1469
1470 if ((color != "green" && color != "grey" && color != "yellow") ||
1471 (type != "info" && type != "srce" && type != "conf" && type != "bild" && type != "view"))
1472 return g_EmptyText;
1473
1474 text_t href = "_http"+type+"_";
1475 text_t target = "";
1476
1477 if (thispage == "info" || thispage == "srce" || thispage == "conf" ||
1478 thispage == "bildcancel" || thispage == "bildfail") {
1479 // call the check submit macro instead of linking directly to the page
1480 href="\"javascript:check_submit('"+type+"');\"";
1481 } else if (type == "view") {
1482 // view button is special case as it needs a target=_top
1483 target = " target=_top";
1484 }
1485
1486 text_t tdclass = "wizardbar"+color;
1487 if (enabled) {
1488 // link to the appropriate page
1489 return "<td class="+tdclass+"><a href="+href+target+">_text"+type+"_</a></td>";
1490 }
1491 else {
1492 // just display the text
1493 return "<td class="+tdclass+">_text"+type+"_</td>";
1494 }
1495}
1496
1497#endif //GSDL_USE_COLLECTOR_ACTION
Note: See TracBrowser for help on using the repository browser.