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

Revision 28913, 34.1 KB (checked in by ak19, 6 years ago)

6th commit for security of cgiargs. Looked over all occurrences of setmacro in *action.cpp files

  • 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" + translation_file_key + "_");
389  disp.setmacro("gtitranslationfiledescHtmlsafe", "gti", "_gti:textgti" + encodeForHTML(translation_file_key) + "_");
390
391  if (query_string == "") {
392    // No query, so no search results
393    disp.setmacro("gtifindformcontent", "gti", "");
394    return;
395  }
396
397  // Display text right to left if target language is Arabic or Farsi or Urdu
398  if (target_language_code == "ar" || target_language_code == "fa" || target_language_code == "ur") {
399    disp.setmacro("gtitextdirection", "gti", "rtl");
400  }
401  else {
402    disp.setmacro("gtitextdirection", "gti", "ltr");
403  }
404
405  // Send a request to gti.pl to get the valid translation files
406  logout << "Query argument: " << query_string << endl;
407  text_t gti_arguments = "search-chunks " + target_language_code + " " + translation_file_key + " " + query_string;
408  GTI_Response gti_response = parse_gti_response(do_gti_request(gti_arguments, logout), logout);
409  if (gti_response.error_message != "") {
410    // An error has occurred
411    disp.setmacro("gtiformcontent", "gti", "_gti:gtierror_");
412    disp.setmacro("gtierrormessage", "gti", gti_response.error_message);
413    return;
414  }
415
416  disp.setmacro("gtinumchunksmatchingquery", "gti", gti_response.num_chunks_matching_query);
417
418  // Loop through the chunks returned, displaying them on the page
419  text_t gti_find_form_content = "_gtifindformheader_\n";
420  text_tmap::iterator chunk_key_iterator = gti_response.target_file_chunks_key_to_text_mapping.begin();
421  while (chunk_key_iterator != gti_response.target_file_chunks_key_to_text_mapping.end()) {
422    text_t chunk_key = chunk_key_iterator->first;
423
424    // Need to escape any underscores in the chunk key to show it correctly on the page
425    text_t chunk_key_escaped = escape_all(chunk_key, '_');
426
427    // Need to escape any backslashes, underscores, commas, parentheses, and single quotes in the chunk text
428    text_t target_file_chunk_text = gti_response.target_file_chunks_key_to_text_mapping[chunk_key];
429    text_t target_file_chunk_text_escaped = escape_all(target_file_chunk_text, '\\');
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    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, '\'');
436
437    // This chunk matches the query
438    gti_find_form_content += "_gtichunkmatchingquery_(" + chunk_key_escaped + "," + target_file_chunk_text_escaped + ")\n";
439
440    chunk_key_iterator++;
441  }
442  gti_find_form_content += "_gtifindformfooter_\n";
443
444  disp.setmacro("gtifindformcontent", "gti", gti_find_form_content);
445}
446
447
448
449void gtiaction::define_gti_offline_page(displayclass& disp, cgiargsclass& args, ostream& logout)
450{
451  // Get the target language code and file to translate from the CGI arguments
452  text_t target_language_code = args["tlc"];
453  text_t translation_file_key = args["tfk"];
454
455  disp.setmacro("gtiformcontent", "gti", "_gti:gtioffline_");
456
457  languageinfo_tmap loaded_languages = recpt->get_configinfo().languages;
458  disp.setmacro("gtitargetlanguagename", "gti", loaded_languages[target_language_code].longname);
459  disp.setmacro("gtitranslationfiledesc", "gti", "_gti:textgti" + translation_file_key + "_");
460  disp.setmacro("gtitranslationfiledescHtmlsafe", "gti", "_gti:textgti" + encodeForHTML(translation_file_key) + "_");
461}
462
463
464
465void gtiaction::define_gti_core_page(displayclass& disp, cgiargsclass& args, ostream& logout)
466{
467  // Get the target language code and file to translate from the CGI arguments
468  text_t target_language_code = args["tlc"];
469  text_t translation_file_key = args["tfk"];
470  text_t num_chunks_per_page = args["ncpp"];
471  logout << "Num chunks per page: " << num_chunks_per_page << endl;
472
473  disp.setmacro("gtiformcontent", "gti", "_gti:gticore_");
474
475  // Display text right to left if target language is Arabic or Farsi or Urdu
476  if (target_language_code == "ar" || target_language_code == "fa" || target_language_code == "ur") {
477    disp.setmacro("gtitextdirection", "gti", "rtl");
478  }
479  else {
480    disp.setmacro("gtitextdirection", "gti", "ltr");
481  }
482
483  // Send a request to gti.pl to get the first string to translate
484  text_t gti_arguments = "get-first-n-chunks-requiring-work " + target_language_code + " " + translation_file_key + " " + num_chunks_per_page;
485  GTI_Response gti_response = parse_gti_response(do_gti_request(gti_arguments, logout), logout);
486  if (gti_response.error_message != "") {
487    // An error has occurred
488    disp.setmacro("gtiformcontent", "gti", "_gti:gtierror_");
489    disp.setmacro("gtierrormessage", "gti", gti_response.error_message);
490    return;
491  }
492
493  languageinfo_tmap loaded_languages = recpt->get_configinfo().languages;
494  disp.setmacro("gtitargetlanguagename", "gti", loaded_languages[target_language_code].longname);
495  if (translation_file_key == "glihelp") {
496    disp.setmacro("gtitargetfilepath", "gti", "_gtidownloadglihelp_");
497  } else {
498    disp.setmacro("gtitargetfilepath", "gti", gti_response.translation_files_key_to_target_file_path_mapping[translation_file_key]);
499  }
500  disp.setmacro("gtitranslationfiledesc", "gti", "_gti:textgti" + translation_file_key + "_");
501  disp.setmacro("gtitranslationfiledescHtmlsafe", "gti", "_gti:textgti" + encodeForHTML(translation_file_key) + "_");
502  disp.setmacro("gtiviewtranslationfileinaction", "gti", "_gti:gtiview" + translation_file_key + "inaction_");
503  disp.setmacro("gtiviewtranslationfileinactionHtmlsafe", "gti", "_gti:gtiview" + encodeForHTML(translation_file_key) + "inaction_");
504
505  disp.setmacro("gtinumchunkstranslated", "gti", gti_response.translation_files_key_to_num_chunks_translated_mapping[translation_file_key]);
506  disp.setmacro("gtinumchunksrequiringtranslation", "gti", gti_response.translation_files_key_to_num_chunks_requiring_translation_mapping[translation_file_key]);
507  disp.setmacro("gtinumchunksrequiringupdating", "gti", gti_response.translation_files_key_to_num_chunks_requiring_updating_mapping[translation_file_key]);
508
509  // Check if the translation file is finished
510  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") {
511    disp.setmacro("gtiformcontent", "gti", "_gti:gtidone_");
512    return;
513  }
514
515  // Loop through the chunks returned, displaying them on the page
516  text_t gti_core_form_content = "";
517  text_tmap::iterator chunk_key_iterator = gti_response.source_file_chunks_key_to_text_mapping.begin();
518  while (chunk_key_iterator != gti_response.source_file_chunks_key_to_text_mapping.end()) {
519    text_t chunk_key = chunk_key_iterator->first;
520
521    // Need to escape any underscores in the chunk key to show it correctly on the page
522    text_t chunk_key_escaped = escape_all(chunk_key, '_');
523
524    // Need to escape any backslashes, underscores, commas, parentheses, and single quotes in the chunk text
525    text_t source_file_chunk_text = gti_response.source_file_chunks_key_to_text_mapping[chunk_key];
526    text_t source_file_chunk_text_escaped = escape_all(source_file_chunk_text, '\\');
527    source_file_chunk_text_escaped = escape_all(source_file_chunk_text_escaped, '_');
528    source_file_chunk_text_escaped = escape_all(source_file_chunk_text_escaped, ',');
529    source_file_chunk_text_escaped = escape_all(source_file_chunk_text_escaped, '(');
530    source_file_chunk_text_escaped = escape_all(source_file_chunk_text_escaped, ')');
531    source_file_chunk_text_escaped = escape_all(source_file_chunk_text_escaped, '\'');
532    text_t target_file_chunk_text = gti_response.target_file_chunks_key_to_text_mapping[chunk_key];
533    text_t target_file_chunk_text_escaped = escape_all(target_file_chunk_text, '\\');
534    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, '_');
535    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, ',');
536    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, '(');
537    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, ')');
538    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, '\'');
539
540    text_t source_file_chunk_date = gti_response.source_file_chunks_key_to_date_mapping[chunk_key];
541    text_t target_file_chunk_date = gti_response.target_file_chunks_key_to_date_mapping[chunk_key];
542
543    // This chunk requires translation
544    if (target_file_chunk_text == "") {
545      gti_core_form_content += "_gtichunkrequiringtranslation_(" + chunk_key_escaped + "," + source_file_chunk_text_escaped + "," + source_file_chunk_date + ")\n";
546    }
547    // This chunk requires updating
548    else {
549      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";
550    }
551
552    chunk_key_iterator++;
553  }
554
555  disp.setmacro("gticoreformcontent", "gti", gti_core_form_content);
556}
557
558
559
560void gtiaction::process_gti_submissions(displayclass& disp, cgiargsclass& args, ostream& logout, bool force_submission)
561{
562  // Get the target language code and file to translate from the CGI arguments
563  text_t target_language_code = args["tlc"];
564  text_t translation_file_key = args["tfk"];
565  text_t submitter_username = args["un"];
566
567  // Submitted chunk arguments contain the language code followed by "::"
568  char* source_chunk_key_start_cstr = ((text_t) "en" + "%3A%3A").getcstr();
569  char* target_chunk_key_start_cstr = (target_language_code + "%3A%3A").getcstr();
570
571  // Find the cgi arguments with submitted chunk information
572  text_t submission_text;
573  cgiargsclass::const_iterator cgi_argument = args.begin();
574  while (cgi_argument != args.end()) {
575    char* cgi_argument_name_cstr = cgi_argument->first.getcstr();
576
577    // Source file text
578    if (strncmp(cgi_argument_name_cstr, source_chunk_key_start_cstr, strlen(source_chunk_key_start_cstr)) == 0) {
579      submission_text += "<SourceFileText key=\"";
580      text_t source_key = &cgi_argument_name_cstr[strlen(source_chunk_key_start_cstr)];
581      decode_cgi_arg(source_key);
582      submission_text += source_key;
583      //submission_text += &cgi_argument_name_cstr[strlen(source_chunk_key_start_cstr)];
584      submission_text += "\">\n";
585
586      text_t source_value = xml_safe(decode_commas(args[cgi_argument->first]));
587      // if (args["w"] != "utf-8") {
588      // source_value = to_utf8(source_value);
589      // }
590      submission_text += source_value + "\n";
591      submission_text += "</SourceFileText>\n";
592    }
593    // Target file text
594    if (strncmp(cgi_argument_name_cstr, target_chunk_key_start_cstr, strlen(target_chunk_key_start_cstr)) == 0) {
595      submission_text += "<TargetFileText key=\"";
596      text_t target_key = &cgi_argument_name_cstr[strlen(target_chunk_key_start_cstr)];
597      decode_cgi_arg(target_key);
598      submission_text += target_key;
599      //submission_text += &cgi_argument_name_cstr[strlen(target_chunk_key_start_cstr)];
600      submission_text += "\">\n";
601
602      text_t target_value = xml_safe(decode_commas(args[cgi_argument->first]));
603      // if (args["w"] != "utf-8") {
604      // target_value = to_utf8(target_value);
605      // }
606      submission_text += target_value + "\n";
607      submission_text += "</TargetFileText>\n";
608    }
609
610    delete[] cgi_argument_name_cstr;
611    ++cgi_argument;
612  }
613
614  logout << "Submission text: " << submission_text << endl;
615
616  // Send the submission to gti.pl
617  text_t gti_arguments = "submit-translations " + target_language_code + " " + translation_file_key + " " + submitter_username;
618  if (force_submission) {
619    gti_arguments += " -force_submission";
620  }
621  do_gti_submission(gti_arguments, submission_text, logout);
622  logout << "Done." << endl;
623
624  delete[] source_chunk_key_start_cstr;
625  delete[] target_chunk_key_start_cstr;
626}
627
628
629
630bool gtiaction::produce_excel_spreadsheet(cgiargsclass& args, ostream& logout)
631{
632  // Get the target language code and file to translate from the CGI arguments
633  text_t target_language_code = args["tlc"];
634  text_t translation_file_key = args["tfk"];
635  text_t target_chunk_type = args["tct"];
636
637  // Send a request to gti.pl to get the Excel spreadsheet data
638  text_t gti_arguments = "";
639  if (target_chunk_type == "work") {
640    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 -";
641  } else {
642    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 -";
643  }
644 
645  text_t gti_response_xml_text = do_gti_request(gti_arguments, logout); 
646  if (gti_response_xml_text == "") {
647    // An error has occurred
648    return false;
649  }
650
651  // Write the Excel spreadsheet data to the browser
652  char* gti_response_xml_text_cstr = gti_response_xml_text.getcstr();
653  printf(gti_response_xml_text_cstr);
654  delete[] gti_response_xml_text_cstr;
655
656  return true;
657}
658
659bool gtiaction::produce_glihelp_zipfile(displayclass& disp, cgiargsclass& args, ostream& logout)
660{
661 text_t target_language_code = args["tlc"];
662 text_t gti_arguments = "create-glihelp-zip-file " + target_language_code;
663
664 do_gti_request(gti_arguments, logout);
665
666 disp.setmacro("gtiglihelpzipfilepath", "gti", target_language_code + "_GLIHelp.zip");
667 disp.setmacro("gtiglihelpzipfilepathUrlsafe", "gti", encodeForURL(target_language_code) + "_GLIHelp.zip");
668
669 return true;
670}
671
672
673text_t gtiaction::escape_all(text_t text_string, char character_to_escape)
674{
675  text_t text_string_escaped = "";
676
677  text_t::iterator text_string_character = text_string.begin();
678  while (text_string_character != text_string.end()) {
679    if (*text_string_character == character_to_escape) {
680      text_string_escaped += "\\";
681    }
682    text_string_escaped.push_back(*text_string_character);
683    text_string_character++;
684  }
685
686  return text_string_escaped;
687}
688
689
690
691char* xml_get_attribute(const char** attributes, char* attribute_name)
692{
693  for (int i = 0; (attributes[i] != NULL); i += 2) {
694    if (strcmp(attribute_name, attributes[i]) == 0) {
695      return strdup(attributes[i+1]);
696    }
697  }
698
699  return NULL;
700}
701
702
703static void XMLCALL gti_response_xml_start_element(void* user_data, const char* element_name_cstr, const char** attributes)
704{
705  GTI_Response* gti_response = (GTI_Response*) user_data;
706  text_t element_name = element_name_cstr;
707  cerr << "In startElement() for " << element_name << endl;
708
709  if (element_name == "GTIError") {
710    gti_response->recorded_text = "";
711    gti_response->is_recording_text = true;
712  }
713
714  if (element_name == "TranslationFile") {
715    int translation_file_index = gti_response->translation_files_index_to_key_mapping.size();
716    gti_response->translation_file_key = xml_get_attribute(attributes, "key");
717    gti_response->translation_files_index_to_key_mapping[translation_file_index] = gti_response->translation_file_key;
718    gti_response->translation_files_key_to_target_file_path_mapping[gti_response->translation_file_key] = xml_get_attribute(attributes, "target_file_path");
719    gti_response->translation_files_key_to_num_chunks_translated_mapping[gti_response->translation_file_key] = xml_get_attribute(attributes, "num_chunks_translated");
720    gti_response->translation_files_key_to_num_chunks_requiring_translation_mapping[gti_response->translation_file_key] = xml_get_attribute(attributes, "num_chunks_requiring_translation");
721    gti_response->translation_files_key_to_num_chunks_requiring_updating_mapping[gti_response->translation_file_key] = xml_get_attribute(attributes, "num_chunks_requiring_updating");
722  }
723
724  if (element_name == "ChunksMatchingQuery") {
725    gti_response->num_chunks_matching_query = xml_get_attribute(attributes, "size");
726  }
727
728  if (element_name == "Chunk") {
729    gti_response->chunk_key = xml_get_attribute(attributes, "key");
730  }
731
732  if (element_name == "SourceFileText") {
733    gti_response->source_file_chunks_key_to_date_mapping[gti_response->chunk_key] = xml_get_attribute(attributes, "date");
734    gti_response->recorded_text = "";
735    gti_response->is_recording_text = true;
736  }
737
738  if (element_name == "TargetFileText") {
739    if (xml_get_attribute(attributes, "date") != NULL) {
740      gti_response->target_file_chunks_key_to_date_mapping[gti_response->chunk_key] = xml_get_attribute(attributes, "date");
741    }
742    gti_response->recorded_text = "";
743    gti_response->is_recording_text = true;
744  }
745}
746
747
748static void XMLCALL gti_response_xml_end_element(void* user_data, const char* element_name_cstr)
749{
750  GTI_Response* gti_response = (GTI_Response*) user_data;
751  text_t element_name = element_name_cstr;
752
753  if (element_name == "GTIError") {
754    gti_response->error_message = to_uni(gti_response->recorded_text);
755    gti_response->is_recording_text = false;
756  }
757
758  if (element_name == "SourceFileText") {
759    gti_response->source_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  if (element_name == "TargetFileText") {
764    gti_response->target_file_chunks_key_to_text_mapping[gti_response->chunk_key] = to_uni(gti_response->recorded_text);
765    gti_response->is_recording_text = false;
766  }
767}
768
769
770static void XMLCALL gti_response_xml_character_data(void *user_data, const char* text_cstr, int text_length)
771{
772  GTI_Response* gti_response = (GTI_Response*) user_data;
773  if (gti_response->is_recording_text) {
774    gti_response->recorded_text.appendcarr(text_cstr, text_length);
775  }
776}
777
778
779
780text_t gtiaction::do_gti_request(text_t gti_arguments, ostream& logout)
781{
782  // Send the request to gti.pl and read the XML output
783  text_t gti_command = "perl -S " + filename_cat(gsdlhome, "bin", "script", "gti.pl") + " " + gti_arguments;
784  char* gti_command_cstr = gti_command.getcstr();
785  FILE *gti_pipe = popen(gti_command_cstr, "r");
786  delete[] gti_command_cstr;
787  if (gti_pipe == NULL) {
788    logout << "Error: Could not open pipe for GTI command " << gti_command << endl;
789    return "";
790  }
791
792  // Read the gti.pl response
793  text_t gti_response_xml_text;
794  while (!feof(gti_pipe)) {
795    char buffer[1024];
796    gti_response_xml_text.appendcarr(buffer, fread(buffer, 1, 1024, gti_pipe));
797  }
798  pclose(gti_pipe);
799
800  return gti_response_xml_text;
801}
802
803
804
805GTI_Response gtiaction::parse_gti_response(text_t gti_response_xml_text, ostream& logout)
806{
807  GTI_Response gti_response;
808  gti_response.is_recording_text = false;
809
810  // Parse the gti.pl response (XML)
811  logout << "Parsing GTI command response: " << gti_response_xml_text << endl;
812  XML_Parser xml_parser = XML_ParserCreate(NULL);
813  XML_SetUserData(xml_parser, &gti_response);
814  XML_SetElementHandler(xml_parser, gti_response_xml_start_element, gti_response_xml_end_element);
815  XML_SetCharacterDataHandler(xml_parser, gti_response_xml_character_data);
816
817  char* gti_response_xml_text_cstr = gti_response_xml_text.getcstr();
818  int parse_status = XML_Parse(xml_parser, gti_response_xml_text_cstr, strlen(gti_response_xml_text_cstr), XML_TRUE);
819  delete[] gti_response_xml_text_cstr;
820  if (parse_status == XML_STATUS_ERROR) {
821    logout << "Parse error " << XML_ErrorString(XML_GetErrorCode(xml_parser)) << " at line " << XML_GetCurrentLineNumber(xml_parser) << endl;
822    return gti_response;
823  }
824
825  XML_ParserFree(xml_parser);
826
827  logout << "Finished parse." << endl;
828  return gti_response;
829}
830
831
832
833void gtiaction::do_gti_submission(text_t gti_arguments, text_t gti_submission, ostream& logout)
834{
835  // Send the submission to gti.pl
836  text_t gti_command = "perl -S " + filename_cat(gsdlhome, "bin", "script", "gti.pl") + " " + gti_arguments;
837  char* gti_command_cstr = gti_command.getcstr();
838  FILE *gti_pipe = popen(gti_command_cstr, "w");
839  delete[] gti_command_cstr;
840  if (gti_pipe == NULL) {
841    logout << "Error: Could not open pipe for GTI command " << gti_command << endl;
842    return;
843  }
844
845  // Write the gti.pl submission
846  char* gti_submission_cstr = gti_submission.getcstr();
847  fwrite(gti_submission_cstr, 1, strlen(gti_submission_cstr), gti_pipe);
848  delete[] gti_submission_cstr;
849
850  pclose(gti_pipe);
851}
852
853
854
855#endif  // GSDL_USE_GTI_ACTION
Note: See TracBrowser for help on using the browser.