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

Revision 28973, 36.3 KB (checked in by ak19, 6 years ago)

All the changes required to get the GTI installed on a local greenstone using the latest gs2 src code from svn, since this has the security updates. 1. ApplyXSLT in build-src needed a lot of code additions since runtime-src's gtiaction.cpp needs to send the xml file from stdin using a pipe command. ApplyXSLT used to read stdin from a piped cmd differently, expecting DocStart? and DocEnd? embedding tags to mark the start and stop of each stream. This is still used by code in BasePlugout?, so ApplyXSLT has been modified to take a minus-c parameter when requested to read from stdin without special embedding tag markers, such as when gtiaction calls it. ApplyXSLT uses an internal StreamGobbler? class to read the stdin since it takes a while for xml generated by the gti.pl (which is piped in) to come in to ApplyXSLT. 2. The inner StreamGobbler? class needed to be added into the ApplyXSLT jar file, so the Makefile.in has been updated. 3. In runtime-src, added in missing header files and updated the code that generated the spreadsheets on GTI, since it was firstly hardcoded to use paths on /home/nzdl, and the code that generated the spreadsheets when running ApplyXSLT/xalan.jar no longer worked as it had been coded.

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