source: main/trunk/greenstone2/runtime-src/src/recpt/depositoraction.cpp@ 28899

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

Third commit for security, for ensuring cgiargs macros are websafe. This time all the changes to the runtime action classes.

  • Property svn:keywords set to Author Date Id Revision
File size: 32.8 KB
Line 
1/**********************************************************************
2 *
3 * depositoraction.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_DEPOSITOR_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 "depositoraction.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
53#include <stdio.h>
54//#include <strings.h> // seems to be needed for gcc 2.95, but not particularly happy it
55#include <fcntl.h>
56#include <time.h>
57
58#if !defined (__WIN32__)
59#include <sys/utsname.h>
60#include <unistd.h>
61#endif
62
63#include <new>
64//#include <string>
65#include <vector>
66#include <stdexcept>
67#include <iostream>
68//#include <cstdlib>
69
70depositoraction::depositoraction ()
71 : wizardaction()
72{
73 macro_prefix = "di1"; //deposit item
74 lastpage = 0;
75
76 cgiarginfo arg_ainfo;
77 arg_ainfo.shortname = "a";
78 arg_ainfo.longname = "action";
79 arg_ainfo.multiplechar = true;
80 arg_ainfo.multiplevalue = false;
81 arg_ainfo.defaultstatus = cgiarginfo::weak;
82 arg_ainfo.argdefault = "depositor";
83 arg_ainfo.savedarginfo = cgiarginfo::must;
84 argsinfo.addarginfo (NULL, arg_ainfo);
85
86 arg_ainfo.shortname = "p";
87 arg_ainfo.longname = "page";
88 arg_ainfo.multiplechar = true;
89 arg_ainfo.multiplevalue = false;
90 arg_ainfo.defaultstatus = cgiarginfo::weak;
91 arg_ainfo.argdefault = "select";
92 arg_ainfo.savedarginfo = cgiarginfo::must;
93 argsinfo.addarginfo (NULL, arg_ainfo);
94
95 //furthest page that has been visited
96 arg_ainfo.shortname = "di1lastpage";
97 arg_ainfo.longname = "depositor specific";
98 arg_ainfo.multiplechar = true;
99 arg_ainfo.multiplevalue = false;
100 arg_ainfo.defaultstatus = cgiarginfo::weak;
101 arg_ainfo.argdefault = "0";
102 arg_ainfo.savedarginfo = cgiarginfo::must;
103 argsinfo.addarginfo (NULL, arg_ainfo);
104
105 // the fileupload info that cgiwrapper produces - we parse the fileupload_t
106 // and set di1userfile, di1userfilesize
107 arg_ainfo.shortname = "di1userfileinfo";
108 arg_ainfo.longname = "depositor specific";
109 arg_ainfo.fileupload = true;
110 arg_ainfo.multiplevalue = false;
111 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
112 argsinfo.addarginfo (NULL, arg_ainfo);
113
114 // essential: reset fileupload to default as we are not setting
115 // it for each arg
116 arg_ainfo.fileupload = false;
117
118 //the name of the file to be added
119 arg_ainfo.shortname = "di1userfile";
120 arg_ainfo.longname = "depositor specific";
121 arg_ainfo.multiplechar = true;
122 arg_ainfo.multiplevalue = false;
123 arg_ainfo.defaultstatus = cgiarginfo::weak;
124 arg_ainfo.argdefault = g_EmptyText;
125 arg_ainfo.savedarginfo = cgiarginfo::must;
126 argsinfo.addarginfo (NULL, arg_ainfo);
127
128 //the file size
129 arg_ainfo.shortname = "di1userfilesize";
130 arg_ainfo.longname = "depositor specific";
131 arg_ainfo.multiplechar = true;
132 arg_ainfo.multiplevalue = false;
133 arg_ainfo.defaultstatus = cgiarginfo::weak;
134 arg_ainfo.argdefault = "0";
135 arg_ainfo.savedarginfo = cgiarginfo::must;
136 argsinfo.addarginfo (NULL, arg_ainfo);
137
138 //the file timestamp
139 arg_ainfo.shortname = "di1timestamp";
140 arg_ainfo.longname = "depositor specific";
141 arg_ainfo.multiplechar = true;
142 arg_ainfo.multiplevalue = false;
143 arg_ainfo.defaultstatus = cgiarginfo::weak;
144 arg_ainfo.argdefault = "0";
145 arg_ainfo.savedarginfo = cgiarginfo::must;
146 argsinfo.addarginfo (NULL, arg_ainfo);
147
148 // temporary directory name for this collector
149 // session
150 arg_ainfo.shortname = "di1tmp";
151 arg_ainfo.longname = "depositor specific";
152 arg_ainfo.multiplechar = true;
153 arg_ainfo.multiplevalue = false;
154 arg_ainfo.defaultstatus = cgiarginfo::weak;
155 arg_ainfo.argdefault = g_EmptyText;
156 arg_ainfo.savedarginfo = cgiarginfo::must;
157 argsinfo.addarginfo (NULL, arg_ainfo);
158
159// arg_ainfo.shortname = "di1fullname";
160// arg_ainfo.longname = "depositor specific";
161// arg_ainfo.multiplechar = true;
162// arg_ainfo.multiplevalue = false;
163// arg_ainfo.defaultstatus = cgiarginfo::weak;
164// arg_ainfo.argdefault = g_EmptyText;
165// arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
166// argsinfo.addarginfo (NULL, arg_ainfo);
167
168 arg_ainfo.shortname = "di1dirname";
169 arg_ainfo.longname = "depositor specific";
170 arg_ainfo.multiplechar = true;
171 arg_ainfo.multiplevalue = false;
172 arg_ainfo.defaultstatus = cgiarginfo::weak;
173 arg_ainfo.argdefault = g_EmptyText;
174 arg_ainfo.savedarginfo = cgiarginfo::must;
175 argsinfo.addarginfo (NULL, arg_ainfo);
176
177 arg_ainfo.shortname = "di1contactemail";
178 arg_ainfo.longname = "depositor specific";
179 arg_ainfo.multiplechar = true;
180 arg_ainfo.multiplevalue = false;
181 arg_ainfo.defaultstatus = cgiarginfo::weak;
182 arg_ainfo.argdefault = g_EmptyText;
183 arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
184 argsinfo.addarginfo (NULL, arg_ainfo);
185
186// arg_ainfo.shortname = "di1clone";
187// arg_ainfo.longname = "depositor specific";
188// arg_ainfo.multiplechar = false;
189// arg_ainfo.multiplevalue = false;
190// arg_ainfo.defaultstatus = cgiarginfo::weak;
191// arg_ainfo.argdefault = "0";
192// arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
193// argsinfo.addarginfo (NULL, arg_ainfo);
194
195// arg_ainfo.shortname = "di1clonecol";
196// arg_ainfo.longname = "depositor specific";
197// arg_ainfo.multiplechar = true;
198// arg_ainfo.multiplevalue = false;
199// arg_ainfo.defaultstatus = cgiarginfo::weak;
200// arg_ainfo.argdefault = g_EmptyText;
201// arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
202// argsinfo.addarginfo (NULL, arg_ainfo);
203
204// arg_ainfo.shortname = "cfgfile";
205// arg_ainfo.longname = "configuration file contents";
206// arg_ainfo.multiplechar = true;
207// arg_ainfo.multiplevalue = false;
208// arg_ainfo.defaultstatus = cgiarginfo::weak;
209// arg_ainfo.argdefault = g_EmptyText;
210// arg_ainfo.savedarginfo = cgiarginfo::mustnot;
211// argsinfo.addarginfo (NULL, arg_ainfo);
212
213// // will be set if we arrived at the "configure collection" page
214// // via the "changing an existing collection" page
215// arg_ainfo.shortname = "di1econf";
216// arg_ainfo.longname = "depositor specific";
217// arg_ainfo.multiplechar = false;
218// arg_ainfo.multiplevalue = false;
219// arg_ainfo.defaultstatus = cgiarginfo::weak;
220// arg_ainfo.argdefault = "0";
221// arg_ainfo.savedarginfo = cgiarginfo::must;
222// argsinfo.addarginfo (NULL, arg_ainfo);
223
224 // wizard uses this to see if we are working with an existing collection:
225 // set the default to 1
226 arg_ainfo.shortname = "di1esrce";
227 arg_ainfo.longname = "depositor specific";
228 arg_ainfo.multiplechar = false;
229 arg_ainfo.multiplevalue = false;
230 arg_ainfo.defaultstatus = cgiarginfo::weak;
231 arg_ainfo.argdefault = "1";
232 arg_ainfo.savedarginfo = cgiarginfo::must;
233 argsinfo.addarginfo (NULL, arg_ainfo);
234
235// arg_ainfo.shortname = "di1input";
236// arg_ainfo.longname = "depositor 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// //we don't need this in the depositor
245// arg_ainfo.shortname = "di1inputtype";
246// arg_ainfo.longname = "depositor specific";
247// arg_ainfo.multiplechar = true;
248// arg_ainfo.multiplevalue = true;
249// arg_ainfo.defaultstatus = cgiarginfo::weak;
250// arg_ainfo.argdefault = g_EmptyText;
251// arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
252// argsinfo.addarginfo (NULL, arg_ainfo);
253
254}
255
256depositoraction::~depositoraction () {
257}
258
259
260bool depositoraction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, recptprotolistclass * protos, ostream &logout) {
261
262 wizardaction::check_cgiargs(argsinfo,args,protos,logout);
263
264 text_t &current_page = args["p"];
265
266 // note that the "bildstatus" and "bildframe1" pages don't actually do anything
267 // functional so we don't need to worry about authenticating them (it's the
268 // underlying "bild" page that does the building (and creates the frameset))
269 // This helps us overcome a bit of a problem we have with multiple pages trying
270 // to read from the key.gdb database at the same time.
271
272 //right now, anyone can do anything until it's time to build
273
274 // Used to check current page was "select", now changed to "step1".
275 // (i.e. one page later). This is needed so users that belong to
276 // specific collection-edit groups (e.g. demo-collection-editor) are able
277 // to log in successfully.
278 //
279
280 if (current_page == "step1") {
281 //authenticate the user if authentication is available
282 args["uan"] = 1;
283 args["ug"] = "all-collections-editor," + args["c"] + "-collection-editor";
284 }
285
286
287 //Check to see if a file was specified
288 //if so, upload it and set the di1userfile, di1userfilesize, and
289 //di1timestamp args.
290 //every time a new file is specified, a new timestamped folder is
291 //created.
292
293 // This doesn't create a problem but is inefficient (wasted space)
294 // Consider recoding at some point in the future.
295
296 fileupload_t *fileupload = args.getargfile("di1userfileinfo");
297
298 if (fileupload != NULL) {
299
300 if (!(*fileupload).tmp_name.empty() && file_exists((*fileupload).tmp_name)) {
301 // create the timestamp
302 time_t timestamp = time(NULL);
303 text_t timestamp_str(timestamp);
304
305 args["di1timestamp"] = timestamp_str;
306
307 // set filename and size from the fileupload struct
308 args["di1userfilesize"] = (*fileupload).size;
309 args["di1userfile"] = (*fileupload).name;
310 // copy the file into its temporary location
311 text_t tmpdir = filename_cat(gsdlhome,"tmp",args["di1tmp"],timestamp_str);
312 bool tflag = mk_dir(tmpdir);
313 text_t tmpfile = filename_cat(tmpdir,(*fileupload).name);
314 if (!file_copy((*fileupload).tmp_name, tmpfile)) {
315 cerr << "Depositor error: cannot save uploaded fileto "<<tmpfile<<endl;
316 } else {
317 cerr << "Depositor: saved uploaded file to "<<tmpfile<<endl;
318 }
319 }
320 }
321
322 if (current_page == "select") {
323
324 //make sure the last page arg is re-set to zero
325 //since a new collection is being chosen
326 args["di1lastpage"] = "0";
327
328 // assign (and create) a temporary directory This will create a new
329 // tbuild directory every time the user goes back to select a new
330 // collection. It causes no problems except wasted space. Should be
331 // addressed in the future
332 if (assign_tmpname (args, logout)==false) {
333 // there was an error creating the tmp dir
334 message="tmpfail";
335 return true; // true because we could still parse the arguments
336 }
337
338 // clean up any old builds left laying about in the tmp directory
339 // (note that it's possible this could take some time if there's a huge
340 // partially built collecton laying about so we'll make it an asynchronous
341 // system call)
342 gsdl_system ("perl -S cleantmp.pl", false, logout);
343
344 }
345
346 if (current_page == "bildstatus" || current_page == "bildcancel") {
347 // if .final file exists then build has finished
348 text_t fbld = filename_cat (gsdlhome, "tmp", args[macro_prefix + "tmp"], args[macro_prefix + "dirname"] + ".bld.final");
349 if (file_exists (fbld)) {
350 char *fbldc = fbld.getcstr();
351 ifstream fbld_in (fbldc);
352 if (fbld_in) {
353 failcode = fbld_in.get();
354 fbld_in.close();
355 if (failcode == '0') {
356 // success - we need to create and configure a collection server for the
357 // newly built collection (for fastcgi and local library where
358 // initialization isn't going to be redone when the user clicks the
359 // "view your new collection" button
360 create_colserver (args[macro_prefix + "dirname"], logout);
361 current_page = "bilddone";
362 }
363 else current_page = "bildfail";
364 } else {
365 // assume build failed (we shouldn't get here though ... right?)
366 current_page = "bildfail";
367 }
368 delete []fbldc;
369 }
370 }
371
372 //is it a step page?
373 text_t::const_iterator here = current_page.begin();
374 text_t::const_iterator end = current_page.end();
375 text_t stepstring = substr(here,here+4);
376
377 //if so, increment the step count
378 //this should not be going up more than one at a time.
379 if(stepstring == "step") {
380 text_t currpage_textt = substr(here+4,here+5);
381 int currpage = currpage_textt.getint();
382
383 text_t lastpage_textt = args["di1lastpage"];
384 int lastpage = lastpage_textt.getint();
385 if (currpage > lastpage) {
386 lastpage++;
387 text_t lastpage_textt(lastpage);
388 args["di1lastpage"] = lastpage_textt;
389 }
390
391 // create cached metadata values
392 text_t cached_metadata_values = "";
393 cgiargsclass::const_iterator args_here = args.begin();
394 cgiargsclass::const_iterator args_end = args.end();
395 while (args_here != args_end) {
396 text_t args_name = (*args_here).first;
397 int prefix_len = macro_prefix.size();
398 int args_name_len = args_name.size();
399
400 if(args_name_len >= prefix_len+3) { // Only now can we substring args_name by prefix_len+3
401 text_t args_prefix;
402 if(args_name_len == prefix_len+3) {
403 args_prefix = args_name;
404 } else { // >, so substring
405 args_prefix = substr(args_name.begin(),args_name.begin()+prefix_len+3);
406 }
407
408 if (args_prefix == (macro_prefix+"md.")) {
409 text_t args_val = args[args_name];
410 text_t args_suffix = substr(args_name.begin()+prefix_len+3,args_name.end());
411
412 text_tarray mdvalues;
413 splitchar (args_val.begin(), args_val.end(), ',', mdvalues);
414 int numvalues = mdvalues.size();
415
416 for (int i = 0; i < numvalues; ++i) {
417 if (!mdvalues[i].empty()) {
418 decode_cgi_arg(mdvalues[i]);
419
420 if (cached_metadata_values == "") {
421 cached_metadata_values = "var CachedMDValues = new Array(\\{";
422 } else {
423 cached_metadata_values += ",";
424 }
425
426 cached_metadata_values += "\"" + args_name + "\":\"" + args_val + "\"";
427 }
428 }
429 }
430 }
431 ++args_here;
432 }
433
434 if (cached_metadata_values != "") {
435 cached_metadata_values += "\\});";
436 args["cachedMDValues"] = cached_metadata_values;
437 }
438 }
439 return true;
440}
441
442
443void depositoraction::define_internal_macros (displayclass &disp, cgiargsclass &args,
444 recptprotolistclass *protos, ostream &logout) {
445
446 // define_internal_macros sets some/all of the following macros (depending
447 // on cgiargs):
448 //
449 // _pagescriptextra_
450 // _header_
451 // _depositorbar_
452 // _textfailmsg_
453 // _di1userfile_
454 // _di1userfilesize_
455
456 text_t &depositor_page = args["p"];
457
458 // set _pagescriptextra_ macro to _cpagescriptextra_
459 disp.setmacro ("pagescriptextra", "depositor", "_" + depositor_page + "scriptextra_");
460
461 if (depositor_page == "bildstatus" || depositor_page == "bilddone" ||
462 depositor_page == "bildfail" || depositor_page == "bildframe1" ||
463 depositor_page == "select") {
464 disp.setmacro ("header", "depositor", "_" + depositor_page + "header_");
465 }
466
467 if (depositor_page == "bildstatus") {
468 set_statusline (disp, args, logout);
469 }
470
471 if (depositor_page == "select") {
472 set_fullnamemenu (disp, args, protos, logout);
473 }
474
475 //how many pages in collection?
476 //we need a _depositorbar_ for each
477
478 text_t numsteps_str;
479 disp.expandstring("depositor", "_numsteps_", numsteps_str);
480 int numsteps = numsteps_str.getint();
481
482 //is the page a step page?
483
484 text_t::const_iterator here = depositor_page.begin();
485 text_t::const_iterator end = depositor_page.end();
486 text_t stepstring = substr(here,here+4);
487
488 if((stepstring) == "step" || (depositor_page == "depositonly") ) {
489 disp.setmacro("di1userfile","depositor",args["di1userfile"]);
490 disp.setmacro("di1userfilesize","depositor",args["di1userfilesize"]);
491 }
492
493 //set up the depositor bar
494 text_t depositorbar = "<table class=wizardbar border=0 cellspacing=4 cellpadding=0><tr>\n";
495
496 if(stepstring == "step") {
497 // check configured metadata elements
498 if (args["metadataconf"] == "var DepositorMDFields = new Array();" || args["metadataconf"] == "") {
499 text_t cfgfile_name = filename_cat (collecthome, args[macro_prefix + "dirname"], "etc", "collect.cfg");
500 text_t cfgfile_content;
501 text_t metadata_str;
502
503 if (read_file (cfgfile_name, cfgfile_content)) {
504 text_t::const_iterator here = cfgfile_content.begin();
505 text_t::const_iterator end = cfgfile_content.end();
506 while (here != end) {
507 here = findchar (here, end, 'd');
508 if (here == end) break;
509 if ((here+17 < end) && (substr (here, here+17) == "depositormetadata")) {
510 here = findchar (here, end, '"');
511 if (here == end) break;
512 text_t enddelimit = "\"\n";
513 getdelimitstr (here+1, end, enddelimit, metadata_str);
514 args["metadataconf"] = "var DepositorMDFields = new Array("+metadata_str+");";
515 }
516 ++here;
517 }
518 }
519
520 if (metadata_str == "") {
521 args["metadataconf"] = "var DepositorMDFields = new Array({\"name\":\"dc.Title\",\"label\":\"Title\",\"tooltip\":\"dc.Title: A name given to the resource.\",\"type\":\"text\"}, {\"name\":\"dc.Creator\",\"label\":\"Creator\",\"tooltip\":\"dc.Creator: An entity primarily responsible for making the content of the resource.\",\"type\":\"text\"}, {\"name\":\"dc.Description\",\"label\":\"Description\",\"tooltip\":\"dc.Description: An account of the content of the resource.\",\"type\":\"textarea\"});";
522 }
523 }
524
525 here = depositor_page.begin();
526 text_t stepnums = substr(here+4,here+5);
527 int stepnum = stepnums.getint();
528
529 text_t lastpage_textt = args["di1lastpage"];
530 int lastpage = lastpage_textt.getint();
531
532 // again, begin with the select bar...
533 //the first button - selecting a collection
534 for(int i = 1; i <= numsteps; i++) {
535 text_t numstr(i);
536 if(i <= lastpage && i == stepnum) {
537 depositorbar += get_button (args,depositor_page, "yellow", "step"+numstr, false);
538 } else if (i <= lastpage) {
539 depositorbar += get_button (args,depositor_page, "yellow", "step"+numstr, true);
540 } else if((i == lastpage+1)){
541 depositorbar += get_button (args,depositor_page, "green", "step"+numstr, true);
542 } else {
543 depositorbar += get_button (args,depositor_page, "grey", "step"+numstr, false);
544 }
545 depositorbar += "<td>_icongreyarrow_</td>\n";
546
547 }
548
549 //the build and preview pages are always last
550 if(lastpage == numsteps) {
551 depositorbar += get_button (args,depositor_page, "green", "laststep", true);
552 } else {
553 depositorbar += get_button (args,depositor_page, "grey", "laststep", false);
554 }
555
556 text_t laststep_textt;
557 disp.expandstring("depositor", "_laststep_", laststep_textt);
558 if(laststep_textt == "bild") {
559 depositorbar += "<td>_icongreyarrow_</td>\n";
560 depositorbar += get_button (args,depositor_page, "grey", "view", false);
561 }
562 depositorbar += "</tr><tr>";
563
564 for(int j = 1; j <= 2*(stepnum-1); j++) {
565 depositorbar += "<td></td>";
566 }
567 depositorbar += "<td align=center>_icongreyuparrow_</td>\n";
568
569 depositorbar += "</tr></table>\n";
570
571 // set the javascript so that the metadata form can read the existing values
572 if (args["cachedMDValues"] != "") {
573 disp.setmacro("cachedmetadatavalues", "depositor", args["cachedMDValues"]);
574 }
575 if (args["metadataconf"] != "") {
576 disp.setmacro("metadataconf", "depositor", args["metadataconf"]);
577 }
578 }
579
580 if ((depositor_page == "bildcancel") || (depositor_page == "bildfail")) {
581
582 for(int i = 1; i <= numsteps; i++) {
583
584 text_t numstr(i);
585 depositorbar += get_button (args,depositor_page, "yellow", "step"+numstr, true);
586 depositorbar += "<td>_icongreyarrow_</td>\n";
587
588 }
589
590 //the build and preview pages are always last
591 depositorbar += get_button (args,depositor_page, "green", "laststep", true);
592 depositorbar += "<td>_icongreyarrow_</td>\n";
593 depositorbar += get_button (args,depositor_page, "grey", "view", false);
594
595 depositorbar += "</tr><tr>";
596
597 for(int j = 1; j <= 2*numsteps; j++) {
598 depositorbar += "<td></td>";
599 }
600 depositorbar += "<td align=center>_icongreyuparrow_</td>\n";
601
602 depositorbar += "</tr></table>\n";
603
604 }
605
606 if(depositor_page == "bilddone"){
607
608 for(int i = 1; i <= numsteps; i++) {
609
610 text_t numstr(i);
611 depositorbar += get_button (args, depositor_page, "grey", "step"+numstr, false);
612 depositorbar += "<td>_icongreyarrow_</td>\n";
613
614 }
615
616 //the build and preview pages are always last
617 depositorbar += get_button (args,depositor_page, "yellow", "laststep", false);
618 depositorbar += "<td>_icongreyarrow_</td>\n";
619 depositorbar += get_button (args,depositor_page, "green", "view", true);
620
621 depositorbar += "</tr><tr>";
622
623 for(int j = 1; j <= 2*numsteps; j++) {
624 depositorbar += "<td></td>";
625 }
626 depositorbar += "<td align=center>_icongreyuparrow_</td>\n";
627
628 depositorbar += "</tr></table>\n";
629 }
630 disp.setmacro ("depositorbar", "depositor", depositorbar);
631
632 if (depositor_page == "bildfail") {
633
634 text_t textfailmsg = "_textfailmsg";
635 textfailmsg.push_back(failcode);
636 textfailmsg.push_back('_');
637 disp.setmacro("textfailmsg", "depositor", textfailmsg);
638
639 text_t bldlog = filename_cat(gsdlhome, "tmp", args["di1tmp"], args["di1dirname"] + ".bld");
640 //text_t rawlog = file_tail (bldlog, 6, 0);
641 text_t rawlog;
642 read_file(bldlog, rawlog);
643 // we'll shove in some <br> tags where \n's occur
644 text_t faillog;
645 text_t::const_iterator here = rawlog.begin();
646 text_t::const_iterator end = rawlog.end();
647 while (here != end) {
648 if (*here == '\n') faillog += "<br>";
649 faillog.push_back (*here);
650 ++here;
651 }
652 disp.setmacro ("faillog", "depositor", dm_safe(faillog));
653 }
654}
655
656
657//basic framework
658bool depositoraction::do_action (cgiargsclass &args, recptprotolistclass * /*protos*/,
659 browsermapclass * /*browsers*/, displayclass &disp,
660 outconvertclass &outconvert, ostream &textout,
661 ostream &logout) {
662 // make sure the depositor is enabled
663 if (disabled) {
664 textout << outconvert
665 << "<html>\n"
666 << "<head>\n"
667 << "<title>Depositor disabled</title>\n"
668 << "</head>\n"
669 << "<body bgcolor=\"#ffffff\" text=\"#000000\" link=\"#006666\" "
670 << "alink=\"#cc9900\" vlink=\"#666633\">\n"
671 << "<h2>Facility disabled</h2>\n"
672 << "Sorry, the Depositor end-user collecation update facility is currently disabled\n"
673 << "\n</body>\n"
674 << "</html>\n";
675 return true;
676 }
677
678 text_t &depositor_page = args["p"];
679 text_t &collection = args["di1dirname"];
680
681 // make sure we have perl (we won't bother with this check for the
682 // building status pages to avoid slowing things down unneccessarily)
683 if (depositor_page != "bildstatus" && depositor_page != "bildframe1" && !perl_ok(logout)) {
684 textout << outconvert
685 << "<html>\n"
686 << "<head>\n"
687 << "<title>Perl not found</title>\n"
688 << "</head>\n"
689 << "<body bgcolor=\"#ffffff\" text=\"#000000\" link=\"#006666\" "
690 << "alink=\"#cc9900\" vlink=\"#666633\">\n"
691 << "<h2>Perl not found</h2>\n"
692 << "Greenstone could not detect perl on this system. It is therefore not\n"
693 << "possible to build a Greenstone collection, either from the Collector or the \n"
694 << "command-line tools, or to use the Collector for any other task.\n"
695 << "<p>Please refer to the Greenstone Installer's Guide for details on\n"
696 << "installing perl on your system.\n"
697 << "\n</body>\n"
698 << "</html>\n";
699 return true;
700
701 }
702
703 text_t::const_iterator here = depositor_page.begin();
704 text_t::const_iterator end = depositor_page.end();
705 text_t stepstring = substr(here,here+4);
706
707 if ((depositor_page == "select") || (stepstring == "step")) {
708 textout << outconvert << disp << ("_depositor:header_\n")
709 << ("_depositor:" + encodeForHTML(depositor_page) + "content_\n")
710 << ("_depositor:footer_\n");
711
712 }
713
714 if ((depositor_page == "bild") || (depositor_page == "depositonly")) {
715
716 text_t filename_textt = args["di1userfile"];
717 text_t timestamp_str = args["di1timestamp"];
718 //check to make sure a file was uploaded
719 //if more than one upload occurred, the last one is taken
720 if(filename_textt == "") {
721 textout << outconvert << disp << "<p> no file available</p>\n";
722 } else {
723
724 text_t col_dirname = filename_cat(collecthome,args[macro_prefix+"dirname"]);
725 text_t import_dirname = filename_cat(col_dirname,"import");
726 if(!directory_exists(import_dirname)) {
727 bool flag = mk_dir(import_dirname);
728 if(!flag) {
729 cerr << "Error: unable to make directory " << import_dirname << endl;
730 return true;
731 }
732 }
733
734 text_t dirname = filename_cat(import_dirname,timestamp_str);
735 bool flag = mk_dir(dirname);
736 if(!flag) {
737 cerr << "Error: unable to make timestamp directory " << dirname << endl;
738 return true;
739 }
740
741 text_t filename_textt = args["di1userfile"];
742 text_t tmpdir = filename_cat(gsdlhome,"tmp",args["di1tmp"],timestamp_str);
743 text_t tmpfile = filename_cat(tmpdir,filename_textt);
744 text_t filename = filename_cat(dirname, filename_textt);
745 if(!file_copy(tmpfile, filename)) {
746 cerr << "Unable to copy " << tmpfile << " to " << filename << endl;
747 }
748
749 //write the metadata file
750 write_metadata_file(args, filename_textt, timestamp_str);
751
752 if(depositor_page == "bild"){
753
754 //create a manifest file
755 write_manifest_file(args, filename_textt, timestamp_str);
756
757 // do the work (download, import, build)
758 gsdl_build (args, logout);
759
760 if (message.empty()) {
761 // bild page is a frameset so we don't want headers and stuff
762 textout << outconvert << disp << ("_depositor:bildcontent_\n");
763 }
764 }
765 }
766 }
767
768 if (message.empty()) {
769
770 if (depositor_page != "bild" && stepstring != "step" && depositor_page != "select") {
771 // output page ("bild" page was already output above)
772 textout << outconvert << disp << ("_depositor:header_\n")
773 << ("_depositor:" + encodeForHTML(depositor_page) + "content_\n")
774 << ("_depositor:footer_\n");
775 }
776 } else {
777 // message was set somewhere (probably an error), output message page
778 textout << outconvert << disp << ("_depositor:header_\n")
779 << ("_depositor:" + message + "content_\n")
780 << ("_depositor:footer_\n");
781 message.clear();
782 }
783
784 return true;
785
786}
787
788
789//This function creates a metadata.xml file
790void depositoraction::write_metadata_file(cgiargsclass &args, text_t filename_str, text_t& timestamp_str)
791{
792
793 //build metadata file
794 //the front
795 text_t metadata_file = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
796 metadata_file += "<!DOCTYPE DirectoryMetadata SYSTEM \"http://greenstone.org/dtd/DirectoryMetadata/1.0/DirectoryMetadata.dtd\">\n";
797 metadata_file += "<DirectoryMetadata>\n";
798 metadata_file += " <FileSet>\n";
799 metadata_file += " <FileName>";
800
801 // Generate 'regular expression' save version of filename
802 // for now that means escaping any '.' characters
803 // consider generalising as function in gsdltools.h/cpp?
804
805 text_t filename_re;
806 text_t::const_iterator here = filename_str.begin();
807 text_t::const_iterator end = filename_str.end();
808 while (here != end) {
809 if (*here == '.') {
810 filename_re.push_back('\\');
811 }
812
813 filename_re.push_back(*here);
814 ++here;
815 }
816
817 metadata_file += filename_re;
818
819 metadata_file += "</FileName>\n";
820 metadata_file += " <Description>\n";
821
822
823 cgiargsclass::const_iterator args_here = args.begin();
824 cgiargsclass::const_iterator args_end = args.end();
825
826 while (args_here != args_end) {
827 text_t args_name = (*args_here).first;
828
829 int prefix_len = macro_prefix.size();
830 int args_name_len = args_name.size();
831
832 if(args_name_len >= prefix_len+3) { // Only now can we substring args_name by prefix_len+3
833 text_t args_prefix;
834 if(args_name_len == prefix_len+3) {
835 args_prefix = args_name;
836 } else { // >, so substring
837 args_prefix = substr(args_name.begin(),args_name.begin()+prefix_len+3);
838 }
839
840 if (args_prefix == (macro_prefix+"md.")) {
841 text_t args_val = args[args_name];
842
843 text_t args_suffix = substr(args_name.begin()+prefix_len+3,args_name.end());
844
845 text_tarray mdvalues;
846 splitchar (args_val.begin(), args_val.end(), ',', mdvalues);
847 int numvalues = mdvalues.size();
848
849 for (int i = 0; i < numvalues; ++i) {
850 if (!mdvalues[i].empty()) {
851
852 decode_cgi_arg(mdvalues[i]);
853
854 metadata_file += " <Metadata mode=\"accumulate\" name=\"";
855 metadata_file += args_suffix;
856 metadata_file += "\">";
857 metadata_file += mdvalues[i];
858 metadata_file += "</Metadata>\n";
859
860 }
861 }
862 }
863 }
864 ++args_here;
865 }
866
867 //the end of the file
868 metadata_file += " </Description>\n";
869 metadata_file += " </FileSet>\n";
870 metadata_file += "</DirectoryMetadata>\n";
871
872 //create metadata.xml file
873 text_t metadata_path = filename_cat(collecthome, args[macro_prefix+"dirname"], "import", timestamp_str, "metadata.xml");
874 text_t my_path = filename_cat(gsdlhome,"tmp", "metadata.xml");
875
876 ofstream metadata(metadata_path.getcstr());
877 ofstream my_tmp(my_path.getcstr());
878
879 if(!metadata.is_open()) {
880 cerr << "Cannot open metadata.xml!" << endl;
881 } else {
882
883 //write metadata.xml
884 metadata.write(metadata_file.getcstr(), metadata_file.size());
885 my_tmp.write(metadata_file.getcstr(), metadata_file.size());
886 }
887}
888
889//This function creates a manifest.xml file
890void depositoraction::write_manifest_file(cgiargsclass &args, text_t filename,
891 text_t& timestamp_str)
892{
893
894 //build manifest file
895
896 //the front
897 text_t manifest_file = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
898 manifest_file += "<Manifest>\n";
899 manifest_file += " <Index>\n";
900 manifest_file += " <Filename>\n";
901 manifest_file += " " + timestamp_str + "\n";
902 manifest_file += " </Filename>\n";
903
904 //the end of the file
905 manifest_file += " </Index>\n";
906 manifest_file += "</Manifest>\n";
907
908 //create manifest.xml file
909 text_t manifest_path = filename_cat(collecthome, args[macro_prefix+"dirname"], "manifest.xml");
910
911 char* manifest_cstr = manifest_path.getcstr();
912
913 ofstream manifest(manifest_cstr);
914
915 if(!manifest.is_open()) {
916 cerr << "Cannot open" << manifest_cstr << endl;
917 } else {
918
919 //write manifest.xml
920 char *manifest_file_cstr = manifest_file.getcstr();
921 manifest.write(manifest_file_cstr, manifest_file.size());
922 delete [] manifest_file_cstr;
923 }
924
925 delete [] manifest_cstr;
926}
927
928
929
930text_t depositoraction::get_button(cgiargsclass &args, const text_t &thispage,
931 const text_t &color,
932 const text_t &type, bool enabled)
933{
934
935 text_t::const_iterator here = type.begin();
936 text_t::const_iterator end = type.end();
937 text_t stepstring = substr(here,here+4);
938 if ((color != "green" && color != "grey" && color != "yellow") ||
939 (type != "select" && type != "laststep" && stepstring != "step" && type != "view"))
940 return g_EmptyText;
941
942 text_t href = "_http"+type+"_";
943 text_t target = "";
944
945 here = thispage.begin();
946 stepstring = substr(here,here+4);
947 if (thispage == "bildcancel" || thispage == "bildfail" || thispage == "select"|| stepstring == "step") {
948 // call the check submit macro instead of linking directly to the page
949
950 if(type == "laststep") {
951 href="\"javascript:check_submit('_"+type+"_');\"";
952 } else {
953 href="\"javascript:check_submit('"+type+"');\"";
954 }
955
956 } else if (type == "view") {
957 //target = " target=_top";
958 target = " target=_blank";
959 }
960
961 text_t tdclass = "wizardbar"+color;
962 if (enabled) {
963 // link to the appropriate page
964 return "<td class="+tdclass+"><a href="+href+target+">_text"+type+"_</a></td>";
965 }
966 else {
967 // just display the text
968 return "<td class="+tdclass+">_text"+type+"_</td>";
969 }
970}
971
972
973#endif //GSDL_USE_DEPOSITOR_ACTION
Note: See TracBrowser for help on using the repository browser.