33 #include <libxml/xpath.h>
34 #include <libxml/xpathInternals.h>
35 #include <libxslt/xsltutils.h>
45 #define G_LOG_DOMAIN "gsad xslt"
47 #ifndef GETTEXT_CONTEXT_GLUE
48 #define GETTEXT_CONTEXT_GLUE "\004"
54 #define GSA_I18N_EXT_URI "http://openvas.org/i18n"
59 #define GSA_XSL_TEXTDOMAIN "gsad_xsl"
64 static GMutex locale_env_mutex;
69 static int ext_gettext_enabled = 0;
74 static GList *installed_languages = NULL;
79 static GHashTable *language_names = NULL;
80 static GHashTable *native_language_names = NULL;
89 xslt_ext_gettext (xmlXPathParserContextPtr ctxt,
92 xmlXPathObjectPtr lang_obj, msgid_obj, context_obj;
94 xmlXPathObjectPtr result_obj;
103 if (nargs < 2 || nargs > 3)
105 xsltGenericError (xsltGenericErrorContext,
106 "gettext : Expected 2 or 3 arguments, got %d\n",
113 context_obj = valuePop (ctxt);
114 if (context_obj->type != XPATH_STRING)
116 valuePush (ctxt, context_obj);
117 xmlXPathStringFunction (ctxt, 1);
118 context_obj = valuePop (ctxt);
124 msgid_obj = valuePop (ctxt);
125 if (msgid_obj->type != XPATH_STRING)
127 valuePush (ctxt, msgid_obj);
128 xmlXPathStringFunction (ctxt, 1);
129 msgid_obj = valuePop (ctxt);
132 lang_obj = valuePop (ctxt);
133 if (lang_obj->type != XPATH_STRING)
135 valuePush (ctxt, lang_obj);
136 xmlXPathStringFunction (ctxt, 1);
137 lang_obj = valuePop (ctxt);
140 if (ext_gettext_enabled == 0)
142 valuePush (ctxt, msgid_obj);
144 xmlXPathFreeObject (lang_obj);
146 xmlXPathFreeObject (context_obj);
151 if (msgid_obj->stringval && strcmp ((
char*) msgid_obj->stringval,
""))
156 char *gettext_result = NULL;
158 g_mutex_lock (&locale_env_mutex);
160 old_locale = g_strdup (setlocale (LC_ALL, NULL));
161 old_LANGUAGE = getenv (
"LANGUAGE");
162 setenv (
"LANGUAGE", (
char*)lang_obj->stringval, 1);
163 setlocale (LC_ALL,
"");
166 msgid = g_strdup_printf (
"%s%s%s",
167 (gchar*) context_obj->stringval,
169 (gchar*) msgid_obj->stringval);
171 msgid = g_strdup ((gchar*) msgid_obj->stringval);
174 gettext_result = gettext (msgid);
175 result_str = (xmlChar*) g_strdup ((gettext_result != msgid)
181 setenv (
"LANGUAGE", old_LANGUAGE, 1);
183 unsetenv (
"LANGUAGE");
184 setlocale (LC_ALL, old_locale);
187 g_mutex_unlock (&locale_env_mutex);
190 result_str = (xmlChar*) g_strdup (
"");
192 result_obj = xmlXPathNewString (result_str);
194 xmlXPathFreeObject (lang_obj);
195 xmlXPathFreeObject (msgid_obj);
197 xmlXPathFreeObject (context_obj);
200 valuePush (ctxt, result_obj);
210 xslt_ext_ngettext (xmlXPathParserContextPtr ctxt,
213 xmlXPathObjectPtr lang_obj, msgid_obj, msgid_pl_obj, count_obj, context_obj;
215 xmlXPathObjectPtr result_obj;
226 if (nargs < 4 || nargs > 5)
228 xsltGenericError (xsltGenericErrorContext,
229 "ngettext : Expected 4 or 5 arguments, got %d\n",
236 context_obj = valuePop (ctxt);
237 if (context_obj->type != XPATH_STRING)
239 valuePush (ctxt, context_obj);
240 xmlXPathStringFunction (ctxt, 1);
241 context_obj = valuePop (ctxt);
247 count_obj = valuePop (ctxt);
248 if (count_obj->type != XPATH_NUMBER)
250 valuePush (ctxt, count_obj);
251 xmlXPathNumberFunction (ctxt, 1);
252 count_obj = valuePop (ctxt);
254 if (count_obj->type != XPATH_NUMBER || isnan (count_obj->floatval))
255 xsltGenericError (xsltGenericErrorContext,
256 "ngettext : 4th argument cannot be converted"
257 " to a valid number\n");
260 msgid_pl_obj = valuePop (ctxt);
261 if (msgid_pl_obj->type != XPATH_STRING)
263 valuePush (ctxt, msgid_pl_obj);
264 xmlXPathStringFunction (ctxt, 1);
265 msgid_pl_obj = valuePop (ctxt);
268 msgid_obj = valuePop (ctxt);
269 if (msgid_obj->type != XPATH_STRING)
271 valuePush (ctxt, msgid_obj);
272 xmlXPathStringFunction (ctxt, 1);
273 msgid_obj = valuePop (ctxt);
276 lang_obj = valuePop (ctxt);
277 if (lang_obj->type != XPATH_STRING)
279 valuePush (ctxt, lang_obj);
280 xmlXPathStringFunction (ctxt, 1);
281 lang_obj = valuePop (ctxt);
284 if (ext_gettext_enabled == 0)
288 count = (
unsigned long) count_obj->floatval;
292 xmlXPathFreeObject (msgid_pl_obj);
293 valuePush (ctxt, msgid_obj);
297 xmlXPathFreeObject (msgid_obj);
298 valuePush (ctxt, msgid_pl_obj);
301 xmlXPathFreeObject (lang_obj);
302 xmlXPathFreeObject (count_obj);
304 xmlXPathFreeObject (context_obj);
309 if (msgid_obj->stringval && strcmp ((
char*) msgid_obj->stringval,
""))
314 gchar *msgid_pl = NULL;
316 char *gettext_result = NULL;
318 g_mutex_lock (&locale_env_mutex);
320 old_locale = g_strdup (setlocale (LC_ALL, NULL));
321 old_LANGUAGE = getenv (
"LANGUAGE");
322 setenv (
"LANGUAGE", (
char*)lang_obj->stringval, 1);
323 setlocale (LC_ALL,
"");
326 msgid = g_strdup_printf (
"%s%s%s",
327 (gchar*) context_obj->stringval,
329 (gchar*) msgid_obj->stringval);
331 msgid = g_strdup ((gchar*) msgid_obj->stringval);
333 if (context_obj && context_obj->stringval)
334 msgid_pl = g_strdup_printf (
"%s%s%s",
335 (gchar*) context_obj->stringval,
337 (gchar*) msgid_pl_obj->stringval);
339 msgid_pl = g_strdup ((gchar*) msgid_pl_obj->stringval);
341 count = (
unsigned long) count_obj->floatval;
344 gettext_result = ngettext (msgid, msgid_pl, count);
345 result_str = (xmlChar*) g_strdup ((gettext_result != msgid
346 && gettext_result != msgid_pl)
352 setenv (
"LANGUAGE", old_LANGUAGE, 1);
354 unsetenv (
"LANGUAGE");
355 setlocale (LC_ALL, old_locale);
358 g_mutex_unlock (&locale_env_mutex);
361 result_str = (xmlChar*) g_strdup (
"");
363 result_obj = xmlXPathNewString (result_str);
365 xmlXPathFreeObject (lang_obj);
366 xmlXPathFreeObject (msgid_obj);
367 xmlXPathFreeObject (msgid_pl_obj);
368 xmlXPathFreeObject (count_obj);
370 xmlXPathFreeObject (context_obj);
373 valuePush (ctxt, result_obj);
383 xslt_ext_strformat (xmlXPathParserContextPtr ctxt,
387 int i, pos, format_string_len, in_string_number;
388 xmlXPathObjectPtr format_string_obj, result_obj;
389 gchar *format_string;
390 GString *result_str, *number_str;
398 format_args = g_array_sized_new (TRUE, TRUE,
sizeof (gchar*), nargs-1);
400 for (i = 0; i < nargs-1; i++)
402 xmlXPathObjectPtr format_arg_obj;
405 format_arg_obj = valuePop (ctxt);
406 if (format_arg_obj->type != XPATH_STRING)
408 valuePush (ctxt, format_arg_obj);
409 xmlXPathStringFunction (ctxt, 1);
410 format_arg_obj = valuePop (ctxt);
413 new_string = g_strdup ((gchar*) format_arg_obj->stringval);
414 g_array_prepend_val (format_args, new_string);
415 xmlXPathFreeObject (format_arg_obj);
416 format_arg_obj = NULL;
419 format_string_obj = valuePop (ctxt);
420 if (format_string_obj->type != XPATH_STRING)
422 valuePush (ctxt, format_string_obj);
423 xmlXPathStringFunction (ctxt, 1);
424 format_string_obj = valuePop (ctxt);
426 format_string = g_strdup ((gchar*) format_string_obj->stringval);
427 xmlXPathFreeObject (format_string_obj);
429 result_str = g_string_sized_new (strlen (format_string));
430 number_str = g_string_sized_new (3);
431 format_string_len = strlen (format_string);
432 in_string_number = 0;
434 for (pos = 0; pos <= format_string_len; pos++)
436 if (in_string_number)
438 if (format_string [pos] >=
'0' && format_string [pos] <=
'9')
440 g_string_append_c (number_str, format_string [pos]);
444 int arg_number = atoi (number_str->str);
446 if (arg_number > 0 && arg_number <= format_args->len)
448 g_string_append (result_str,
449 g_array_index (format_args, gchar*,
453 g_string_append_c (result_str, format_string [pos]);
454 g_string_erase (number_str, 0, number_str->len);
455 in_string_number = 0;
460 if (format_string [pos] ==
'%')
461 in_string_number = 1;
463 g_string_append_c (result_str, format_string [pos]);
467 result_obj = xmlXPathNewString ((xmlChar*) result_str->str);
470 guint index = format_args->len;
472 g_free (g_array_index (format_args, gchar*, index));
473 g_array_free (format_args, TRUE);
475 g_free (format_string);
476 g_string_free (number_str, TRUE);
477 g_string_free (result_str, TRUE);
478 valuePush (ctxt, result_obj);
488 init_i18n_module (xsltTransformContextPtr ctxt,
491 xsltRegisterExtFunction (ctxt,
492 (xmlChar*)
"gettext",
496 xsltRegisterExtFunction (ctxt,
497 (xmlChar*)
"ngettext",
501 xsltRegisterExtFunction (ctxt,
502 (xmlChar*)
"strformat",
517 shutdown_i18n_module (xsltTransformContextPtr ctxt,
521 xsltUnregisterExtModuleFunction ((xmlChar*)
"gettext",
523 xsltUnregisterExtModuleFunction ((xmlChar*)
"ngettext",
525 xsltUnregisterExtModuleFunction ((xmlChar*)
"strformat",
535 g_debug (
"Registering i18n XSLT module");
539 shutdown_i18n_module);
546 g_critical (
"%s: Failed to bind text domain for gettext", __FUNCTION__);
560 return ext_gettext_enabled;
571 ext_gettext_enabled = (enabled != 0);
582 FILE *lang_names_file;
583 const char *locale_dir_name;
585 struct dirent *entry;
587 if (installed_languages != NULL)
589 g_warning (
"%s: Language lists already initialized.", __FUNCTION__);
594 language_names = g_hash_table_new_full (g_str_hash, g_str_equal,
597 native_language_names = g_hash_table_new_full (g_str_hash, g_str_equal,
603 installed_languages = g_list_append (installed_languages,
604 g_strdup (
"Browser Language"));
605 installed_languages = g_list_append (installed_languages,
607 g_hash_table_insert (language_names,
608 g_strdup (
"Browser Language"),
609 g_strdup (
"Browser Language"));
610 g_hash_table_insert (native_language_names,
611 g_strdup (
"Browser Language"),
612 g_strdup (
"Browser Language"));
613 g_hash_table_insert (language_names,
614 g_strdup (
"en"), g_strdup (
"English"));
615 g_hash_table_insert (native_language_names,
616 g_strdup (
"en"), g_strdup (
"English"));
619 lang_names_file = fopen (GSA_DATA_DIR
"/language_names.tsv",
"r");
624 while (getline (&line, &len, lang_names_file) != -1)
627 if (line [0] !=
'\0' && line [0] !=
'#')
630 gchar *code, *name, *native_name;
631 columns = g_strsplit (line,
"\t", 3);
633 name = code ? columns [1] : NULL;
634 native_name = name ? columns [2] : NULL;
636 g_hash_table_insert (language_names,
639 if (code && native_name)
640 g_hash_table_insert (native_language_names,
642 g_strdup (native_name));
643 g_strfreev (columns);
648 fclose (lang_names_file);
652 g_warning (
"%s: Failed to open language names file: %s",
653 __FUNCTION__, strerror (errno));
659 locale_dir = opendir (locale_dir_name);
661 if (locale_dir == NULL)
663 g_warning (
"%s: Failed to open locale directory \"%s\": %s",
664 __FUNCTION__, GSA_LOCALE_DIR, strerror (errno));
668 while ((entry = readdir (locale_dir)) != 0)
670 if (entry->d_name[0] !=
'.'
671 && strlen (entry->d_name) >= 2
672 && entry->d_type == DT_DIR
673 && strcmp (entry->d_name,
"en")
674 && strcmp (entry->d_name,
"Browser Language"))
678 lang_mo_path = g_build_filename (locale_dir_name,
684 mo_file = fopen (lang_mo_path,
"r");
689 = g_list_insert_sorted (installed_languages,
690 g_strdup (entry->d_name),
691 (GCompareFunc) strcmp);
696 g_warning (
"%s: Failed to open %s: %s",
697 __FUNCTION__, lang_mo_path, strerror (errno));
699 g_free (lang_mo_path);
702 closedir (locale_dir);
704 GString *test = g_string_new (
"");
706 g_debug (
"%s: Initialized language lists", __FUNCTION__);
707 g_string_free (test, TRUE);
723 langs_list = g_list_first (installed_languages);
725 g_string_append (buffer,
"<gsa_languages>");
728 gchar *lang_code, *lang_name, *native_name, *language_escaped;
730 lang_code = (gchar*) langs_list->data;
732 lang_name = g_hash_table_lookup (language_names, lang_code);
733 if (lang_name == NULL)
734 lang_name = lang_code;
736 native_name = g_hash_table_lookup (native_language_names, lang_code);
737 if (native_name == NULL)
738 native_name = lang_name;
741 = g_markup_printf_escaped (
"<language>"
744 "<native_name>%s</native_name>"
749 g_string_append (buffer, language_escaped);
750 g_free (language_escaped);
751 langs_list = g_list_nth (langs_list, 1);
753 g_string_append (buffer,
"</gsa_languages>");
771 if (accept_language == NULL)
777 gchar **prefs, *pref;
778 prefs = g_strsplit_set (accept_language,
",;", -1);
786 while (pos[0] !=
'\0')
#define GSA_I18N_EXT_URI
Namespace URI for the i18n XSLT extension.
int get_ext_gettext_enabled()
Get whether gettext functions for extensions are enabled.
void set_ext_gettext_enabled(int enabled)
Enable or disable gettext functions for extensions.
#define DEFAULT_GSAD_LANGUAGE
Default language code, used when Accept-Language header is missing.
gchar * accept_language_to_env_fmt(const char *accept_language)
Convert an Accept-Language string to the LANGUAGE env variable form.
void register_i18n_ext_module()
Register the i18n XSLT extension module.
Headers/structs used generally in GSA.
#define GSA_XSL_TEXTDOMAIN
int init_language_lists()
Initialize the list of available languages.
int get_chroot_state()
Gets the chroot state.
#define GETTEXT_CONTEXT_GLUE
void buffer_languages_xml(GString *buffer)
Write the list of installed languages to a buffer as XML.