root/main/trunk/greenstone2/runtime-src/src/recpt/gtiaction.cpp @ 28899

Revision 28899, 33.6 KB (checked in by ak19, 4 years ago)

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

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1/**********************************************************************
2 *
3 * gtiaction.cpp --
4 * Copyright (C) 2005  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
27#include "gsdl_modules_cfg.h"
28#ifdef GSDL_USE_GTI_ACTION
29
30
31#include <expat.h>
32#include <stdio.h>
33#include <sys/utsname.h>
34#include "gtiaction.h"
35#include "cgiutils.h"
36#include "fileutil.h"
37#include "gsdlunicode.h"
38
39
40
41gtiaction::gtiaction()
42{
43  cgiarginfo arg_ainfo;
44
45  arg_ainfo.shortname = "tlc";
46  arg_ainfo.longname = "translation target language code";
47  arg_ainfo.multiplechar = true;
48  arg_ainfo.multiplevalue = false;
49  arg_ainfo.defaultstatus = cgiarginfo::weak;
50  arg_ainfo.savedarginfo = cgiarginfo::must;
51  argsinfo.addarginfo (&cerr, arg_ainfo);
52
53  arg_ainfo.shortname = "tfk";
54  arg_ainfo.longname = "translation file key";
55  arg_ainfo.multiplechar = true;
56  arg_ainfo.multiplevalue = false;
57  arg_ainfo.defaultstatus = cgiarginfo::weak;
58  arg_ainfo.savedarginfo = cgiarginfo::must;
59  argsinfo.addarginfo (&cerr, arg_ainfo);
60
61  arg_ainfo.shortname = "ncpp";
62  arg_ainfo.longname = "number of chunks per page";
63  arg_ainfo.multiplechar = true;
64  arg_ainfo.multiplevalue = false;
65  arg_ainfo.defaultstatus = cgiarginfo::weak;
66  arg_ainfo.argdefault = "1";
67  arg_ainfo.savedarginfo = cgiarginfo::must;
68  argsinfo.addarginfo (&cerr, arg_ainfo);
69}
70
71
72
73gtiaction::~gtiaction()
74{
75  delete[] set_gsdlhome_cstr;
76  delete[] set_gsdlos_cstr;
77}
78
79
80
81bool gtiaction::init (ostream& /*logout*/)
82{
83  // Set GSDLHOME and GSDLOS environment variables
84  text_t set_gsdlhome = "GSDLHOME=" + gsdlhome;
85  text_t set_gsdlos = "GSDLOS=";
86
87#if defined (__WIN32__)
88  set_gsdlos += "windows";
89#else
90  struct utsname *buf = new struct utsname();
91  if (uname(buf) == -1) {
92    // uname failed, so this must be linux
93    set_gsdlos += "linux";
94  }
95  else {
96    text_t gsdlos = buf->sysname;
97    lc(gsdlos);
98    set_gsdlos += gsdlos;
99  }
100  delete buf;
101#endif
102
103  // These will be cleaned up in the destructor
104  set_gsdlhome_cstr = set_gsdlhome.getcstr();
105  set_gsdlos_cstr = set_gsdlos.getcstr();
106  putenv(set_gsdlhome_cstr);
107  putenv(set_gsdlos_cstr);
108
109  return true;
110}
111
112
113
114bool gtiaction::check_cgiargs(cgiargsinfoclass& /*argsinfo*/, cgiargsclass& args,
115                  recptprotolistclass* /*protos*/, ostream& logout)
116{
117  // Authenticate the user, except for the "home" and "lang" pages
118  if (args["p"] != "home" && args["p"] != "lang" && args["p"] != "status") {
119    args["uan"] = 1;
120    args["ug"] = "langadmin_" + args["tlc"];
121  }
122
123  return true;
124}
125
126
127
128bool gtiaction::do_action(cgiargsclass& args, recptprotolistclass* /*protos*/,
129              browsermapclass* /*browsers*/, displayclass& disp,
130              outconvertclass& outconvert, ostream& textout,
131              ostream& logout)
132{
133  // Special case for producing Excel spreadsheets, as these are downloaded
134  if (args["p"] == "excel") {
135    return produce_excel_spreadsheet(args, logout);
136  }
137
138  textout << outconvert << disp << ("_gti:header_\n") << ("_gti:content_\n") << ("_gti:footer_\n");
139  return true;
140}
141
142
143
144void gtiaction::get_cgihead_info(cgiargsclass& args, recptprotolistclass* /*protos*/,
145                 response_t& response, text_t& response_data,
146                 ostream& logout)
147{
148  // Special case for producing Excel spreadsheets, as these are downloaded
149  if (args["p"] == "excel") {
150    printf("Content-Disposition: attachment; filename=\"Greenstone-%s-%s.xml\"\n", args["tlc"].getcstr(), args["tfk"].getcstr());
151    response = content;
152    response_data = "text/xml";
153    return;
154  }
155
156  response = content;
157  response_data = "text/html";
158}
159
160
161
162void gtiaction::define_internal_macros(displayclass& disp, cgiargsclass& args,
163                       recptprotolistclass* protos, ostream& logout)
164{
165  // logout << endl << "Arguments: " << args << endl;
166  logout << endl << "CGI arg p: " << args["p"] << endl;
167
168  // For some reason this must be done as well as setting the macro in gti.dm
169  // is that still true??
170  disp.setmacro("preflink", displayclass::defaultpackage, "_gti:preflink_");
171 
172  // Define the page content for the GTI home page
173  if (args["p"] == "home") {
174    define_gti_home_page(disp, args, logout);
175    return;
176  }
177
178  // Define the page content for the GTI language page
179  if (args["p"] == "lang") {
180    define_gti_lang_page(disp, args, logout);
181    return;
182  }
183
184  // Define the page content for the GTI search page
185  if (args["p"] == "find") {
186    define_gti_find_page(disp, args, logout);
187    return;
188  }
189
190  // Define the page content for the GTI offline page
191  if (args["p"] == "offline") {
192    define_gti_offline_page(disp, args, logout);
193    return;
194  }
195 
196  // Define the page content for the GTI view status page
197  if (args["p"] == "status") {
198    define_gti_status_page(disp, args, logout);
199    return;
200  }
201
202  // Process user translations
203  if (args["p"] == "submit") {
204    process_gti_submissions(disp, args, logout, true);
205  }
206
207  if (args["p"] == "glihelp") {
208    produce_glihelp_zipfile(disp, args, logout);   
209  }
210   
211  // Define the page content for the GTI core pages (containing the translation input forms)
212  define_gti_core_page(disp, args, logout);
213}
214
215
216
217void gtiaction::define_gti_home_page(displayclass& disp, cgiargsclass& args, ostream& logout)
218{
219  disp.setmacro("gtiformcontent", "gti", "_gti:gtihome_");
220
221  languageinfo_tmap loaded_languages = recpt->get_configinfo().languages;
222
223  // Get the languages specified in the main.cfg file, and put them into a map to sort by name
224  text_tmap gti_languages_name_code_mapping;
225  languageinfo_tmap::const_iterator loaded_language = loaded_languages.begin();
226  while (loaded_language != loaded_languages.end()) {
227    // English is not a valid GTI target language, since it is the source language
228    if (loaded_language->first != "en") {
229      gti_languages_name_code_mapping[loaded_language->second.longname] = loaded_language->first;
230    }
231    ++loaded_language;
232  }
233
234  // Set the gtitlcselection macro
235  text_t gti_tlc_selection = "<select name=\"tlc\">\n";
236  text_tmap::iterator gti_language = gti_languages_name_code_mapping.begin();
237  while (gti_language != gti_languages_name_code_mapping.end()) {
238    gti_tlc_selection += "<option value=\"" + gti_language->second + "\">" + gti_language->first + "</option>\n";
239    ++gti_language;
240  }
241  gti_tlc_selection += "</select>";
242  disp.setmacro("gtitlcselection", "gti", gti_tlc_selection);
243}
244
245
246
247void gtiaction::define_gti_lang_page(displayclass& disp, cgiargsclass& args, ostream& logout)
248{
249  // Get the target language code from the CGI arguments
250  text_t target_language_code = args["tlc"];
251
252  disp.setmacro("gtiformcontent", "gti", "_gti:gtilang_");
253
254  // Send a request to gti.pl to get the valid translation files
255  text_t gti_arguments = "get-language-status " + target_language_code;
256  GTI_Response gti_response = parse_gti_response(do_gti_request(gti_arguments, logout), logout);
257  if (gti_response.error_message != "") {
258    // An error has occurred
259    disp.setmacro("gtiformcontent", "gti", "_gti:gtierror_");
260    disp.setmacro("gtierrormessage", "gti", gti_response.error_message);
261    return;
262  }
263
264  languageinfo_tmap loaded_languages = recpt->get_configinfo().languages;
265  disp.setmacro("gtitargetlanguagename", "gti", loaded_languages[target_language_code].longname);
266
267  // Set the gtitfkselection macro
268  text_t gti_tfk_selection = "<table>";
269  text_tmap::iterator translation_file = gti_response.translation_files_index_to_key_mapping.begin();
270  while (translation_file != gti_response.translation_files_index_to_key_mapping.end()) {
271    text_t translation_file_key = translation_file->second;
272
273    gti_tfk_selection += "<tr><td>";
274    gti_tfk_selection += "<input type=\"radio\" name=\"tfk\" value=\"" + translation_file_key + "\"></td>\n";
275    gti_tfk_selection += "<td>_textgti" + translation_file_key + "_</td></tr>\n";
276
277    text_t num_chunks_translated = gti_response.translation_files_key_to_num_chunks_translated_mapping[translation_file_key];
278    text_t num_chunks_requiring_translation = gti_response.translation_files_key_to_num_chunks_requiring_translation_mapping[translation_file_key];
279    text_t num_chunks_requiring_updating = gti_response.translation_files_key_to_num_chunks_requiring_updating_mapping[translation_file_key];
280    gti_tfk_selection += "<tr><td></td><td>_gtitranslationfilestatus_(" + num_chunks_translated + "," + num_chunks_requiring_translation + "," + num_chunks_requiring_updating + ")</td></tr>\n";
281    ++translation_file;
282  }
283  gti_tfk_selection += "</table>";
284  disp.setmacro("gtitfkselection", "gti", gti_tfk_selection);
285}
286
287
288
289void gtiaction::define_gti_status_page(displayclass& disp, cgiargsclass& args, ostream& logout)
290{
291  disp.setmacro("gtiformcontent", "gti", "_gti:gtistatus_");
292
293  languageinfo_tmap loaded_languages = recpt->get_configinfo().languages;
294
295  // Get the languages specified in the main.cfg file, and put them into a map to sort by name
296  text_tmap gti_languages_name_code_mapping;
297  languageinfo_tmap::const_iterator loaded_language = loaded_languages.begin();
298  while (loaded_language != loaded_languages.end()) {
299    // English is not a valid GTI target language, since it is the source language
300    if (loaded_language->first != "en") {
301      gti_languages_name_code_mapping[loaded_language->second.longname] = loaded_language->first;
302    }
303    ++loaded_language;
304  }
305
306  // Get the languages, for each language, send a request to gti.pl to get the valid translation files and the current status for each file
307  text_t gti_status_table = "<table class=\"status\">\n";
308  text_tmap::iterator gti_language = gti_languages_name_code_mapping.begin();
309  bool first_lang = true;
310  while (gti_language != gti_languages_name_code_mapping.end()) {   
311    // Send a request to gti.pl to get the valid translation files
312    text_t gti_arguments = "get-language-status " + gti_language->second;
313    GTI_Response gti_response = parse_gti_response(do_gti_request(gti_arguments, logout), logout);
314    if (gti_response.error_message != "") {
315      // An error has occurred
316      disp.setmacro("gtiformcontent", "gti", "_gti:gtierror_");
317      disp.setmacro("gtierrormessage", "gti", gti_response.error_message);
318      return;
319    }
320
321    text_tmap::iterator translation_file = gti_response.translation_files_index_to_key_mapping.begin();
322       
323    text_t lang_status_temp = "<tr><td class=\"first\">" + gti_language->first + "</td>\n";
324    text_t files_temp = "<tr><th class=\"status\">_textgtilanguage_</th>\n";
325    text_t number_of_strings_temp = "<tr><td class=\"first\"><b>_textgtitotalnumberoftranslations_</b></td>\n";
326   
327    while (translation_file != gti_response.translation_files_index_to_key_mapping.end()) {
328      text_t translation_file_key = translation_file->second;                     
329
330      text_t num_chunks_translated = gti_response.translation_files_key_to_num_chunks_translated_mapping[translation_file_key];
331      text_t num_chunks_requiring_translation = gti_response.translation_files_key_to_num_chunks_requiring_translation_mapping[translation_file_key];
332        text_t num_chunks_requiring_updating = gti_response.translation_files_key_to_num_chunks_requiring_updating_mapping[translation_file_key];           
333       
334        lang_status_temp += "<td class=\"status\">";
335        if(num_chunks_translated.getint() > 0){
336            lang_status_temp += "<div class=\"nowrap\"><div class=\"done\">";
337            lang_status_temp += num_chunks_translated+"</div><div class=\"plus\">+</div><div class=\"update\">";
338        lang_status_temp += num_chunks_requiring_updating+"</div><div class=\"plus\">+</div><div class=\"todo\">";
339        lang_status_temp += num_chunks_requiring_translation+"</div></div>";
340        }
341        lang_status_temp += "</td>\n";
342       
343       
344    //lang_status_temp += "<td valign=\"top\" nowrap>_gtitranslationfilestatus2_(" + num_chunks_translated + "," + num_chunks_requiring_translation + "," + num_chunks_requiring_updating + ")</td>";           
345       
346    // List the file names as the first row of the status table
347    // Add up number of strings need to be translate in each file, as the second line of the status table
348      if (first_lang) {
349        files_temp += "<th class=\"status\">_textgti" + translation_file_key + "_</th>\n";
350        int int_number_of_strings = num_chunks_translated.getint() + num_chunks_requiring_translation.getint();
351        number_of_strings_temp += "<td class=\"status\"><b>";
352        number_of_strings_temp.appendint(int_number_of_strings);
353        number_of_strings_temp += "</b></td>\n";
354      }
355        ++translation_file;
356    }   
357   
358    if(first_lang) {     
359     gti_status_table += files_temp + "</tr>" + number_of_strings_temp + "</tr>";   
360     first_lang = false;
361    }
362   
363    gti_status_table += lang_status_temp + "</tr>";   
364    ++gti_language;
365  }
366  gti_status_table += "\n</table>";
367  disp.setmacro("gtistatustable", "gti", gti_status_table);
368}
369
370
371
372void gtiaction::define_gti_find_page(displayclass& disp, cgiargsclass& args, ostream& logout)
373{
374  // Get the target language code and file to translate from the CGI arguments
375  text_t target_language_code = args["tlc"];
376  text_t translation_file_key = args["tfk"];
377  text_t query_string = to_utf8(args["q"]);
378
379  // Process user corrections
380  if (args["sp"] != "") {
381    process_gti_submissions(disp, args, logout, false);
382  }
383
384  disp.setmacro("gtiformcontent", "gti", "_gti:gtifind_");
385
386  languageinfo_tmap loaded_languages = recpt->get_configinfo().languages;
387  disp.setmacro("gtitargetlanguagename", "gti", loaded_languages[target_language_code].longname);
388  disp.setmacro("gtitranslationfiledesc", "gti", "_gti:textgti" + encodeForHTML(translation_file_key) + "_");
389
390  if (query_string == "") {
391    // No query, so no search results
392    disp.setmacro("gtifindformcontent", "gti", "");
393    return;
394  }
395
396  // Display text right to left if target language is Arabic or Farsi or Urdu
397  if (target_language_code == "ar" || target_language_code == "fa" || target_language_code == "ur") {
398    disp.setmacro("gtitextdirection", "gti", "rtl");
399  }
400  else {
401    disp.setmacro("gtitextdirection", "gti", "ltr");
402  }
403
404  // Send a request to gti.pl to get the valid translation files
405  logout << "Query argument: " << query_string << endl;
406  text_t gti_arguments = "search-chunks " + target_language_code + " " + translation_file_key + " " + query_string;
407  GTI_Response gti_response = parse_gti_response(do_gti_request(gti_arguments, logout), logout);
408  if (gti_response.error_message != "") {
409    // An error has occurred
410    disp.setmacro("gtiformcontent", "gti", "_gti:gtierror_");
411    disp.setmacro("gtierrormessage", "gti", gti_response.error_message);
412    return;
413  }
414
415  disp.setmacro("gtinumchunksmatchingquery", "gti", gti_response.num_chunks_matching_query);
416
417  // Loop through the chunks returned, displaying them on the page
418  text_t gti_find_form_content = "_gtifindformheader_\n";
419  text_tmap::iterator chunk_key_iterator = gti_response.target_file_chunks_key_to_text_mapping.begin();
420  while (chunk_key_iterator != gti_response.target_file_chunks_key_to_text_mapping.end()) {
421    text_t chunk_key = chunk_key_iterator->first;
422
423    // Need to escape any underscores in the chunk key to show it correctly on the page
424    text_t chunk_key_escaped = escape_all(chunk_key, '_');
425
426    // Need to escape any backslashes, underscores, commas, parentheses, and single quotes in the chunk text
427    text_t target_file_chunk_text = gti_response.target_file_chunks_key_to_text_mapping[chunk_key];
428    text_t target_file_chunk_text_escaped = escape_all(target_file_chunk_text, '\\');
429    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, '_');
430    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, ',');
431    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, '(');
432    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, ')');
433    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, '"');
434    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, '\'');
435
436    // This chunk matches the query
437    gti_find_form_content += "_gtichunkmatchingquery_(" + chunk_key_escaped + "," + target_file_chunk_text_escaped + ")\n";
438
439    chunk_key_iterator++;
440  }
441  gti_find_form_content += "_gtifindformfooter_\n";
442
443  disp.setmacro("gtifindformcontent", "gti", gti_find_form_content);
444}
445
446
447
448void gtiaction::define_gti_offline_page(displayclass& disp, cgiargsclass& args, ostream& logout)
449{
450  // Get the target language code and file to translate from the CGI arguments
451  text_t target_language_code = args["tlc"];
452  text_t translation_file_key = args["tfk"];
453
454  disp.setmacro("gtiformcontent", "gti", "_gti:gtioffline_");
455
456  languageinfo_tmap loaded_languages = recpt->get_configinfo().languages;
457  disp.setmacro("gtitargetlanguagename", "gti", loaded_languages[target_language_code].longname);
458  disp.setmacro("gtitranslationfiledesc", "gti", "_gti:textgti" + translation_file_key + "_");
459}
460
461
462
463void gtiaction::define_gti_core_page(displayclass& disp, cgiargsclass& args, ostream& logout)
464{
465  // Get the target language code and file to translate from the CGI arguments
466  text_t target_language_code = args["tlc"];
467  text_t translation_file_key = args["tfk"];
468  text_t num_chunks_per_page = args["ncpp"];
469  logout << "Num chunks per page: " << num_chunks_per_page << endl;
470
471  disp.setmacro("gtiformcontent", "gti", "_gti:gticore_");
472
473  // Display text right to left if target language is Arabic or Farsi or Urdu
474  if (target_language_code == "ar" || target_language_code == "fa" || target_language_code == "ur") {
475    disp.setmacro("gtitextdirection", "gti", "rtl");
476  }
477  else {
478    disp.setmacro("gtitextdirection", "gti", "ltr");
479  }
480
481  // Send a request to gti.pl to get the first string to translate
482  text_t gti_arguments = "get-first-n-chunks-requiring-work " + target_language_code + " " + translation_file_key + " " + num_chunks_per_page;
483  GTI_Response gti_response = parse_gti_response(do_gti_request(gti_arguments, logout), logout);
484  if (gti_response.error_message != "") {
485    // An error has occurred
486    disp.setmacro("gtiformcontent", "gti", "_gti:gtierror_");
487    disp.setmacro("gtierrormessage", "gti", gti_response.error_message);
488    return;
489  }
490
491  languageinfo_tmap loaded_languages = recpt->get_configinfo().languages;
492  disp.setmacro("gtitargetlanguagename", "gti", loaded_languages[target_language_code].longname);
493  if (translation_file_key == "glihelp") {
494    disp.setmacro("gtitargetfilepath", "gti", "_gtidownloadglihelp_");
495  } else {
496    disp.setmacro("gtitargetfilepath", "gti", gti_response.translation_files_key_to_target_file_path_mapping[translation_file_key]);
497  }
498  disp.setmacro("gtitranslationfiledesc", "gti", "_gti:textgti" + encodeForHTML(translation_file_key) + "_");
499  disp.setmacro("gtiviewtranslationfileinaction", "gti", "_gti:gtiview" + encodeForHTML(translation_file_key) + "inaction_");
500
501  disp.setmacro("gtinumchunkstranslated", "gti", gti_response.translation_files_key_to_num_chunks_translated_mapping[translation_file_key]);
502  disp.setmacro("gtinumchunksrequiringtranslation", "gti", gti_response.translation_files_key_to_num_chunks_requiring_translation_mapping[translation_file_key]);
503  disp.setmacro("gtinumchunksrequiringupdating", "gti", gti_response.translation_files_key_to_num_chunks_requiring_updating_mapping[translation_file_key]);
504
505  // Check if the translation file is finished
506  if (gti_response.translation_files_key_to_num_chunks_requiring_translation_mapping[translation_file_key] == "0" && gti_response.translation_files_key_to_num_chunks_requiring_updating_mapping[translation_file_key] == "0") {
507    disp.setmacro("gtiformcontent", "gti", "_gti:gtidone_");
508    return;
509  }
510
511  // Loop through the chunks returned, displaying them on the page
512  text_t gti_core_form_content = "";
513  text_tmap::iterator chunk_key_iterator = gti_response.source_file_chunks_key_to_text_mapping.begin();
514  while (chunk_key_iterator != gti_response.source_file_chunks_key_to_text_mapping.end()) {
515    text_t chunk_key = chunk_key_iterator->first;
516
517    // Need to escape any underscores in the chunk key to show it correctly on the page
518    text_t chunk_key_escaped = escape_all(chunk_key, '_');
519
520    // Need to escape any backslashes, underscores, commas, parentheses, and single quotes in the chunk text
521    text_t source_file_chunk_text = gti_response.source_file_chunks_key_to_text_mapping[chunk_key];
522    text_t source_file_chunk_text_escaped = escape_all(source_file_chunk_text, '\\');
523    source_file_chunk_text_escaped = escape_all(source_file_chunk_text_escaped, '_');
524    source_file_chunk_text_escaped = escape_all(source_file_chunk_text_escaped, ',');
525    source_file_chunk_text_escaped = escape_all(source_file_chunk_text_escaped, '(');
526    source_file_chunk_text_escaped = escape_all(source_file_chunk_text_escaped, ')');
527    source_file_chunk_text_escaped = escape_all(source_file_chunk_text_escaped, '\'');
528    text_t target_file_chunk_text = gti_response.target_file_chunks_key_to_text_mapping[chunk_key];
529    text_t target_file_chunk_text_escaped = escape_all(target_file_chunk_text, '\\');
530    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, '_');
531    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, ',');
532    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, '(');
533    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, ')');
534    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, '\'');
535
536    text_t source_file_chunk_date = gti_response.source_file_chunks_key_to_date_mapping[chunk_key];
537    text_t target_file_chunk_date = gti_response.target_file_chunks_key_to_date_mapping[chunk_key];
538
539    // This chunk requires translation
540    if (target_file_chunk_text == "") {
541      gti_core_form_content += "_gtichunkrequiringtranslation_(" + chunk_key_escaped + "," + source_file_chunk_text_escaped + "," + source_file_chunk_date + ")\n";
542    }
543    // This chunk requires updating
544    else {
545      gti_core_form_content += "_gtichunkrequiringupdating_(" + chunk_key_escaped + "," + source_file_chunk_text_escaped + "," + source_file_chunk_date + "," + target_file_chunk_text_escaped + "," + target_file_chunk_date + ")\n";
546    }
547
548    chunk_key_iterator++;
549  }
550
551  disp.setmacro("gticoreformcontent", "gti", gti_core_form_content);
552}
553
554
555
556void gtiaction::process_gti_submissions(displayclass& disp, cgiargsclass& args, ostream& logout, bool force_submission)
557{
558  // Get the target language code and file to translate from the CGI arguments
559  text_t target_language_code = args["tlc"];
560  text_t translation_file_key = args["tfk"];
561  text_t submitter_username = args["un"];
562
563  // Submitted chunk arguments contain the language code followed by "::"
564  char* source_chunk_key_start_cstr = ((text_t) "en" + "%3A%3A").getcstr();
565  char* target_chunk_key_start_cstr = (target_language_code + "%3A%3A").getcstr();
566
567  // Find the cgi arguments with submitted chunk information
568  text_t submission_text;
569  cgiargsclass::const_iterator cgi_argument = args.begin();
570  while (cgi_argument != args.end()) {
571    char* cgi_argument_name_cstr = cgi_argument->first.getcstr();
572
573    // Source file text
574    if (strncmp(cgi_argument_name_cstr, source_chunk_key_start_cstr, strlen(source_chunk_key_start_cstr)) == 0) {
575      submission_text += "<SourceFileText key=\"";
576      text_t source_key = &cgi_argument_name_cstr[strlen(source_chunk_key_start_cstr)];
577      decode_cgi_arg(source_key);
578      submission_text += source_key;
579      //submission_text += &cgi_argument_name_cstr[strlen(source_chunk_key_start_cstr)];
580      submission_text += "\">\n";
581
582      text_t source_value = xml_safe(decode_commas(args[cgi_argument->first]));
583      // if (args["w"] != "utf-8") {
584      // source_value = to_utf8(source_value);
585      // }
586      submission_text += source_value + "\n";
587      submission_text += "</SourceFileText>\n";
588    }
589    // Target file text
590    if (strncmp(cgi_argument_name_cstr, target_chunk_key_start_cstr, strlen(target_chunk_key_start_cstr)) == 0) {
591      submission_text += "<TargetFileText key=\"";
592      text_t target_key = &cgi_argument_name_cstr[strlen(target_chunk_key_start_cstr)];
593      decode_cgi_arg(target_key);
594      submission_text += target_key;
595      //submission_text += &cgi_argument_name_cstr[strlen(target_chunk_key_start_cstr)];
596      submission_text += "\">\n";
597
598      text_t target_value = xml_safe(decode_commas(args[cgi_argument->first]));
599      // if (args["w"] != "utf-8") {
600      // target_value = to_utf8(target_value);
601      // }
602      submission_text += target_value + "\n";
603      submission_text += "</TargetFileText>\n";
604    }
605
606    delete[] cgi_argument_name_cstr;
607    ++cgi_argument;
608  }
609
610  logout << "Submission text: " << submission_text << endl;
611
612  // Send the submission to gti.pl
613  text_t gti_arguments = "submit-translations " + target_language_code + " " + translation_file_key + " " + submitter_username;
614  if (force_submission) {
615    gti_arguments += " -force_submission";
616  }
617  do_gti_submission(gti_arguments, submission_text, logout);
618  logout << "Done." << endl;
619
620  delete[] source_chunk_key_start_cstr;
621  delete[] target_chunk_key_start_cstr;
622}
623
624
625
626bool gtiaction::produce_excel_spreadsheet(cgiargsclass& args, ostream& logout)
627{
628  // Get the target language code and file to translate from the CGI arguments
629  text_t target_language_code = args["tlc"];
630  text_t translation_file_key = args["tfk"];
631  text_t target_chunk_type = args["tct"];
632
633  // Send a request to gti.pl to get the Excel spreadsheet data
634  text_t gti_arguments = "";
635  if (target_chunk_type == "work") {
636    gti_arguments = "get-first-n-chunks-requiring-work " + target_language_code + " " + translation_file_key + " " + "10000" + " | /opt/jdk1.6.0/bin/java -cp /home/nzdl/gti:/home/nzdl/gti/xalan.jar ApplyXSLT /home/nzdl/gti/gti-generate-excel-xml.xsl -";
637  } else {
638    gti_arguments = "get-all-chunks " + target_language_code + " " + translation_file_key + " | /opt/jdk1.6.0/bin/java -cp /home/nzdl/gti:/home/nzdl/gti/xalan.jar ApplyXSLT /home/nzdl/gti/gti-generate-excel-xml.xsl -";
639  }
640 
641  text_t gti_response_xml_text = do_gti_request(gti_arguments, logout); 
642  if (gti_response_xml_text == "") {
643    // An error has occurred
644    return false;
645  }
646
647  // Write the Excel spreadsheet data to the browser
648  char* gti_response_xml_text_cstr = gti_response_xml_text.getcstr();
649  printf(gti_response_xml_text_cstr);
650  delete[] gti_response_xml_text_cstr;
651
652  return true;
653}
654
655bool gtiaction::produce_glihelp_zipfile(displayclass& disp, cgiargsclass& args, ostream& logout)
656{
657 text_t target_language_code = args["tlc"];
658 text_t gti_arguments = "create-glihelp-zip-file " + target_language_code;
659
660 do_gti_request(gti_arguments, logout);
661
662 disp.setmacro("gtiglihelpzipfilepath", "gti", encodeForURL(target_language_code) + "_GLIHelp.zip");
663
664 return true;
665}
666
667
668text_t gtiaction::escape_all(text_t text_string, char character_to_escape)
669{
670  text_t text_string_escaped = "";
671
672  text_t::iterator text_string_character = text_string.begin();
673  while (text_string_character != text_string.end()) {
674    if (*text_string_character == character_to_escape) {
675      text_string_escaped += "\\";
676    }
677    text_string_escaped.push_back(*text_string_character);
678    text_string_character++;
679  }
680
681  return text_string_escaped;
682}
683
684
685
686char* xml_get_attribute(const char** attributes, char* attribute_name)
687{
688  for (int i = 0; (attributes[i] != NULL); i += 2) {
689    if (strcmp(attribute_name, attributes[i]) == 0) {
690      return strdup(attributes[i+1]);
691    }
692  }
693
694  return NULL;
695}
696
697
698static void XMLCALL gti_response_xml_start_element(void* user_data, const char* element_name_cstr, const char** attributes)
699{
700  GTI_Response* gti_response = (GTI_Response*) user_data;
701  text_t element_name = element_name_cstr;
702  cerr << "In startElement() for " << element_name << endl;
703
704  if (element_name == "GTIError") {
705    gti_response->recorded_text = "";
706    gti_response->is_recording_text = true;
707  }
708
709  if (element_name == "TranslationFile") {
710    int translation_file_index = gti_response->translation_files_index_to_key_mapping.size();
711    gti_response->translation_file_key = xml_get_attribute(attributes, "key");
712    gti_response->translation_files_index_to_key_mapping[translation_file_index] = gti_response->translation_file_key;
713    gti_response->translation_files_key_to_target_file_path_mapping[gti_response->translation_file_key] = xml_get_attribute(attributes, "target_file_path");
714    gti_response->translation_files_key_to_num_chunks_translated_mapping[gti_response->translation_file_key] = xml_get_attribute(attributes, "num_chunks_translated");
715    gti_response->translation_files_key_to_num_chunks_requiring_translation_mapping[gti_response->translation_file_key] = xml_get_attribute(attributes, "num_chunks_requiring_translation");
716    gti_response->translation_files_key_to_num_chunks_requiring_updating_mapping[gti_response->translation_file_key] = xml_get_attribute(attributes, "num_chunks_requiring_updating");
717  }
718
719  if (element_name == "ChunksMatchingQuery") {
720    gti_response->num_chunks_matching_query = xml_get_attribute(attributes, "size");
721  }
722
723  if (element_name == "Chunk") {
724    gti_response->chunk_key = xml_get_attribute(attributes, "key");
725  }
726
727  if (element_name == "SourceFileText") {
728    gti_response->source_file_chunks_key_to_date_mapping[gti_response->chunk_key] = xml_get_attribute(attributes, "date");
729    gti_response->recorded_text = "";
730    gti_response->is_recording_text = true;
731  }
732
733  if (element_name == "TargetFileText") {
734    if (xml_get_attribute(attributes, "date") != NULL) {
735      gti_response->target_file_chunks_key_to_date_mapping[gti_response->chunk_key] = xml_get_attribute(attributes, "date");
736    }
737    gti_response->recorded_text = "";
738    gti_response->is_recording_text = true;
739  }
740}
741
742
743static void XMLCALL gti_response_xml_end_element(void* user_data, const char* element_name_cstr)
744{
745  GTI_Response* gti_response = (GTI_Response*) user_data;
746  text_t element_name = element_name_cstr;
747
748  if (element_name == "GTIError") {
749    gti_response->error_message = to_uni(gti_response->recorded_text);
750    gti_response->is_recording_text = false;
751  }
752
753  if (element_name == "SourceFileText") {
754    gti_response->source_file_chunks_key_to_text_mapping[gti_response->chunk_key] = to_uni(gti_response->recorded_text);
755    gti_response->is_recording_text = false;
756  }
757
758  if (element_name == "TargetFileText") {
759    gti_response->target_file_chunks_key_to_text_mapping[gti_response->chunk_key] = to_uni(gti_response->recorded_text);
760    gti_response->is_recording_text = false;
761  }
762}
763
764
765static void XMLCALL gti_response_xml_character_data(void *user_data, const char* text_cstr, int text_length)
766{
767  GTI_Response* gti_response = (GTI_Response*) user_data;
768  if (gti_response->is_recording_text) {
769    gti_response->recorded_text.appendcarr(text_cstr, text_length);
770  }
771}
772
773
774
775text_t gtiaction::do_gti_request(text_t gti_arguments, ostream& logout)
776{
777  // Send the request to gti.pl and read the XML output
778  text_t gti_command = "perl -S " + filename_cat(gsdlhome, "bin", "script", "gti.pl") + " " + gti_arguments;
779  char* gti_command_cstr = gti_command.getcstr();
780  FILE *gti_pipe = popen(gti_command_cstr, "r");
781  delete[] gti_command_cstr;
782  if (gti_pipe == NULL) {
783    logout << "Error: Could not open pipe for GTI command " << gti_command << endl;
784    return "";
785  }
786
787  // Read the gti.pl response
788  text_t gti_response_xml_text;
789  while (!feof(gti_pipe)) {
790    char buffer[1024];
791    gti_response_xml_text.appendcarr(buffer, fread(buffer, 1, 1024, gti_pipe));
792  }
793  pclose(gti_pipe);
794
795  return gti_response_xml_text;
796}
797
798
799
800GTI_Response gtiaction::parse_gti_response(text_t gti_response_xml_text, ostream& logout)
801{
802  GTI_Response gti_response;
803  gti_response.is_recording_text = false;
804
805  // Parse the gti.pl response (XML)
806  logout << "Parsing GTI command response: " << gti_response_xml_text << endl;
807  XML_Parser xml_parser = XML_ParserCreate(NULL);
808  XML_SetUserData(xml_parser, &gti_response);
809  XML_SetElementHandler(xml_parser, gti_response_xml_start_element, gti_response_xml_end_element);
810  XML_SetCharacterDataHandler(xml_parser, gti_response_xml_character_data);
811
812  char* gti_response_xml_text_cstr = gti_response_xml_text.getcstr();
813  int parse_status = XML_Parse(xml_parser, gti_response_xml_text_cstr, strlen(gti_response_xml_text_cstr), XML_TRUE);
814  delete[] gti_response_xml_text_cstr;
815  if (parse_status == XML_STATUS_ERROR) {
816    logout << "Parse error " << XML_ErrorString(XML_GetErrorCode(xml_parser)) << " at line " << XML_GetCurrentLineNumber(xml_parser) << endl;
817    return gti_response;
818  }
819
820  XML_ParserFree(xml_parser);
821
822  logout << "Finished parse." << endl;
823  return gti_response;
824}
825
826
827
828void gtiaction::do_gti_submission(text_t gti_arguments, text_t gti_submission, ostream& logout)
829{
830  // Send the submission to gti.pl
831  text_t gti_command = "perl -S " + filename_cat(gsdlhome, "bin", "script", "gti.pl") + " " + gti_arguments;
832  char* gti_command_cstr = gti_command.getcstr();
833  FILE *gti_pipe = popen(gti_command_cstr, "w");
834  delete[] gti_command_cstr;
835  if (gti_pipe == NULL) {
836    logout << "Error: Could not open pipe for GTI command " << gti_command << endl;
837    return;
838  }
839
840  // Write the gti.pl submission
841  char* gti_submission_cstr = gti_submission.getcstr();
842  fwrite(gti_submission_cstr, 1, strlen(gti_submission_cstr), gti_pipe);
843  delete[] gti_submission_cstr;
844
845  pclose(gti_pipe);
846}
847
848
849
850#endif  // GSDL_USE_GTI_ACTION
Note: See TracBrowser for help on using the browser.