diff options
Diffstat (limited to 'usr/src/cmd/ssh/libssh/common/g11n.c')
| -rw-r--r-- | usr/src/cmd/ssh/libssh/common/g11n.c | 964 |
1 files changed, 0 insertions, 964 deletions
diff --git a/usr/src/cmd/ssh/libssh/common/g11n.c b/usr/src/cmd/ssh/libssh/common/g11n.c deleted file mode 100644 index 558b410c96..0000000000 --- a/usr/src/cmd/ssh/libssh/common/g11n.c +++ /dev/null @@ -1,964 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - * - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include <errno.h> -#include <locale.h> -#include <langinfo.h> -#include <iconv.h> -#include <ctype.h> -#include <wctype.h> -#include <strings.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include "includes.h" -#include "xmalloc.h" -#include "xlist.h" -#include "compat.h" -#include "log.h" - -#ifdef MIN -#undef MIN -#endif /* MIN */ - -#define MIN(x, y) ((x) < (y) ? (x) : (y)) - -#define LOCALE_PATH "/usr/bin/locale" - -/* two-char country code, '-' and two-char region code */ -#define LANGTAG_MAX 5 - -static int locale_cmp(const void *d1, const void *d2); -static char *g11n_locale2langtag(char *locale); - -static char *do_iconv(iconv_t cd, const char *s, uint_t *lenp, char **err_str); - -/* - * native_codeset records the codeset of the default system locale. - * It is used to convert the contents of file (eg /etc/issue) which is - * supposed to be in the codeset of default system locale. - */ -static char *native_codeset; - -/* - * Convert locale string name into a language tag. The caller is responsible for - * freeing the memory allocated for the result. - */ -static char * -g11n_locale2langtag(char *locale) -{ - char *langtag; - - /* base cases */ - if (!locale || !*locale) - return (NULL); - - if (strcmp(locale, "POSIX") == 0 || strcmp(locale, "C") == 0) - return (xstrdup("i-default")); - - /* punt for language codes which are not exactly 2 letters */ - if (strlen(locale) < 2 || - !isalpha(locale[0]) || - !isalpha(locale[1]) || - (locale[2] != '\0' && - locale[2] != '_' && - locale[2] != '.' && - locale[2] != '@')) - return (NULL); - - - /* we have a primary language sub-tag */ - langtag = (char *)xmalloc(LANGTAG_MAX + 1); - - strncpy(langtag, locale, 2); - langtag[2] = '\0'; - - /* do we have country sub-tag? For example: cs_CZ */ - if (locale[2] == '_') { - if (strlen(locale) < 5 || - !isalpha(locale[3]) || - !isalpha(locale[4]) || - (locale[5] != '\0' && (locale[5] != '.' && - locale[5] != '@'))) { - return (langtag); - } - - /* example: create cs-CZ from cs_CZ */ - if (snprintf(langtag, 6, "%.*s-%.*s", 2, locale, 2, - locale + 3) == 5) - return (langtag); - } - - /* in all other cases we just use the primary language sub-tag */ - return (langtag); -} - -uint_t -g11n_langtag_is_default(char *langtag) -{ - return (strcmp(langtag, "i-default") == 0); -} - -/* - * This lang tag / locale matching function works only for two-character - * language primary sub-tags and two-character country sub-tags. - */ -uint_t -g11n_langtag_matches_locale(char *langtag, char *locale) -{ - /* match "i-default" to the process' current locale if possible */ - if (g11n_langtag_is_default(langtag)) { - if (strcasecmp(locale, "POSIX") == 0 || - strcasecmp(locale, "C") == 0) - return (1); - else - return (0); - } - - /* - * locale must be at least 2 chars long and the lang part must be - * exactly two characters - */ - if (strlen(locale) < 2 || - (!isalpha(locale[0]) || !isalpha(locale[1]) || - (locale[2] != '\0' && locale[2] != '_' && - locale[2] != '.' && locale[2] != '@'))) - return (0); - - /* same thing with the langtag */ - if (strlen(langtag) < 2 || - (!isalpha(langtag[0]) || !isalpha(langtag[1]) || - (langtag[2] != '\0' && langtag[2] != '-'))) - return (0); - - /* primary language sub-tag and the locale's language part must match */ - if (strncasecmp(langtag, locale, 2) != 0) - return (0); - - /* - * primary language sub-tag and the locale's language match, now - * fuzzy check country part - */ - - /* neither langtag nor locale have more than one component */ - if (langtag[2] == '\0' && - (locale[2] == '\0' || locale[2] == '.' || locale[2] == '@')) - return (2); - - /* langtag has only one sub-tag... */ - if (langtag[2] == '\0') - return (1); - - /* locale has no country code... */ - if (locale[2] == '\0' || locale[2] == '.' || locale[2] == '@') - return (1); - - /* langtag has more than one subtag and the locale has a country code */ - - /* ignore second subtag if not two chars */ - if (strlen(langtag) < 5) - return (1); - - if (!isalpha(langtag[3]) || !isalpha(langtag[4]) || - (langtag[5] != '\0' && langtag[5] != '-')) - return (1); - - /* ignore rest of locale if there is no two-character country part */ - if (strlen(locale) < 5) - return (1); - - if (locale[2] != '_' || !isalpha(locale[3]) || !isalpha(locale[4]) || - (locale[5] != '\0' && locale[5] != '.' && locale[5] != '@')) - return (1); - - /* if the country part matches, return 2 */ - if (strncasecmp(&langtag[3], &locale[3], 2) == 0) - return (2); - - return (1); -} - -char * -g11n_getlocale() -{ - /* we have one text domain - always set it */ - (void) textdomain(TEXT_DOMAIN); - - /* if the locale is not set, set it from the env vars */ - if (!setlocale(LC_MESSAGES, NULL)) - (void) setlocale(LC_MESSAGES, ""); - - return (setlocale(LC_MESSAGES, NULL)); -} - -void -g11n_setlocale(int category, const char *locale) -{ - char *curr; - - if (native_codeset == NULL) { - /* set default locale, and record current codeset */ - (void) setlocale(LC_ALL, ""); - curr = nl_langinfo(CODESET); - native_codeset = xstrdup(curr); - } - - /* we have one text domain - always set it */ - (void) textdomain(TEXT_DOMAIN); - - if (!locale) - return; - - if (*locale && ((curr = setlocale(category, NULL))) && - strcmp(curr, locale) == 0) - return; - - /* if <category> is bogus, setlocale() will do nothing */ - (void) setlocale(category, locale); -} - -char ** -g11n_getlocales() -{ - FILE *locale_out; - uint_t n_elems, list_size, long_line = 0; - char **list; - char locale[64]; /* 64 bytes is plenty for locale names */ - - if ((locale_out = popen(LOCALE_PATH " -a", "r")) == NULL) - return (NULL); - - /* - * start with enough room for 65 locales - that's a lot fewer than - * all the locales available for installation, but a lot more than - * what most users will need and install - */ - n_elems = 0; - list_size = 192; - list = (char **) xmalloc(sizeof (char *) * (list_size + 1)); - memset(list, 0, sizeof (char *) * (list_size + 1)); - - while (fgets(locale, sizeof (locale), locale_out)) { - /* skip long locale names (if any) */ - if (!strchr(locale, '\n')) { - long_line = 1; - continue; - } else if (long_line) { - long_line = 0; - continue; - } - - if (strncmp(locale, "iso_8859", 8) == 0) - /* ignore locale names like "iso_8859-1" */ - continue; - - if (n_elems == list_size) { - list_size *= 2; - list = (char **)xrealloc((void *) list, - (list_size + 1) * sizeof (char *)); - memset(&list[n_elems + 1], 0, - sizeof (char *) * (list_size - n_elems + 1)); - } - - *(strchr(locale, '\n')) = '\0'; /* remove the trailing \n */ - list[n_elems++] = xstrdup(locale); - } - - (void) pclose(locale_out); - - if (n_elems == 0) { - xfree(list); - return (NULL); - } - - list[n_elems] = NULL; - - qsort(list, n_elems - 1, sizeof (char *), locale_cmp); - return (list); -} - -char * -g11n_getlangs() -{ - char *locale; - - if (getenv("SSH_LANGS")) - return (xstrdup(getenv("SSH_LANGS"))); - - locale = g11n_getlocale(); - - if (!locale || !*locale) - return (xstrdup("i-default")); - - return (g11n_locale2langtag(locale)); -} - -char * -g11n_locales2langs(char **locale_set) -{ - char **p, **r, **q; - char *langtag, *langs; - int locales, skip; - - for (locales = 0, p = locale_set; p && *p; p++) - locales++; - - r = (char **)xmalloc((locales + 1) * sizeof (char *)); - memset(r, 0, (locales + 1) * sizeof (char *)); - - for (p = locale_set; p && *p && ((p - locale_set) <= locales); p++) { - skip = 0; - if ((langtag = g11n_locale2langtag(*p)) == NULL) - continue; - for (q = r; (q - r) < locales; q++) { - if (!*q) - break; - if (*q && strcmp(*q, langtag) == 0) - skip = 1; - } - if (!skip) - *(q++) = langtag; - else - xfree(langtag); - *q = NULL; - } - - langs = xjoin(r, ','); - g11n_freelist(r); - - return (langs); -} - -static int -sortcmp(const void *d1, const void *d2) -{ - char *s1 = *(char **)d1; - char *s2 = *(char **)d2; - - return (strcmp(s1, s2)); -} - -int -g11n_langtag_match(char *langtag1, char *langtag2) -{ - int len1, len2; - char c1, c2; - - len1 = (strchr(langtag1, '-')) ? - (strchr(langtag1, '-') - langtag1) - : strlen(langtag1); - - len2 = (strchr(langtag2, '-')) ? - (strchr(langtag2, '-') - langtag2) - : strlen(langtag2); - - /* no match */ - if (len1 != len2 || strncmp(langtag1, langtag2, len1) != 0) - return (0); - - c1 = *(langtag1 + len1); - c2 = *(langtag2 + len2); - - /* no country sub-tags - exact match */ - if (c1 == '\0' && c2 == '\0') - return (2); - - /* one langtag has a country sub-tag, the other doesn't */ - if (c1 == '\0' || c2 == '\0') - return (1); - - /* can't happen - both langtags have a country sub-tag */ - if (c1 != '-' || c2 != '-') - return (1); - - /* compare country subtags */ - langtag1 = langtag1 + len1 + 1; - langtag2 = langtag2 + len2 + 1; - - len1 = (strchr(langtag1, '-')) ? - (strchr(langtag1, '-') - langtag1) : strlen(langtag1); - - len2 = (strchr(langtag2, '-')) ? - (strchr(langtag2, '-') - langtag2) : strlen(langtag2); - - if (len1 != len2 || strncmp(langtag1, langtag2, len1) != 0) - return (1); - - /* country tags matched - exact match */ - return (2); -} - -char * -g11n_langtag_set_intersect(char *set1, char *set2) -{ - char **list1, **list2, **list3, **p, **q, **r; - char *set3, *lang_subtag; - uint_t n1, n2, n3; - uint_t do_append; - - list1 = xsplit(set1, ','); - list2 = xsplit(set2, ','); - - for (n1 = 0, p = list1; p && *p; p++, n1++) - ; - for (n2 = 0, p = list2; p && *p; p++, n2++) - ; - - list3 = (char **) xmalloc(sizeof (char *) * (n1 + n2 + 1)); - *list3 = NULL; - - /* - * we must not sort the user langtags - sorting or not the server's - * should not affect the outcome - */ - qsort(list2, n2, sizeof (char *), sortcmp); - - for (n3 = 0, p = list1; p && *p; p++) { - do_append = 0; - for (q = list2; q && *q; q++) { - if (g11n_langtag_match(*p, *q) != 2) continue; - /* append element */ - for (r = list3; (r - list3) <= (n1 + n2); r++) { - do_append = 1; - if (!*r) - break; - if (strcmp(*p, *r) == 0) { - do_append = 0; - break; - } - } - if (do_append && n3 <= (n1 + n2)) { - list3[n3++] = xstrdup(*p); - list3[n3] = NULL; - } - } - } - - for (p = list1; p && *p; p++) { - do_append = 0; - for (q = list2; q && *q; q++) { - if (g11n_langtag_match(*p, *q) != 1) - continue; - - /* append element */ - lang_subtag = xstrdup(*p); - if (strchr(lang_subtag, '-')) - *(strchr(lang_subtag, '-')) = '\0'; - for (r = list3; (r - list3) <= (n1 + n2); r++) { - do_append = 1; - if (!*r) - break; - if (strcmp(lang_subtag, *r) == 0) { - do_append = 0; - break; - } - } - if (do_append && n3 <= (n1 + n2)) { - list3[n3++] = lang_subtag; - list3[n3] = NULL; - } else - xfree(lang_subtag); - } - } - - set3 = xjoin(list3, ','); - xfree_split_list(list1); - xfree_split_list(list2); - xfree_split_list(list3); - - return (set3); -} - -char * -g11n_clnt_langtag_negotiate(char *clnt_langtags, char *srvr_langtags) -{ - char *list, *result; - char **xlist; - - /* g11n_langtag_set_intersect uses xmalloc - should not return NULL */ - list = g11n_langtag_set_intersect(clnt_langtags, srvr_langtags); - - if (!list) - return (NULL); - - xlist = xsplit(list, ','); - - xfree(list); - - if (!xlist || !*xlist) - return (NULL); - - result = xstrdup(*xlist); - xfree_split_list(xlist); - - return (result); -} - -/* - * Compare locales, preferring UTF-8 codesets to others, otherwise doing - * a stright strcmp() - */ -static int -locale_cmp(const void *d1, const void *d2) -{ - char *dot_ptr; - char *s1 = *(char **)d1; - char *s2 = *(char **)d2; - int s1_is_utf8 = 0; - int s2_is_utf8 = 0; - - /* check if s1 is a UTF-8 locale */ - if (((dot_ptr = strchr((char *)s1, '.')) != NULL) && - (*dot_ptr != '\0') && (strncmp(dot_ptr + 1, "UTF-8", 5) == 0) && - (*(dot_ptr + 6) == '\0' || *(dot_ptr + 6) == '@')) { - s1_is_utf8++; - } - - /* check if s2 is a UTF-8 locale */ - if (((dot_ptr = strchr((char *)s2, '.')) != NULL) && - (*dot_ptr != '\0') && (strncmp(dot_ptr + 1, "UTF-8", 5) == 0) && - (*(dot_ptr + 6) == '\0' || *(dot_ptr + 6) == '@')) { - s2_is_utf8++; - } - - /* prefer UTF-8 locales */ - if (s1_is_utf8 && !s2_is_utf8) - return (-1); - - if (s2_is_utf8 && !s1_is_utf8) - return (1); - - /* prefer any locale over the default locales */ - if (strcmp(s1, "C") == 0 || strcmp(s1, "POSIX") == 0 || - strcmp(s1, "common") == 0) { - if (strcmp(s2, "C") != 0 && strcmp(s2, "POSIX") != 0 && - strcmp(s2, "common") != 0) - return (1); - } - - if (strcmp(s2, "C") == 0 || strcmp(s2, "POSIX") == 0 || - strcmp(s2, "common") == 0) { - if (strcmp(s1, "C") != 0 && - strcmp(s1, "POSIX") != 0 && - strcmp(s1, "common") != 0) - return (-1); - } - - return (strcmp(s1, s2)); -} - - -char ** -g11n_langtag_set_locale_set_intersect(char *langtag_set, char **locale_set) -{ - char **langtag_list, **result, **p, **q, **r; - char *s; - uint_t do_append, n_langtags, n_locales, n_results, max_results; - - if (locale_set == NULL) - return (NULL); - - /* count lang tags and locales */ - for (n_locales = 0, p = locale_set; p && *p; p++) - n_locales++; - - n_langtags = ((s = langtag_set) != NULL && *s && *s != ',') ? 1 : 0; - /* count the number of langtags */ - for (; s = strchr(s, ','); s++, n_langtags++) - ; - - qsort(locale_set, n_locales, sizeof (char *), locale_cmp); - - langtag_list = xsplit(langtag_set, ','); - for (n_langtags = 0, p = langtag_list; p && *p; p++, n_langtags++) - ; - - max_results = MIN(n_locales, n_langtags) * 2; - result = (char **) xmalloc(sizeof (char *) * (max_results + 1)); - *result = NULL; - n_results = 0; - - /* more specific matches first */ - for (p = langtag_list; p && *p; p++) { - do_append = 0; - for (q = locale_set; q && *q; q++) { - if (g11n_langtag_matches_locale(*p, *q) == 2) { - do_append = 1; - for (r = result; (r - result) <= - MIN(n_locales, n_langtags); r++) { - if (!*r) - break; - if (strcmp(*q, *r) == 0) { - do_append = 0; - break; - } - } - if (do_append && n_results < max_results) { - result[n_results++] = xstrdup(*q); - result[n_results] = NULL; - } - break; - } - } - } - - for (p = langtag_list; p && *p; p++) { - do_append = 0; - for (q = locale_set; q && *q; q++) { - if (g11n_langtag_matches_locale(*p, *q) == 1) { - do_append = 1; - for (r = result; (r - result) <= - MIN(n_locales, n_langtags); r++) { - if (!*r) - break; - if (strcmp(*q, *r) == 0) { - do_append = 0; - break; - } - } - if (do_append && n_results < max_results) { - result[n_results++] = xstrdup(*q); - result[n_results] = NULL; - } - break; - } - } - } - - xfree_split_list(langtag_list); - - return (result); -} - -char * -g11n_srvr_locale_negotiate(char *clnt_langtags, char **srvr_locales) -{ - char **results, **locales, *result = NULL; - - if (srvr_locales == NULL) - locales = g11n_getlocales(); - else - locales = srvr_locales; - - if ((results = g11n_langtag_set_locale_set_intersect(clnt_langtags, - locales)) == NULL) - goto err; - - if (*results != NULL) - result = xstrdup(*results); - - xfree_split_list(results); - -err: - if (locales != NULL && locales != srvr_locales) - g11n_freelist(locales); - return (result); -} - -/* - * Functions for converting to UTF-8 from the local codeset and - * converting from UTF-8 to the local codeset. - * - * The error_str parameter is an pointer to a char variable where to - * store a string suitable for use with error() or fatal() or friends. - * It is also used for an error indicator when NULL is returned. - * - * If conversion isn't necessary, *error_str is set to NULL, and - * NULL is returned. - * If conversion error occured, *error_str points to an error message, - * and NULL is returned. - */ -char * -g11n_convert_from_utf8(const char *str, uint_t *lenp, char **error_str) -{ - static char *last_codeset; - static iconv_t cd = (iconv_t)-1; - char *codeset; - - *error_str = NULL; - - codeset = nl_langinfo(CODESET); - - if (strcmp(codeset, "UTF-8") == 0) - return (NULL); - - if (last_codeset == NULL || strcmp(codeset, last_codeset) != 0) { - if (last_codeset != NULL) { - xfree(last_codeset); - last_codeset = NULL; - } - if (cd != (iconv_t)-1) - (void) iconv_close(cd); - - if ((cd = iconv_open(codeset, "UTF-8")) == (iconv_t)-1) { - *error_str = gettext("Cannot convert UTF-8 " - "strings to the local codeset"); - return (NULL); - } - last_codeset = xstrdup(codeset); - } - return (do_iconv(cd, str, lenp, error_str)); -} - -char * -g11n_convert_to_utf8(const char *str, uint_t *lenp, - int native, char **error_str) -{ - static char *last_codeset; - static iconv_t cd = (iconv_t)-1; - char *codeset; - - *error_str = NULL; - - if (native) - codeset = native_codeset; - else - codeset = nl_langinfo(CODESET); - - if (strcmp(codeset, "UTF-8") == 0) - return (NULL); - - if (last_codeset == NULL || strcmp(codeset, last_codeset) != 0) { - if (last_codeset != NULL) { - xfree(last_codeset); - last_codeset = NULL; - } - if (cd != (iconv_t)-1) - (void) iconv_close(cd); - - if ((cd = iconv_open("UTF-8", codeset)) == (iconv_t)-1) { - *error_str = gettext("Cannot convert the " - "local codeset strings to UTF-8"); - return (NULL); - } - last_codeset = xstrdup(codeset); - } - return (do_iconv(cd, str, lenp, error_str)); -} - -/* - * Wrapper around iconv() - * - * The caller is responsible for freeing the result. NULL is returned when - * (errno && errno != E2BIG) (i.e., EILSEQ, EINVAL, EBADF). - * The caller must ensure that the input string isn't NULL pointer. - */ -static char * -do_iconv(iconv_t cd, const char *str, uint_t *lenp, char **err_str) -{ - int ilen, olen; - size_t ileft, oleft; - char *ostr, *optr; - const char *istr; - - ilen = *lenp; - olen = ilen + 1; - - ostr = NULL; - for (;;) { - olen *= 2; - oleft = olen; - ostr = optr = xrealloc(ostr, olen); - istr = (const char *)str; - if ((ileft = ilen) == 0) - break; - - if (iconv(cd, &istr, &ileft, &optr, &oleft) != (size_t)-1) { - /* success: generate reset sequence */ - if (iconv(cd, NULL, NULL, - &optr, &oleft) == (size_t)-1 && errno == E2BIG) { - continue; - } - break; - } - /* failed */ - if (errno != E2BIG) { - oleft = olen; - (void) iconv(cd, NULL, NULL, &ostr, &oleft); - xfree(ostr); - *err_str = gettext("Codeset conversion failed"); - return (NULL); - } - } - olen = optr - ostr; - optr = xmalloc(olen + 1); - (void) memcpy(optr, ostr, olen); - xfree(ostr); - - optr[olen] = '\0'; - *lenp = olen; - - return (optr); -} - -/* - * A filter for output string. Control and unprintable characters - * are converted into visible form (eg "\ooo"). - */ -char * -g11n_filter_string(char *s) -{ - int mb_cur_max = MB_CUR_MAX; - int mblen, len; - char *os = s; - wchar_t wc; - char *obuf, *op; - - /* all character may be converted into the form of \ooo */ - obuf = op = xmalloc(strlen(s) * 4 + 1); - - while (*s != '\0') { - mblen = mbtowc(&wc, s, mb_cur_max); - if (mblen <= 0) { - mblen = 1; - wc = (unsigned char)*s; - } - if (!iswprint(wc) && - wc != L'\n' && wc != L'\r' && wc != L'\t') { - /* - * control chars which need to be replaced - * with safe character sequence. - */ - while (mblen != 0) { - op += sprintf(op, "\\%03o", - (unsigned char)*s++); - mblen--; - } - } else { - while (mblen != 0) { - *op++ = *s++; - mblen--; - } - } - } - *op = '\0'; - len = op - obuf + 1; - op = xrealloc(os, len); - (void) memcpy(op, obuf, len); - xfree(obuf); - return (op); -} - -/* - * Once we negotiated with a langtag, server need to map it to a system - * locale. That is done based on the locale supported on the server side. - * We know (with the locale supported on Solaris) how the langtag is - * mapped to. However, from the client point of view, there is no way to - * know exactly what locale(encoding) will be used. - * - * With the bug fix of SSH_BUG_STRING_ENCODING, it is guaranteed that the - * UTF-8 characters always come over the wire, so it is no longer the problem - * as long as both side has the bug fix. However if the server side doesn't - * have the fix, client can't safely perform the code conversion since the - * incoming character encoding is unknown. - * - * To alleviate this situation, we take an empirical approach to find - * encoding from langtag. - * - * If langtag has a subtag, we can directly map the langtag to UTF-8 locale - * (eg en-US can be mapped to en_US.UTF-8) with a few exceptions. - * Certain xx_YY locales don't support UTF-8 encoding (probably due to lack - * of L10N support ..). Those are: - * - * no_NO, no_NY, sr_SP, sr_YU - * - * They all use ISO8859-X encoding. - * - * For those "xx" langtags, some of them can be mapped to "xx.UTF-8", - * but others cannot. So we need to use the "xx" as the locale name. - * Those locales are: - * - * ar, ca, cs, da, et, fi, he, hu, ja, lt, lv, nl, no, pt, sh, th, tr - * - * Their encoding vary. They could be ISO8859-X or EUC or something else. - * So we don't perform code conversion for these langtags. - */ -static const char *non_utf8_langtag[] = { - "no-NO", "no-NY", "sr-SP", "sr-YU", - "ar", "ca", "cs", "da", "et", "fi", "he", "hu", "ja", - "lt", "lv", "nl", "no", "pt", "sh", "th", "tr", NULL}; - -void -g11n_test_langtag(const char *lang, int server) -{ - const char **lp; - - if (datafellows & SSH_BUG_LOCALES_NOT_LANGTAGS) { - /* - * We negotiated with real locale name (not lang tag). - * We shouldn't expect UTF-8, thus shouldn't do code - * conversion. - */ - datafellows |= SSH_BUG_STRING_ENCODING; - return; - } - - if (datafellows & SSH_BUG_STRING_ENCODING) { - if (server) { - /* - * Whatever bug exists in the client side, server - * side has nothing to do, since server has no way - * to know what actual encoding is used on the client - * side. For example, even if we negotiated with - * en_US, client locale could be en_US.ISO8859-X or - * en_US.UTF-8. - */ - return; - } - /* - * We are on the client side. We'll check with known - * locales to see if non-UTF8 characters could come in. - */ - for (lp = non_utf8_langtag; *lp != NULL; lp++) { - if (strcmp(lang, *lp) == 0) - break; - } - if (*lp == NULL) { - debug2("Server is expected to use UTF-8 locale"); - datafellows &= ~SSH_BUG_STRING_ENCODING; - } else { - /* - * Server is expected to use non-UTF8 encoding. - */ - debug2("Enforcing no code conversion: %s", lang); - } - } -} - -/* - * Free all strings in the list and then free the list itself. We know that the - * list ends with a NULL pointer. - */ -void -g11n_freelist(char **list) -{ - int i = 0; - - while (list[i] != NULL) { - xfree(list[i]); - i++; - } - - xfree(list); -} |
