Back to index

courier  0.68.2
contentlanguage.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2002 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 
00007 #if    HAVE_CONFIG_H
00008 #include      "config.h"
00009 #endif
00010 
00011 #include      <stdio.h>
00012 #include      <string.h>
00013 #include      <stdlib.h>
00014 #include      <ctype.h>
00015 #include      "http11.h"
00016 #include      "../rfc2045/rfc2045charset.h"
00017 
00018 #if    HAVE_DIRENT_H
00019 #include      <dirent.h>
00020 #define       NAMLEN(dirent)       strlen(dirent->d_name)
00021 #else
00022 #define       dirent direct
00023 #define       NAMLEN(dirent)       ((dirent)->d_namlen)
00024 #if    HAVE_SYS_NDIR_H
00025 #include      <sys/ndir.h>
00026 #endif
00027 #if    HAVE_SYS_DIR_H
00028 #include      <sys/dir.h>
00029 #endif
00030 #if    HAVE_NDIR_H
00031 #include      <ndir.h>
00032 #endif
00033 #endif
00034 
00035 extern void error(const char *);
00036 
00037 static void enomem()
00038 {
00039        error("Out of memory.");
00040 }
00041 
00042 static const char defaultlang[] = HTTP11_DEFAULTLANG;
00043 
00044 /*
00045 ** Based upon Accept-Language: header, figure out which directory in
00046 ** HTMLLIBDIR matches it.
00047 */
00048 
00049 FILE *http11_open_langfile(const char *libdir, const char *subdir,
00050               const char *file)
00051 {
00052 char   *p=malloc(strlen(libdir)+strlen(subdir)+strlen(file)+3);
00053 FILE   *fp;
00054 
00055        if (!p)       return (0);
00056        strcat(strcat(strcat(strcat(strcpy(p, libdir), "/"), subdir), "/"),
00057               file);
00058 
00059        fp=fopen(p, "r");
00060        free(p);
00061        return (fp);
00062 }
00063 
00064 /**************************************************************************/
00065 
00066 /* Parse Accept-Language: header */
00067 
00068 static size_t parse_accept_string(const char *acc_lang, char **languages,
00069                      double *weights)
00070 {
00071 char *p=strdup(acc_lang ? acc_lang:"");
00072 size_t cnt=0;
00073 char   *q, *r;
00074 int    has_weights=0;
00075 double *save_weights=weights;
00076 
00077        if (!p)       enomem();
00078        for (q=p; (q=strtok(q, ", ")) != 0; q=0)
00079        {
00080               if (languages)
00081               {
00082                      q=strdup(q);
00083                      if (!q)       enomem();
00084                      *languages++=q;
00085               }
00086               if (weights)  *weights=1;   /* Until further notice */
00087               for (r=q; *r; r++)
00088                      *r=tolower(*r);
00089               if ((r=strchr(q, ';')) != 0)
00090               {
00091                      *r++=0;
00092                      if (*r == 'q' && r[1] == '=')
00093                      {
00094                      double weight=atof(r+2);
00095 
00096                             if (weights)  *weights=weight;
00097                             has_weights=1;
00098                      }
00099               }
00100               if (weights)  ++weights;
00101               ++cnt;
00102        }
00103        free(p);
00104        if (!has_weights && weights)
00105        {
00106        size_t i;
00107        double weight=1;
00108 
00109        /*
00110        ** Broken HTTP/1.1 clients do not specify quality factors, and expect
00111        ** the server to pick the first one on the list
00112        */
00113               for (i=cnt; i; )
00114               {
00115                      --i;
00116                      save_weights[i]=weight;
00117                      weight = weight + 1;
00118               }
00119        }
00120        
00121        return (cnt);
00122 }
00123 
00124 char *http11_best_content_language(const char *libdir, const char *acc_lang)
00125 {
00126 size_t naccept=parse_accept_string(acc_lang, 0, 0);
00127 char **languages=malloc(naccept ? sizeof(char *)*naccept:1);
00128 double *weights=malloc(naccept ? sizeof(double)*naccept:1);
00129 DIR    *p;
00130 struct dirent *de;
00131 size_t i;
00132 #if 0
00133 double missweight=1;
00134 #endif
00135 char   *bestlang=0;
00136 double bestweight=0;
00137 int    found_nondefault_match=0;
00138 
00139        if (!languages || !weights)
00140        {
00141               if (languages)       free(languages);
00142               if (weights)  free(weights);
00143               enomem();
00144        }
00145        (void)parse_accept_string(acc_lang, languages, weights);
00146 #if 0
00147        for (i=0; i<naccept; i++)
00148               if (strcmp(languages[i], "*") == 0)       missweight=weights[i];
00149               /* Default weight */
00150 #endif
00151        p=opendir(libdir);
00152        while (p && (de=readdir(p)) != 0)
00153        {
00154        FILE   *fp;
00155 
00156               if (*de->d_name == '.')     continue;
00157 
00158               if ((fp=http11_open_langfile(libdir, de->d_name, "LOCALE"))
00159                             != 0)
00160               {
00161 #if 0
00162               double myweight=missweight;
00163 #else
00164               double  myweight=0;
00165 #endif
00166 
00167                      fclose(fp);
00168                      for (i=0; i<naccept; i++)
00169                             if (strcmp(languages[i], de->d_name) == 0)
00170                             {
00171                                    myweight=weights[i];
00172                                    break;
00173                             }
00174                      if (!bestlang || myweight > bestweight)
00175                      {
00176                             if (bestlang) free(bestlang);
00177                             bestlang=strdup(de->d_name);
00178                             if (!bestlang)       enomem();
00179                             bestweight=myweight;
00180                             if (i < naccept)
00181                                    found_nondefault_match=1;
00182                      }
00183               }
00184        }
00185        if (p) closedir(p);
00186        if (!bestlang || !found_nondefault_match)
00187        {
00188               if (bestlang) free(bestlang);
00189               if ((bestlang=malloc(sizeof(defaultlang))) == 0) enomem();
00190               strcpy(bestlang, defaultlang);
00191        }
00192        for (i=0; i<naccept; i++)
00193               free(languages[i]);
00194        free(languages);
00195        free(weights);
00196        return (bestlang);
00197 }
00198 
00199 static const char *get_http11(const char *libdir, const char *subdir,
00200               char *buf,
00201               const char *file, const char *def)
00202 {
00203 FILE   *fp=http11_open_langfile(libdir, subdir, file);
00204 
00205        if (fp != 0)
00206        {
00207        size_t n=fread(buf, 1, 79, fp);
00208 
00209               if (n <= 0)   n=0;
00210               buf[n]=0;
00211               fclose(fp);
00212               return (strtok(buf, "\r\n"));
00213        }
00214        return (def);
00215 }
00216 
00217 const char *http11_content_language(const char *libdir, const char *acc_lang)
00218 {
00219 static char   buf[80];
00220 
00221        return (get_http11(libdir, acc_lang, buf, "LANGUAGE", defaultlang));
00222 }
00223 
00224 const char *http11_content_locale(const char *libdir, const char *acc_lang)
00225 {
00226 static char buf[80];
00227 const char *p=get_http11(libdir, acc_lang, buf, "LOCALE", "C");
00228 
00229        return (p);
00230 }
00231 
00232 const char *http11_content_ispelldict(const char *libdir, const char *acc_lang)
00233 {
00234 static char buf[80];
00235 
00236        return (get_http11(libdir, acc_lang, buf, "ISPELLDICT", defaultlang));
00237 }
00238 
00239 const char *http11_content_charset(const char *libdir, const char *acc_lang)
00240 {
00241        char buf[80];
00242        static char buf2[80];
00243        size_t naccept;
00244        char **charsets;
00245        double *weights;
00246        const char *p;
00247        size_t i;
00248 
00249        strcpy(buf2, get_http11(libdir, acc_lang, buf, "CHARSET",
00250                             RFC2045CHARSET));
00251 
00252        p=getenv("HTTP_ACCEPT_CHARSET");
00253 
00254        if (!p) p="";
00255 
00256        naccept=parse_accept_string(p, 0, 0);
00257        charsets=malloc(naccept ? sizeof(char *)*naccept:1);
00258        weights=malloc(naccept ? sizeof(double)*naccept:1);
00259 
00260        if (!charsets || !weights)
00261        {
00262               if (charsets) free(charsets);
00263               if (weights)  free(weights);
00264               enomem();
00265        }
00266 
00267        (void)parse_accept_string(p, charsets, weights);
00268        strcpy(buf, buf2);
00269 
00270        for (p=strtok(buf, ", \t\r\n"); p != NULL; p=strtok(NULL, ", \t\r\n"))
00271        {
00272               for (i=0; i<naccept; i++)
00273                      if (strcmp(charsets[i], p) == 0)
00274                      {
00275                             strcpy(buf2, charsets[i]);
00276                             for (i=0; i<naccept; i++)
00277                                    free(charsets[i]);
00278                             free(charsets);
00279                             free(weights);
00280                             return buf2;
00281                      }
00282        }
00283 
00284        p=strtok(buf2, ", \t\r\n");
00285        if (!p)
00286               p=RFC2045CHARSET;
00287        for (i=0; i<naccept; i++)
00288               free(charsets[i]);
00289        free(charsets);
00290        free(weights);
00291        return p;
00292 }