/* ** Copyright 1998 - 2002 Double Precision, Inc. ** See COPYING for distribution information. */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "http11.h" #include "../rfc2045/rfc2045charset.h" #if HAVE_DIRENT_H #include #define NAMLEN(dirent) strlen(dirent->d_name) #else #define dirent direct #define NAMLEN(dirent) ((dirent)->d_namlen) #if HAVE_SYS_NDIR_H #include #endif #if HAVE_SYS_DIR_H #include #endif #if HAVE_NDIR_H #include #endif #endif extern void error(const char *); static void enomem() { error("Out of memory."); } static const char defaultlang[] = HTTP11_DEFAULTLANG; /* ** Based upon Accept-Language: header, figure out which directory in ** HTMLLIBDIR matches it. */ FILE *http11_open_langfile(const char *libdir, const char *subdir, const char *file) { char *p=malloc(strlen(libdir)+strlen(subdir)+strlen(file)+3); FILE *fp; if (!p) return (0); strcat(strcat(strcat(strcat(strcpy(p, libdir), "/"), subdir), "/"), file); fp=fopen(p, "r"); free(p); return (fp); } /**************************************************************************/ /* Parse Accept-Language: header */ static size_t parse_accept_string(const char *acc_lang, char **languages, double *weights) { char *p=strdup(acc_lang ? acc_lang:""); size_t cnt=0; char *q, *r; int has_weights=0; double *save_weights=weights; if (!p) enomem(); for (q=p; (q=strtok(q, ", ")) != 0; q=0) { if (languages) { q=strdup(q); if (!q) enomem(); *languages++=q; } if (weights) *weights=1; /* Until further notice */ for (r=q; *r; r++) *r=tolower(*r); if ((r=strchr(q, ';')) != 0) { *r++=0; if (*r == 'q' && r[1] == '=') { double weight=atof(r+2); if (weights) *weights=weight; has_weights=1; } } if (weights) ++weights; ++cnt; } free(p); if (!has_weights && weights) { size_t i; double weight=1; /* ** Broken HTTP/1.1 clients do not specify quality factors, and expect ** the server to pick the first one on the list */ for (i=cnt; i; ) { --i; save_weights[i]=weight; weight = weight + 1; } } return (cnt); } char *http11_best_content_language(const char *libdir, const char *acc_lang) { size_t naccept=parse_accept_string(acc_lang, 0, 0); char **languages=malloc(naccept ? sizeof(char *)*naccept:1); double *weights=malloc(naccept ? sizeof(double)*naccept:1); DIR *p; struct dirent *de; size_t i; #if 0 double missweight=1; #endif char *bestlang=0; double bestweight=0; int found_nondefault_match=0; if (!languages || !weights) { if (languages) free(languages); if (weights) free(weights); enomem(); } (void)parse_accept_string(acc_lang, languages, weights); #if 0 for (i=0; id_name == '.') continue; if ((fp=http11_open_langfile(libdir, de->d_name, "LOCALE")) != 0) { #if 0 double myweight=missweight; #else double myweight=0; #endif fclose(fp); for (i=0; id_name) == 0) { myweight=weights[i]; break; } if (!bestlang || myweight > bestweight) { if (bestlang) free(bestlang); bestlang=strdup(de->d_name); if (!bestlang) enomem(); bestweight=myweight; if (i < naccept) found_nondefault_match=1; } } } if (p) closedir(p); if (!bestlang || !found_nondefault_match) { if (bestlang) free(bestlang); if ((bestlang=malloc(sizeof(defaultlang))) == 0) enomem(); strcpy(bestlang, defaultlang); } for (i=0; i