diff options
Diffstat (limited to 'source3/web/neg_lang.c')
-rw-r--r-- | source3/web/neg_lang.c | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/source3/web/neg_lang.c b/source3/web/neg_lang.c new file mode 100644 index 0000000000..8cb41a34ec --- /dev/null +++ b/source3/web/neg_lang.c @@ -0,0 +1,378 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Samba Web Administration Tool + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + Created by Ryo Kawahara <rkawa@lbe.co.jp> +*/ + +#include "includes.h" +/* #include "config.h" */ +#include "webintl.h" + +#if I18N_SWAT +/* constants. */ +/* it is ok to make them bigger.*/ +#define LN_PREFLANG_MAX 10 +#define LN_LNAME_LENGTH 8+1+8 + +#define LN_DEFAULT_LANG I18N_DEFAULT_LANG +#define LN_LANGDESC_DEFAULT -1 +#define LN_NO_AVAILABLE_LANG -1 + +/* ****************************************************************** + * macros for debugging. + ***************************************************************** */ +#ifdef LN_R_NODEBUG + +#else +/* + *#define LN_DEBUG_LOG "/tmp/lndebug.log" + *void ln_debug_error(const char *info, int nLine) + *{ + * FILE* fp; + * fp = sys_fopen(LN_DEBUG_LOG, "a"); + * fprintf(fp, "%s at %d.\n", info, nLine); + * fclose(fp); + *} + *void rassert_help(BOOL b, int l) + *{ + * if(!b) + * { + * ln_debug_error("language negotiation error.", l); + * exit(1); + * } + *} + */ +#endif /* LN_R_NODEBUG */ + +/* **************************************************************** + LNNegotiator struct. It contains... + [aPrefLang] + the array of strings. each string is the name of + languages ("ja", "ko"...), given by web browser. + [nPrefLang] + the number of the languages in aPrefLang. + [lOriginalLang] + == "en": indicates what language the default(original) files + are written with. +**************************************************************** */ +typedef char lnstring[LN_LNAME_LENGTH + 1]; +#define lnstrcpy(d,s) safe_strcpy((d),(s),sizeof(lnstring)-1) + +typedef struct tagLNNegotiator +{ + lnstring aPrefLang[LN_PREFLANG_MAX]; + int nPrefLang; + lnstring lOriginalLang; +}LNNegotiator; + +/* ************************************************************** + * some access functions & macros for LNNegotiator struct. + * ************************************************************ */ +#define ln_getPreflangCount(pLn) ((pLn)->nPrefLang) +#define ln_getOriginalLang(pLn) ((pLn)->lOriginalLang) +#define ln_getDefaultPrefLang(pLn) ((pLn)->lDefaultPrefLang) + +/* make it inline-expanded (or macro) to get better performance */ +static const char* ln_getPreflang(LNNegotiator* pLn, int i) +{ + rassert(i == LN_LANGDESC_DEFAULT + || (0 <= i && i < ln_getPreflangCount(pLn))); + + if(i == LN_LANGDESC_DEFAULT) + return NULL; + if(0 <= i && i < ln_getPreflangCount(pLn)) + return pLn->aPrefLang[i]; + return NULL; +} +/* initialize structures */ +static void ln_resetln(LNNegotiator* pLn) +{ + pLn->nPrefLang = 0; + /* using fixed memory.*/ +} +static BOOL ln_addPreflang(LNNegotiator* pLn, const char* pLang) +{ + int nPref = ln_getPreflangCount(pLn); + + if(nPref >= LN_PREFLANG_MAX) + return False; + + lnstrcpy(pLn->aPrefLang[nPref], pLang); + (pLn->nPrefLang)++; + return True; +} +static void ln_initln_help(LNNegotiator* pLn) +{ + ln_resetln(pLn); + lnstrcpy(pLn->lOriginalLang, I18N_ORIGINAL_LANG); + /* I18N_ORIGINAL_LANG = "en" is hardcoded in + webintl.h. */ + if (I18N_DEFAULT_PREF_LANG[0] != '\0') + ln_addPreflang(pLn, I18N_DEFAULT_PREF_LANG); + + /* this entry is used only when web browser didn't send + ACCEPT-LANGUAGE header. */ +} +/* **************************************************************** + * store acceptable languages into LNNegotiator object. + * [pstrLangarray] The arguments of "accept-language" http header, + * which is like "en-GB, es;q=0.5, ja". "q=0.5" is called quality value, + * but it is ignored now. wiled card "*" is also ignored. + ***************************************************************** */ +static BOOL ln_negotiate_language_help( LNNegotiator* pLn, const char* pstrLangarray ) +{ + char* pToken; + const char* pDelim = " \n\r\t,;"; + pstring strBuffer; + + rassert(pstrLangarray); + rassert(pLn); + + ln_resetln(pLn); + pstrcpy(strBuffer, pstrLangarray); + pToken = strtok(strBuffer, pDelim); + while(pToken != NULL) + { + if(strncmp(pToken, "q=", strlen("q=")) == 0) + { + pToken = strtok(NULL, pDelim); + continue; + } + if(!ln_addPreflang(pLn, pToken)) + break; + pToken = strtok(NULL, pDelim); + } + rassert(ln_getPreflangCount(pLn) != 0); + return (ln_getPreflangCount(pLn) != 0); +} +/* parse catalog file header and get encoding information.*/ +static BOOL parse_po_header(const char* pheader, pstring pencoding_name) +{ + const char *ap_i_v = "Project-Id-Version:"; + const char *acharset = "charset="; + char* penc; + int nenc; + + if(pencoding_name == NULL) return False; + if(pheader == NULL || *pheader == '\0') + { + /* error or catalog is not available. */ + pstrcpy(pencoding_name,""); + return False; + } + penc = strstr(pheader, acharset); + if(strncmp(pheader, ap_i_v, strlen(ap_i_v)) != 0 || penc == NULL) + { + /* catalog file exists, but header is not good.*/ + pstrcpy(pencoding_name, ""); + return True; + } + nenc = strcspn(penc + strlen(acharset), "\n"); + strncpy(pencoding_name, + penc + strlen(acharset), nenc); + return True; +} +/* ad-hoc mime charset -> samba encoding name converter. + character conversion is done when internal samba data, + such as paramters, open files, share names, are going to be displayed. + it is only valid for japanese encodings because samba-2.0.7 only has + these three character convertors. + so other .po file(catalog file) should be encoded with one which + samba can deal with (i.e same as DOS codepage). + + display-time conversion is deleted on this version because + all catalog files are encoded with samba internal encoding (DOS codepage). + + THIS FUNCTION is ALREADY obsolated and maybe removed soon, -- monyo +*/ +#define LN_SAMBA_ENCODINGS 3 +static const char* get_samba_enc(const char* penc) +{ + int i; + static const fstring fdefault = ""; + static const fstring fmimeenc[LN_SAMBA_ENCODINGS] = + { + "EUC-JP", "Shift_JIS", "ISO-2022-JP" + }; + static const fstring fsambaenc[LN_SAMBA_ENCODINGS] = + { + "euc", "sjis", "jis" + }; + for(i = 0; i < LN_SAMBA_ENCODINGS; i++) + { + if(strcasecmp(penc, fmimeenc[i]) == 0) + return fsambaenc[i]; + } + return fdefault; +} +/* ************************************************************ + find a better language. + if the language specified by web browser matches to a language + which is supported by the swat server, this function returns it. + *********************************************************** */ +static void set_a_language(const char* planguage) +{ + /* included gettext source is affected by + these env.variables without locale settings. + */ + /* + putenv(env) will not duplicate env argument + but smbw_setenv() does this. + */ + FILE *file; + smbw_setenv("LANGUAGE", planguage); + smbw_setenv("LANG", planguage); + bindtextdomain(I18N_PACKAGE, I18N_LOCALEDIR); + textdomain(I18N_PACKAGE); +} +static int ln_set_pref_language(LNNegotiator* pLn) +{ + int j; + pstring enc_name; + + for(j = 0; j < ln_getPreflangCount(pLn); j++) + { + set_a_language(ln_getPreflang(pLn, j)); + /* then check for _("") special entry which has + a lot of information about .po file. */ + if(parse_po_header(_(""), enc_name)) + { + /* the catalog file must exist and may have + encoding information .*/ + /* + but in this version, catalog files must be + written with samba-internal encoding (i.e. + dos encoding, dos codepage) + so there is no need to convert. + //ln_init_swat_encoding(get_samba_enc(enc_name)); + ln_init_swat_encoding(enc_name); + */ + return j; + } + } + return LN_NO_AVAILABLE_LANG; + /* no available or return the default? */ +} +/* ************************************************************** + initialize gettext. Before this, cgi_setup() should be done. + cgi_setup() calls ln_negotiate_language() if the user specifies + languages in web browser. Then, ln_set_pref_language() will work. + ************************************************************* */ +static BOOL ln_init_lang_env_help(LNNegotiator* pLn) +{ +#if I18N_GETTEXT + int nLang; + + nLang = ln_set_pref_language(pLn); + rstrace(getenv("LANGUAGE")); +#endif /* I18N_GETTEXT */ + return True; +} +/* ***************************************************************** + * This function searches for the "PrefLang" version of pFile. + * if not available, returns pFile. + * [pFile] the filename. + * [pst] the address of a struct. it will be filled with the information + * of the file. + * [pLangDesc] The address of an integer. a value which indicates the + * language of the returned value is written to the address. the value + * is used in ln_get_lang(). + * [return value] address of the name of the language version of the file. + * It is static object so it will be destroyed at the time ln_get_pref_file() + * is called. + **************************************************************** */ +static void ln_make_filename( pstring afname, const char* pFile, const char* pAdd ) +{ +#if LANG_PREFIX + /* LANG_PREFIX is already undefined, maybe removed soon */ + /* maybe, foo.html.ja */ + pstrcpy(afname, pFile); + pstrcat(afname, "."); + pstrcat(afname, pAdd); +#else + /* maybe, lang/ja/foo.html */ + pstrcpy(afname, "lang/"); + pstrcat(afname, pAdd); + pstrcat(afname, "/"); + pstrcat(afname, pFile); +#endif +} +static const char* ln_get_pref_file_help( + LNNegotiator* pLn, const char* pFile, + SMB_STRUCT_STAT* pst, int* pLangDesc) +{ + static pstring afname; + int i; + + for(i = 0; i < ln_getPreflangCount(pLn); i++) + { + if(strcmp(ln_getPreflang(pLn, i), ln_getOriginalLang(pLn)) + == 0) + break; + ln_make_filename(afname, pFile, ln_getPreflang(pLn, i)); + if(file_exist(afname, pst)) + { + *pLangDesc = i; + return afname; + } + } + pstrcpy(afname, pFile); + file_exist(afname, pst); + *pLangDesc = LN_LANGDESC_DEFAULT; + return afname; +} +/* ******************************************************************* + * file scope variables. this variable is not locked. + * (not multithread-safe) + ******************************************************************** */ +static LNNegotiator lnLanguagenegotiator; + +/* ******************************************************************* + * interfaces to the outside of this file. + ******************************************************************** */ +void ln_initln(void) +{ + ln_initln_help(&lnLanguagenegotiator); +} +BOOL ln_init_lang_env(void) +{ + return ln_init_lang_env_help(&lnLanguagenegotiator); +} +const char* ln_get_lang(int nLangDesc) +{ + return ln_getPreflang(&lnLanguagenegotiator, nLangDesc); +} +const char* ln_get_pref_file(const char* pFile, + SMB_STRUCT_STAT* pst, int* pLangDesc) +{ + return ln_get_pref_file_help( + &lnLanguagenegotiator, pFile, pst, pLangDesc); +} +BOOL ln_negotiate_language(const char* pstrLangarray) +{ + return ln_negotiate_language_help( + &lnLanguagenegotiator, pstrLangarray); +} +const char* ln_get_pref_file_n_o(const char* pFile) +{ + SMB_STRUCT_STAT st; + int nLangDesc; + return ln_get_pref_file(pFile, &st, &nLangDesc); +} +#endif /* I18N_SWAT */ |