source: main/trunk/greenstone2/runtime-src/src/recpt/gtiaction.cpp@ 33430

Last change on this file since 33430 was 33430, checked in by ak19, 5 years ago

Undo call to to_utf8() on the query_string argument (arg[q]) to prevent doubly encoding the query_string argument as this modified the query string, in those cases where arg[q] contains characters outside those used in the script for English. As a result of the double encoding, the user's search term is not found. Doesn't fix the final remaining part of the problem: whereby the query term still looks modified (strangely encoded) to the user in the search box when the search results are displayed. That part of the problem still needs investigating and will committed after it gets fixed

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