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

Last change on this file since 1437 was 1437, checked in by sjboddie, 24 years ago

* empty log message *

  • Property svn:keywords set to Author Date Id Revision
File size: 31.9 KB
Line 
1/**********************************************************************
2 *
3 * collectoraction.cpp --
4 * Copyright (C) 2000 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26// note that the collectoraction relies on having direct access to a
27// collections configuration file. this breaks the separation between
28// receptionist and collection server and so is not suitable (at least
29// in its current form) for use when collection servers are separate
30// from the receptionist (e.g. when using the CORBA protocol).
31
32#include "collectoraction.h"
33#include "OIDtools.h"
34#include "fileutil.h"
35#include "cfgread.h"
36#include "gsdltools.h"
37
38#if !defined (__WIN32__)
39#include <sys/utsname.h>
40#include <unistd.h>
41#endif
42
43collectoraction::collectoraction () {
44
45 recpt = NULL;
46 do_mkcol = false;
47 clone_failed = false;
48
49 cgiarginfo arg_ainfo;
50 arg_ainfo.shortname = "a";
51 arg_ainfo.longname = "action";
52 arg_ainfo.multiplechar = true;
53 arg_ainfo.defaultstatus = cgiarginfo::weak;
54 arg_ainfo.argdefault = "collector";
55 arg_ainfo.savedarginfo = cgiarginfo::must;
56 argsinfo.addarginfo (NULL, arg_ainfo);
57
58 arg_ainfo.shortname = "cp";
59 arg_ainfo.longname = "collector page";
60 arg_ainfo.multiplechar = true;
61 arg_ainfo.defaultstatus = cgiarginfo::weak;
62 arg_ainfo.argdefault = "intro";
63 arg_ainfo.savedarginfo = cgiarginfo::must;
64 argsinfo.addarginfo (NULL, arg_ainfo);
65
66 arg_ainfo.shortname = "bc1fullname";
67 arg_ainfo.longname = "collector specific";
68 arg_ainfo.multiplechar = true;
69 arg_ainfo.defaultstatus = cgiarginfo::weak;
70 arg_ainfo.argdefault = "";
71 arg_ainfo.savedarginfo = cgiarginfo::must;
72 argsinfo.addarginfo (NULL, arg_ainfo);
73
74 arg_ainfo.shortname = "bc1dirname";
75 arg_ainfo.longname = "collector specific";
76 arg_ainfo.multiplechar = true;
77 arg_ainfo.defaultstatus = cgiarginfo::weak;
78 arg_ainfo.argdefault = "";
79 arg_ainfo.savedarginfo = cgiarginfo::must;
80 argsinfo.addarginfo (NULL, arg_ainfo);
81
82 arg_ainfo.shortname = "bc1contactemail";
83 arg_ainfo.longname = "collector specific";
84 arg_ainfo.multiplechar = true;
85 arg_ainfo.defaultstatus = cgiarginfo::weak;
86 arg_ainfo.argdefault = "";
87 arg_ainfo.savedarginfo = cgiarginfo::must;
88 argsinfo.addarginfo (NULL, arg_ainfo);
89
90 arg_ainfo.shortname = "bc1aboutdesc";
91 arg_ainfo.longname = "collector specific";
92 arg_ainfo.multiplechar = true;
93 arg_ainfo.defaultstatus = cgiarginfo::weak;
94 arg_ainfo.argdefault = "";
95 arg_ainfo.savedarginfo = cgiarginfo::must;
96 argsinfo.addarginfo (NULL, arg_ainfo);
97
98 arg_ainfo.shortname = "bc1clone";
99 arg_ainfo.longname = "collector specific";
100 arg_ainfo.multiplechar = false;
101 arg_ainfo.defaultstatus = cgiarginfo::weak;
102 arg_ainfo.argdefault = "0";
103 arg_ainfo.savedarginfo = cgiarginfo::must;
104 argsinfo.addarginfo (NULL, arg_ainfo);
105
106 arg_ainfo.shortname = "bc1clonecol";
107 arg_ainfo.longname = "collector specific";
108 arg_ainfo.multiplechar = true;
109 arg_ainfo.defaultstatus = cgiarginfo::weak;
110 arg_ainfo.argdefault = "";
111 arg_ainfo.savedarginfo = cgiarginfo::must;
112 argsinfo.addarginfo (NULL, arg_ainfo);
113
114 // set when cloning option has changed
115 arg_ainfo.shortname = "bc1clonechanged";
116 arg_ainfo.longname = "collector specific";
117 arg_ainfo.multiplechar = false;
118 arg_ainfo.defaultstatus = cgiarginfo::weak;
119 arg_ainfo.argdefault = "0";
120 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
121 argsinfo.addarginfo (NULL, arg_ainfo);
122
123 arg_ainfo.shortname = "bc1inputdir1";
124 arg_ainfo.longname = "collector specific";
125 arg_ainfo.multiplechar = true;
126 arg_ainfo.defaultstatus = cgiarginfo::weak;
127 arg_ainfo.argdefault = "";
128 arg_ainfo.savedarginfo = cgiarginfo::must;
129 argsinfo.addarginfo (NULL, arg_ainfo);
130
131 arg_ainfo.shortname = "bc1inputdir2";
132 arg_ainfo.longname = "collector specific";
133 arg_ainfo.multiplechar = true;
134 arg_ainfo.defaultstatus = cgiarginfo::weak;
135 arg_ainfo.argdefault = "";
136 arg_ainfo.savedarginfo = cgiarginfo::must;
137 argsinfo.addarginfo (NULL, arg_ainfo);
138
139 arg_ainfo.shortname = "bc1inputdir3";
140 arg_ainfo.longname = "collector specific";
141 arg_ainfo.multiplechar = true;
142 arg_ainfo.defaultstatus = cgiarginfo::weak;
143 arg_ainfo.argdefault = "";
144 arg_ainfo.savedarginfo = cgiarginfo::must;
145 argsinfo.addarginfo (NULL, arg_ainfo);
146
147 arg_ainfo.shortname = "bc1inputdir4";
148 arg_ainfo.longname = "collector specific";
149 arg_ainfo.multiplechar = true;
150 arg_ainfo.defaultstatus = cgiarginfo::weak;
151 arg_ainfo.argdefault = "";
152 arg_ainfo.savedarginfo = cgiarginfo::must;
153 argsinfo.addarginfo (NULL, arg_ainfo);
154
155 // only set when one of the fields was changed in
156 // the "collection info" page
157 arg_ainfo.shortname = "bc1infochanged";
158 arg_ainfo.longname = "collector specific";
159 arg_ainfo.multiplechar = false;
160 arg_ainfo.defaultstatus = cgiarginfo::weak;
161 arg_ainfo.argdefault = "0";
162 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
163 argsinfo.addarginfo (NULL, arg_ainfo);
164
165 // only set when cfg file is altered from within
166 // "configure collection" page
167 arg_ainfo.shortname = "bc1cfgchanged";
168 arg_ainfo.longname = "collector specific";
169 arg_ainfo.multiplechar = 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 arg_ainfo.shortname = "bc1dodelete";
176 arg_ainfo.longname = "collector specific";
177 arg_ainfo.multiplechar = false;
178 arg_ainfo.defaultstatus = cgiarginfo::weak;
179 arg_ainfo.argdefault = "0";
180 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
181 argsinfo.addarginfo (NULL, arg_ainfo);
182
183 // will be set if we arrived at the "configure collection" page
184 // via the "changing an existing collection" page
185 arg_ainfo.shortname = "bc1econf";
186 arg_ainfo.longname = "collector specific";
187 arg_ainfo.multiplechar = false;
188 arg_ainfo.defaultstatus = cgiarginfo::weak;
189 arg_ainfo.argdefault = "0";
190 arg_ainfo.savedarginfo = cgiarginfo::must;
191 argsinfo.addarginfo (NULL, arg_ainfo);
192
193 // will be set if we arrived at the "source data" page
194 // via the "changing an existing collection" page
195 arg_ainfo.shortname = "bc1esrce";
196 arg_ainfo.longname = "collector specific";
197 arg_ainfo.multiplechar = false;
198 arg_ainfo.defaultstatus = cgiarginfo::weak;
199 arg_ainfo.argdefault = "0";
200 arg_ainfo.savedarginfo = cgiarginfo::must;
201 argsinfo.addarginfo (NULL, arg_ainfo);
202}
203
204collectoraction::~collectoraction () {
205 delete gsdlosc;
206 delete gsdlhomec;
207}
208
209bool collectoraction::init (ostream & /*logout*/) {
210
211 // set up GSDLOS and GSDLHOME environment variables
212 text_t gsdlos;
213#if defined (__WIN32__)
214 gsdlos = "windows";
215#else
216 utsname *buf = new utsname();
217 int i = uname (buf);
218 if (i == -1) gsdlos = "linux"; // uname failed
219 else gsdlos.setcstr (buf->sysname);
220 delete buf;
221 lc (gsdlos);
222#endif
223
224 gsdlos = "GSDLOS=" + gsdlos;
225 text_t setgsdlhome = "GSDLHOME=" + gsdlhome;
226
227 // these will be cleaned up in the destructor
228 gsdlosc = gsdlos.getcstr();
229 gsdlhomec = setgsdlhome.getcstr();
230
231 putenv (gsdlosc);
232 putenv (gsdlhomec);
233
234 return true;
235}
236
237bool collectoraction::check_cgiargs (cgiargsinfoclass &/*argsinfo*/, cgiargsclass &args,
238 ostream &logout) {
239
240 if (args["cp"] != "intro") {
241 // authenticate the user if authentication is available
242 args["uan"] = 1;
243 args["ug"] = "colbuilder";
244 }
245
246 if (args["bc1infochanged"] == "1") {
247
248 if (args["bc1dirname"].empty()) {
249 // we've just come from the "collection information" page for the
250 // first time so we'll need to create the collection with mkcol.pl
251 // and set up bc1dirname - we do this part here instead of in do_action
252 // because the bc1dirname argument must be set to its new value before
253 // the compressedoptions macros are set.
254 args["bc1dirname"] = get_directory_name (args["bc1fullname"]);
255 do_mkcol = true;
256 } else {
257 // "collection information" has been changed after collection was made
258 // so we'll need to update the cfg file.
259 update_cfgfile_partial (args, logout);
260 }
261 }
262
263 if (args["bc1cfgchanged"] == "1") {
264 // configuration file has been changed from the "configure collection"
265 // page. we need to update the file on disk and catch bc1 arguments up
266 // with changes.
267 update_cfgfile_complete (args, logout);
268 }
269
270 if (args["bc1clonechanged"] == "1") {
271 // cloning option has been changed on "source data" page. if it was turned
272 // on we want to create a new collect.cfg file using the bc1clonecol cfg file
273 // as a model (we'll save the old file as collect.cfg.org). if cloning was
274 // turned off we'll revert to using the collect.cfg.org file (which will need
275 // updating in case the bc1 arguments have been altered since cloning was
276 // turned on).
277 update_cfgfile_clone (args, logout);
278 }
279
280 return true;
281}
282
283void collectoraction::update_cfgfile_clone (cgiargsclass &args, ostream &logout) {
284
285 text_t cfgfile = filename_cat(gsdlhome, "collect", args["bc1dirname"], "etc", "collect.cfg");
286 text_t cfgfile_org = cfgfile + ".org";
287
288 if (args["bc1clone"] == "1") {
289 // cloning was turned on
290
291 text_t cfgfile_clone = filename_cat(gsdlhome, "collect", args["bc1clonecol"], "etc", "collect.cfg");
292 if (file_exists (cfgfile_clone)) {
293 // if .org file doesn't exist already create it
294 if (!file_exists (cfgfile_org)) {
295 file_copy (cfgfile, cfgfile_org);
296 }
297 // copy clone collections cfg file to new collection
298 file_copy (cfgfile_clone, cfgfile);
299 // update the new cfg file
300 update_cfgfile_partial (args, logout);
301
302 } else {
303 // can't clone non-existant collection
304 clone_failed = true;
305 }
306
307 } else {
308 // cloning has been turned off having been on at some point. the .org file
309 // should exist, if it doesn't we'll bail out and leave the user with the
310 // cloned copy
311 if (file_exists (cfgfile_org)) {
312 // copy original back again and update it with any recent changes
313 file_copy (cfgfile_org, cfgfile);
314 update_cfgfile_partial (args, logout);
315 }
316 }
317}
318
319// update configuration file on disk to match bc1 arguments
320void collectoraction::update_cfgfile_partial (cgiargsclass &args, ostream &logout) {
321
322 text_t cfgfile = filename_cat(gsdlhome, "collect", args["bc1dirname"], "etc", "collect.cfg");
323 char *cfgfilec = cfgfile.getcstr();
324
325 vector<text_tarray> cfgarray;
326
327 // read in cfg file
328 ifstream cfg_in (cfgfilec);
329 if (cfg_in) {
330 text_tarray cfgline;
331 while (read_cfg_line(cfg_in, cfgline) >= 0) {
332 if (cfgline.size () >= 2) {
333 if (cfgline[0] == "creator" || cfgline[0] == "maintainer") {
334 cfgline[1] = args["bc1contactemail"];
335 } else if (cfgline[0] == "collectionmeta") {
336 if (cfgline[1] == "collectionname") {
337 cfgline[2] = args["bc1fullname"];
338 } else if (cfgline[1] == "collectionextra") {
339 cfgline[2] = carriage_replace (args["bc1aboutdesc"], 0);
340 }
341 }
342 }
343 cfgarray.push_back (cfgline);
344 }
345 cfg_in.close();
346
347 // now write cfg file back out
348#ifdef __WIN32__
349 ofstream cfg_out (cfgfilec, ios::binary);
350#else
351 ofstream cfg_out (cfgfilec);
352#endif
353 if (cfg_out) {
354 // lock the file
355 int fd = GSDL_GET_FILEDESC(cfg_out);
356 int lock_val = 1;
357 GSDL_LOCK_FILE (fd);
358 if (lock_val != 0) {
359 logout << "Error: Couldn't lock file " << cfgfilec << "\n";
360 cfg_out.close();
361
362 } else {
363
364 vector<text_tarray>::const_iterator this_line = cfgarray.begin();
365 vector<text_tarray>::const_iterator end_line = cfgarray.end();
366 while (this_line != end_line) {
367 write_cfg_line (cfg_out, *this_line);
368 this_line ++;
369 }
370 GSDL_UNLOCK_FILE (fd);
371 cfg_out.close();
372 }
373
374 } else {
375 logout << "collectoraction::update_cfgfile_partial: unable to open "
376 << cfgfilec << " for output\n";
377 }
378
379 } else {
380 logout << "collectoraction::update_cfgfile_partial: unable to open "
381 << cfgfilec << " for input\n";
382 }
383 delete cfgfilec;
384}
385
386// replace configuration file on disk with that in the bc1cfgfile argument and
387// catch other bc1 arguments up with those the new cfgfile contains
388void collectoraction::update_cfgfile_complete (cgiargsclass &args, ostream &logout) {
389
390 text_t cfgfile = filename_cat(gsdlhome, "collect", args["bc1dirname"], "etc", "collect.cfg");
391 char *cfgfilec = cfgfile.getcstr();
392#ifdef __WIN32__
393 ofstream cfg_out (cfgfilec, ios::binary);
394#else
395 ofstream cfg_out (cfgfilec);
396#endif
397
398 if (cfg_out) {
399 // lock the file
400 int fd = GSDL_GET_FILEDESC(cfg_out);
401 int lock_val = 1;
402 GSDL_LOCK_FILE (fd);
403 if (lock_val != 0) {
404 logout << "Error: Couldn't lock file " << cfgfilec << "\n";
405 cfg_out.close();
406
407 } else {
408
409 outconvertclass text_t2ascii;
410 cfg_out << text_t2ascii << args["bc1cfgfile"];
411 GSDL_UNLOCK_FILE (fd);
412 cfg_out.close();
413
414 // now that we've written the file we'll read it back again and
415 // update our bc1 arguments
416 ifstream cfg_in (cfgfilec);
417 if (cfg_in) {
418 text_tarray cfgline;
419 while (read_cfg_line(cfg_in, cfgline) >= 0) {
420 if (cfgline.size () >= 2) {
421 if (cfgline[0] == "creator") {
422 args["bc1contactemail"] = cfgline[1];
423 } else if (cfgline[0] == "collectionmeta") {
424 if (cfgline[1] == "collectionname") {
425 args["bc1fullname"] = cfgline[2];
426 } else if (cfgline[1] == "collectionextra") {
427 args["bc1aboutdesc"] = carriage_replace (cfgline[2], 1);
428 }
429 }
430 }
431 }
432 cfg_in.close();
433 } else {
434 logout << "collectoraction::update_cfgfile_complete: unable to open "
435 << cfgfilec << " for input\n";
436 }
437 }
438 } else {
439 logout << "collectoraction::update_cfgfile_complete: unable to open "
440 << cfgfilec << " for output\n";
441 }
442 delete cfgfilec;
443}
444
445void collectoraction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
446 response_t &response,text_t &response_data,
447 ostream &/*logout*/) {
448 response = content;
449 response_data = "text/html";
450}
451
452// return html for buttons used in collector bar
453// color may be "green", "grey", or "yellow"
454// type may be:
455// "info" --> "collection information" button
456// "srce" --> "source data" button
457// "conf" --> "configure collection" button
458// "bild" --> "build collection" button
459// "view" --> "view collection" button
460// if enabled is true button will be flashy rollover type and
461// will be hyperlinked
462
463text_t collectoraction::get_button (const text_t &thispage, const text_t &color,
464 const text_t &type, bool enabled) {
465
466 if ((color != "green" && color != "grey" && color != "yellow") ||
467 (type != "info" && type != "srce" && type != "conf" && type != "bild" && type != "view"))
468 return "";
469
470 text_t prefix = "gc";
471 if (color == "grey") prefix = "nc";
472 else if (color == "yellow") prefix = "yc";
473
474 text_t httpicon = "httpicon" + prefix + type;
475
476 if (enabled) {
477 text_t gsmacro = "_gsimage_";
478 if (thispage == "info" || thispage == "srce" || thispage == "conf") {
479 gsmacro = "_gsjimage_";
480 }
481 return "<td>" + gsmacro + "(_collector:http" + type + "_,_collector:" + httpicon +
482 "of_,_collector:" + httpicon + "on_," + type + ",_collector:text" + type + "_)</td>\n";
483 } else {
484 return "<td>_icon" + prefix + type + "of_</td>\n";
485 }
486}
487
488// set the _fullnamemenu_ macro
489void collectoraction::set_fullnamemenu (displayclass &disp, cgiargsclass &args,
490 recptprotolistclass *protos, ostream &logout) {
491
492 if (recpt == NULL) {
493 logout << "ERROR (collectoraction::set_fullnamemenu): This action does not contain\n"
494 << " information about any receptionists. The method set_receptionist was\n"
495 << " probably not called from the module which instantiated this action.\n";
496 return;
497 }
498
499 text_t &current_page = args["cp"];
500 text_t currentname = args["bc1dirname"];
501 if (current_page == "srce") currentname = args["bc1clonecol"];
502
503 text_tarray dirnames;
504 text_tarray fullnames;
505 vector<bool> write_protected;
506 int selected_index = 0;
507 int index = 0;
508
509 recptprotolistclass::iterator rprotolist_here = protos->begin();
510 recptprotolistclass::iterator rprotolist_end = protos->end();
511 while (rprotolist_here != rprotolist_end) {
512 if ((*rprotolist_here).p != NULL) {
513
514 // don't include z39.50 collection
515 if ((*rprotolist_here).p->get_protocol_name () == "z3950proto") {
516 rprotolist_here ++;
517 continue;
518 }
519
520 text_tarray collist;
521 comerror_t err;
522 (*rprotolist_here).p->get_collection_list (collist, err, logout);
523 if (err == noError) {
524 text_tarray::iterator collist_here = collist.begin();
525 text_tarray::iterator collist_end = collist.end();
526 FilterResponse_t response;
527 text_tset metadata;
528 metadata.insert ("collectionname");
529 while (collist_here != collist_end) {
530 ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr ((*rprotolist_here).p, *collist_here, logout);
531 if (cinfo != NULL) {
532 text_t collectionname = *collist_here;
533 if (!cinfo->collectionmeta["collectionname"].empty()) {
534 // get collection name from the collection cfg file
535 collectionname = cinfo->collectionmeta["collectionname"];
536 } else if (get_info ("collection", *collist_here, metadata, false,
537 (*rprotolist_here).p, response, logout)) {
538 // get collection name from gdbm file
539 collectionname = response.docInfo[0].metadata["collectionname"].values[0];
540 }
541 dirnames.push_back(*collist_here);
542 fullnames.push_back(collectionname);
543 // check to see if the "collection" is writable
544 if (collection_protected (*collist_here)) write_protected.push_back(true);
545 else write_protected.push_back(false);
546 if (*collist_here == currentname) selected_index = index;
547
548 index ++;
549 }
550 collist_here ++;
551 }
552 }
553 }
554 rprotolist_here ++;
555 }
556
557 bool have_one = false;
558 text_t fullnamemenu = "<select name=\"bc1dirname\">\n";
559 if (current_page == "srce") fullnamemenu = "<select name=\"bc1clonecol\">\n";
560 for (int i = 0; i < index; i ++) {
561 // don't want write protected collections in list on "change existing
562 // collection" page
563 if (write_protected[i] && current_page == "existing") continue;
564 have_one = true;
565 fullnamemenu += "<option value=\"" + dirnames[i] + "\"";
566 if (i == selected_index) fullnamemenu += " selected";
567 fullnamemenu.push_back ('>');
568 fullnamemenu += fullnames[i];
569 if (write_protected[i]) fullnamemenu += " <b>(write protected)</b>";
570 }
571 fullnamemenu += "</select>\n";
572 if (have_one) disp.setmacro ("fullnamemenu", "collector", fullnamemenu);
573}
574
575// set the _cfgfile_ macro
576void collectoraction::set_cfgfile (displayclass &disp, const text_t &dirname, ostream &logout) {
577
578 // read in collect.cfg
579 text_t cfgfile = filename_cat(gsdlhome, "collect", dirname, "etc", "collect.cfg");
580 char *cfgfilec = cfgfile.getcstr();
581
582#ifdef GSDL_USE_IOS_H
583 ifstream cfg_ifs (cfgfilec, ios::in | ios::nocreate);
584#else
585 ifstream cfg_ifs (cfgfilec, ios::in);
586#endif
587
588 if (cfg_ifs) {
589 // read in collect.cfg
590 text_t cfgtext;
591 char c;
592 cfg_ifs.get(c);
593 while (!cfg_ifs.eof ()) {
594 if (c=='\\') cfgtext.push_back('\\');
595 cfgtext.push_back(c);
596 cfg_ifs.get(c);
597 }
598 cfg_ifs.close();
599
600 // define it as a macro
601 disp.setmacro("cfgfile","collector",cfgtext);
602
603 } else {
604 logout << "collectoraction::set_cfgfile: couldn't open configuration file ("
605 << cfgfilec << ") for reading\n";
606 }
607 delete cfgfilec;
608}
609
610// set the _statusline_ macro
611void collectoraction::set_statusline (displayclass &disp, const text_t &collection, ostream &logout) {
612
613 // the build command creates .bld.download, .bld.import, and .bld.build files (in that
614 // order) and deletes them (also in that order) when each stage is complete. the .bld
615 // file is the concatenation of all these files.
616 text_t bld_file = filename_cat (gsdlhome, "tmp", collection + ".bld");
617 text_t statusline;
618
619 if (file_exists (bld_file + ".download")) {
620 statusline = "Downloading files ...<br>";
621 statusline += file_tail (bld_file + ".download");
622 } else if (file_exists (bld_file + ".import")) {
623 statusline = "Importing collection ...<br>";
624 statusline += file_tail (bld_file + ".import");
625 } else if (file_exists (bld_file + ".build")) {
626 statusline = "Building collection ...";
627 statusline += file_tail (bld_file + ".build");
628 } else {
629 statusline += file_tail (bld_file);
630 }
631
632 disp.setmacro ("statusline", "collector", statusline);
633
634}
635
636void collectoraction::define_internal_macros (displayclass &disp, cgiargsclass &args,
637 recptprotolistclass *protos, ostream &logout) {
638
639 // define_internal_macros sets the following macros:
640 // _collectorbar_
641 // _pagescriptextra_
642 // _fullnamemenu_ -- if displaying the "source data" page or the "changing existing
643 // collection" page
644 // _cfgfile_ -- if displaying the "configure collection" page
645 // _statusline_ -- if displaying the bildstatus page
646 // _pagebanner_ -- may be set to _collector:plainbanner_ for some pages
647
648 text_t &collector_page = args["cp"];
649 int esrce = args["bc1esrce"].getint();
650 int econf = args["bc1econf"].getint();
651
652 // set _pagescriptextra_ macro to _cpagescriptextra_
653 disp.setmacro ("pagescriptextra", "collector", "_" + collector_page + "scriptextra_");
654
655 // set _pagebanner_ for those pages that don't want a fancy header (e.g. those
656 // displayed in frames
657 if (collector_page == "bildstatus") {
658 disp.setmacro ("pagebanner", "collector", "_plainbanner_");
659 }
660
661 // set the collectorbar macro
662 text_t collectorbar = "<table border=0 cellspacing=4 cellpadding=0><tr>\n";
663
664 if (collector_page == "new") {
665 collectorbar += get_button (collector_page, "green", "info", true);
666 collectorbar += "<td>_icongreyarrow_</td>\n";
667 collectorbar += get_button (collector_page, "grey", "srce", false);
668 collectorbar += "<td>_icongreyarrow_</td>\n";
669 collectorbar += get_button (collector_page, "grey", "conf", false);
670 collectorbar += "<td>_icongreyarrow_</td>\n";
671 collectorbar += get_button (collector_page, "grey", "bild", false);
672 collectorbar += "<td>_icongreyarrow_</td>\n";
673 collectorbar += get_button (collector_page, "grey", "view", false);
674
675 } else if (collector_page == "info") {
676 collectorbar += get_button (collector_page, "yellow", "info", false);
677 collectorbar += "<td>_icongreyarrow_</td>\n";
678 collectorbar += get_button (collector_page, "green", "srce", true);
679 collectorbar += "<td>_icongreyarrow_</td>\n";
680 collectorbar += get_button (collector_page, "grey", "conf", false);
681 collectorbar += "<td>_icongreyarrow_</td>\n";
682 collectorbar += get_button (collector_page, "grey", "bild", false);
683 collectorbar += "<td>_icongreyarrow_</td>\n";
684 collectorbar += get_button (collector_page, "grey", "view", false);
685 collectorbar += "</tr><tr><td align=center>_icongreyuparrow_</td><td colspan=8></td>\n";
686
687 } else if (collector_page == "srce") {
688 if (esrce == 1) {
689 // if we came from the "change an existing collection" page previous button(s)
690 // are disabled
691 collectorbar += get_button (collector_page, "grey", "info", false);
692 } else {
693 collectorbar += get_button (collector_page, "yellow", "info", true);
694 }
695 collectorbar += "<td>_icongreyarrow_</td>\n";
696 collectorbar += get_button (collector_page, "yellow", "srce", false);
697 collectorbar += "<td>_icongreyarrow_</td>\n";
698 collectorbar += get_button (collector_page, "green", "conf", true);
699 collectorbar += "<td>_icongreyarrow_</td>\n";
700 collectorbar += get_button (collector_page, "grey", "bild", false);
701 collectorbar += "<td>_icongreyarrow_</td>\n";
702 collectorbar += get_button (collector_page, "grey", "view", false);
703 collectorbar += "</tr><tr><td colspan=2></td><td align=center>_icongreyuparrow_</td><td colspan=6></td>\n";
704
705 } else if (collector_page == "conf") {
706 // disable appropriate buttons if we came from "change an existing collection"
707 // page
708 if (esrce == 1 || econf == 1) {
709 collectorbar += get_button (collector_page, "grey", "info", false);
710 } else {
711 collectorbar += get_button (collector_page, "yellow", "info", true);
712 }
713 collectorbar += "<td>_icongreyarrow_</td>\n";
714 if (econf == 1) {
715 collectorbar += get_button (collector_page, "grey", "srce", false);
716 } else {
717 collectorbar += get_button (collector_page, "yellow", "srce", true);
718 }
719 collectorbar += "<td>_icongreyarrow_</td>\n";
720 collectorbar += get_button (collector_page, "yellow", "conf", false);
721 collectorbar += "<td>_icongreyarrow_</td>\n";
722 collectorbar += get_button (collector_page, "green", "bild", true);
723 collectorbar += "<td>_icongreyarrow_</td>\n";
724 collectorbar += get_button (collector_page, "grey", "view", false);
725 collectorbar += "</tr><tr><td colspan=4></td><td align=center>_icongreyuparrow_</td><td colspan=4></td>\n";
726
727 } else if (collector_page == "bild") {
728
729
730 }
731
732 collectorbar += "</tr></table>\n";
733 disp.setmacro ("collectorbar", "collector", collectorbar);
734
735 if (collector_page == "srce" || collector_page == "existing")
736 set_fullnamemenu (disp, args, protos, logout);
737 if (collector_page == "conf")
738 set_cfgfile (disp, args["bc1dirname"], logout);
739 if (collector_page == "bildstatus")
740 set_statusline (disp, args["bc1dirname"], logout);
741}
742
743bool collectoraction::do_action (cgiargsclass &args, recptprotolistclass * /*protos*/,
744 browsermapclass * /*browsers*/, displayclass &disp,
745 outconvertclass &outconvert, ostream &textout,
746 ostream &logout) {
747
748 text_t &collector_page = args["cp"];
749 text_t &collection = args["bc1dirname"];
750
751 if (collector_page == "bild") {
752 // do the work (download, import, build)
753 text_t tmpdir = filename_cat (gsdlhome, "tmp", collection + ".bld");
754
755 text_t build_cmd = "perl " + filename_cat (gsdlhome, "bin", "script", "build");
756 build_cmd += " -append -remove_import";
757 build_cmd += " -out \"" + tmpdir + "\"";
758 if (!args["bc1inputdir1"].empty()) {
759 build_cmd += " -download \"" + args["bc1inputdir1"] + "\"";
760 }
761 if (!args["bc1inputdir2"].empty()) {
762 build_cmd += " -download \"" + args["bc1inputdir2"] + "\"";
763 }
764 if (!args["bc1inputdir3"].empty()) {
765 build_cmd += " -download \"" + args["bc1inputdir3"] + "\"";
766 }
767 if (!args["bc1inputdir4"].empty()) {
768 build_cmd += " -download \"" + args["bc1inputdir4"] + "\"";
769 }
770 build_cmd.push_back (' ');
771 build_cmd += collection;
772
773#if !defined (__WIN32__)
774 // run in background on unix systems
775 build_cmd += " &";
776#endif
777 char *build_cmdc = build_cmd.getcstr();
778#if defined (__WIN32__)
779 gsdl_system (build_cmdc, logout);
780#else
781 system (build_cmdc);
782#endif
783 delete build_cmdc;
784
785 // don't want header and stuff for build page as it uses frames
786 textout << outconvert << disp << ("_collector:bildcontent_\n");
787
788 } else {
789
790 // not bild page
791
792 text_t message;
793
794 if (do_mkcol) {
795 // execute mkcol.pl (do_mkcol is set from within check_cgiargs)
796 text_t mkcol_cmd = "perl ";
797 mkcol_cmd += filename_cat (gsdlhome, "bin", "script", "mkcol.pl");
798 mkcol_cmd += " -creator \"" + args["bc1contactemail"] + "\"";
799 mkcol_cmd += " -title \"" + args["bc1fullname"] + "\"";
800 mkcol_cmd += " -about \"" + carriage_replace (args["bc1aboutdesc"], 0) + "\" ";
801 mkcol_cmd += collection;
802 char *mkcol_cmdc = mkcol_cmd.getcstr();
803 system (mkcol_cmdc);
804 delete mkcol_cmdc;
805
806 // make sure it went ok
807 text_t cfgfile = filename_cat (gsdlhome, "collect", collection,
808 "etc", "collect.cfg");
809 if (!file_writable (cfgfile)) message = "mkcolfail";
810 do_mkcol = false; // reset for fast-cgi
811 }
812
813 if (args["bc1dodelete"] == "1") {
814 // delete bcidirname collection
815 if (collection_protected (collection)) {
816 message = "delinvalid";
817
818 } else {
819
820 text_t delete_cmd = "perl " + filename_cat (gsdlhome, "bin", "script", "delcol.pl");
821 delete_cmd += " -f " + collection;
822 char *delete_cmdc = delete_cmd.getcstr();
823 int rv = system (delete_cmdc);
824 delete delete_cmdc;
825 if (rv != 0) {
826 // deletion failed -- permissions?
827 message = "delpermission";
828 } else {
829 message = "delsuccess";
830 }
831 }
832 }
833
834 if (clone_failed) {
835 // clone_failed is set from check_cgiargs if an attempt was made
836 // to clone an invalid collection
837 message = "clonefail";
838 clone_failed = false;
839 }
840
841 if (message.empty()) {
842 textout << outconvert << disp << ("_collector:header_\n")
843 << ("_collector:" + collector_page + "content_\n")
844 << ("_collector:footer_\n");
845 } else {
846 textout << outconvert << disp << ("_collector:header_\n")
847 << ("_collector:" + message + "content_\n")
848 << ("_collector:footer_\n");
849 }
850 }
851 return true;
852}
853
854// if sw = 0 replace all carriage returns in intext with the string "\n"
855// else replace all occurances of "\n" with a carriage return
856text_t collectoraction::carriage_replace (const text_t &intext, int sw) {
857
858 text_t outtext;
859 text_t::const_iterator here = intext.begin();
860 text_t::const_iterator end = intext.end();
861 while (here != end) {
862 if (sw == 0) {
863 if (*here == '\n') {
864 if ((here+1) != end && *(here+1) == '\r') here ++;
865 outtext += "\\n";
866 } else if (*here == '\r') {
867 if ((here+1) != end && *(here+1) == '\n') here ++;
868 outtext += "\\n";
869 } else {
870 outtext.push_back (*here);
871 }
872 } else if (*here == '\\' && (here+1) != end && *(here+1) == 'n') {
873 outtext.push_back ('\n');
874 here ++;
875 } else {
876 outtext.push_back (*here);
877 }
878 here ++;
879 }
880 return outtext;
881}
882
883// create a short directory name from fullname
884text_t collectoraction::get_directory_name (const text_t &fullname) {
885
886 text_t shortname;
887 if (fullname.empty()) {
888 shortname = "coll";
889
890 } else {
891
892 // first make all lowercase and remove any dodgy characters
893 // (i.e. anything not [a-z]
894 text_t::const_iterator here = fullname.begin();
895 text_t::const_iterator end = fullname.end();
896 while (here != end) {
897 if ((*here >= 'A' && *here <= 'Z') || (*here >= 'a' && *here <= 'z') ||
898 (*here == ' ')) {
899 if (*here >= 'A' && *here <= 'Z') shortname.push_back (*here+32);
900 else if (*here == ' ') {
901 while ((*(here+1)) == ' ') here ++;
902 shortname.push_back (*here);
903 } else shortname.push_back (*here);
904 }
905 here ++;
906 }
907
908 text_tarray words;
909 splitchar (shortname.begin(), shortname.end(), ' ', words);
910 int num_words = words.size();
911
912 if (num_words == 0) {
913 shortname = "coll";
914
915 } else {
916
917 shortname.clear();
918 int use_words = (num_words <= 6) ? num_words : 6;
919 int substr_len = 6 / use_words;
920
921 for (int i = 0; i < use_words; i++) {
922 if (words[i].size() < substr_len) shortname += words[i];
923 else shortname += substr (words[i].begin(), words[i].begin()+substr_len);
924 }
925 }
926 }
927
928 // check to see if shortname is unique
929 text_t fulldirname = filename_cat (gsdlhome, "collect", shortname);
930 if (directory_exists (fulldirname)) {
931 int version = 0;
932 text_t newname;
933 do {
934 version ++;
935 newname = shortname;
936 newname.push_back ('v');
937 newname.appendint (version);
938 fulldirname = filename_cat (gsdlhome, "collect", newname);
939 } while (directory_exists (fulldirname));
940
941 shortname = newname;
942 }
943
944 return shortname;
945}
946
947// tests if collection is write protected (currently just checks if
948// collect.cfg file is writable
949bool collectoraction::collection_protected (const text_t &collection) {
950 text_t cfgfile = filename_cat(gsdlhome, "collect", collection, "etc", "collect.cfg");
951 if (file_writable(cfgfile)) return false;
952 return true;
953}
Note: See TracBrowser for help on using the repository browser.