Back to index

courier  0.68.2
rfc2231.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2002-2011 Double Precision, Inc.  See COPYING for
00003 ** distribution information.
00004 */
00005 
00006 /*
00007 */
00008 
00009 #if    HAVE_CONFIG_H
00010 #include "rfc2045_config.h"
00011 #endif
00012 #include      <stdlib.h>
00013 #include      <stdio.h>
00014 #include      <string.h>
00015 #include      <ctype.h>
00016 #include      "rfc2045.h"
00017 #include      "rfc822/rfc822.h"
00018 #include      "unicode/unicode.h"
00019 
00020 /*
00021 ** Deallocate a link list of rfc2231param structures.
00022 */
00023 
00024 void rfc2231_paramDestroy(struct rfc2231param *p)
00025 {
00026        while (p)
00027        {
00028               struct rfc2231param *q=p->next;
00029 
00030               free(p);
00031               p=q;
00032        }
00033 }
00034 
00035 int rfc2231_buildAttrList(struct rfc2231param **paramList,
00036                        const char *name,
00037 
00038                        const char *attrName,
00039                        const char *attrValue)
00040 {
00041        int nameLen=strlen(name);
00042 
00043        if (strncmp(attrName, name, nameLen) == 0 &&
00044            (attrName[nameLen] == 0 ||
00045             attrName[nameLen] == '*'))
00046        {
00047               struct rfc2231param *n
00048                      =malloc(sizeof(struct rfc2231param)), **o;
00049 
00050               const char *p=attrName + nameLen;
00051 
00052               if (!n)
00053               {
00054                      rfc2231_paramDestroy(*paramList);
00055                      return -1;
00056               }
00057 
00058               /*
00059               ** A non-rfc 2231 parameter has paramnum set to 0, an
00060               ** rfc 2231 parameter has paramnum set to its number, plus 1.
00061               */
00062 
00063               if (*p == 0)
00064               {
00065                      n->paramnum=0;
00066               }
00067               else
00068               {
00069                      p++;
00070 
00071                      n->paramnum=atoi(p)+1;
00072 
00073                      if (n->paramnum <= 0)
00074                             n->paramnum=1;
00075               }
00076 
00077               p=strrchr(attrName, '*');
00078 
00079               n->encoded=p && p[1] == 0;
00080               n->value=attrValue;
00081 
00082               for (o=paramList; *o; o= &(*o)->next)
00083                      if ( (*o)->paramnum > n->paramnum)
00084                             break;
00085 
00086               n->next= *o;
00087               *o=n;
00088        }
00089        return 0;
00090 }
00091 
00092 
00093 /*
00094 ** Create a link list of rfc2231param structures for a specific attribute
00095 **
00096 ** Returns: 0 - ok, < 0 - out of memory.
00097 */
00098 
00099 static int rfc2231_paramCreate(struct rfc2045attr *attr,
00100                             const char *name,
00101                             struct rfc2231param **paramList)
00102 {
00103        *paramList=NULL;
00104 
00105        while (attr)
00106        {
00107               if (rfc2231_buildAttrList(paramList, name, attr->name,
00108                                      attr->value) < 0)
00109                      return (-1);
00110               attr=attr->next;
00111        }
00112 
00113        return (0);
00114 }
00115 
00116 static const char rfc2231_xdigit[]="0123456789ABCDEFabcdef";
00117 
00118 static int nyb(char c)
00119 {
00120        const char *p=strchr(rfc2231_xdigit, c);
00121        int n;
00122 
00123        if (!p)
00124               return 0;
00125 
00126        n=p-rfc2231_xdigit;
00127 
00128        if (n >= 16)
00129               n -= 6;
00130 
00131        return n;
00132 }
00133 
00134 /*
00135 ** Decode an rfc2231param link list.
00136 **
00137 ** charset, language, text, are decoded, if the corresponding args below are
00138 ** not null.  Their corresponding lengths (including the null bytes) are
00139 ** always saved in the corresponding int args.  rfc2231_decode() is called
00140 ** twice to get the lengths, then once again after the buffers are allocated.
00141 */
00142 
00143 void rfc2231_paramDecode(struct rfc2231param *paramList,
00144                       char *charsetPtr,
00145                       char *langPtr,
00146                       char *textPtr,
00147                       int *charsetLen,
00148                       int *langLen,
00149                       int *textLen)
00150 {
00151        int first=1;
00152 
00153        *charsetLen=*langLen=*textLen=1;   /* null byte */
00154 
00155        if (paramList && paramList->paramnum == 0 &&
00156            paramList->next)
00157               paramList=paramList->next;
00158        /*
00159        ** Both a non-rfc2231 and an rfc2231 parameter was specified, so
00160        ** take the better one.
00161        */
00162 
00163        while (paramList)
00164        {
00165               const char *p=paramList->value;
00166 
00167               if (first && paramList->encoded)
00168               {
00169                      const char *q=strchr(p, '\'');
00170 
00171                      if (q && strchr(q+1, '\''))
00172                      {
00173                             while (*p != '\'')
00174                             {
00175                                    if (charsetPtr)
00176                                           *charsetPtr++ = *p;
00177                                    p++;
00178                                    (*charsetLen)++;
00179                             }
00180                             p++;
00181                             while (*p != '\'')
00182                             {
00183                                    if (langPtr)
00184                                           *langPtr++ = *p;
00185                                    p++;
00186                                    (*langLen)++;
00187                             }
00188                             p++;
00189                      }
00190               }
00191 
00192               first=0;
00193 
00194               while (*p)
00195               {
00196                      if (*p == '%' && p[1] && p[2] && paramList->encoded)
00197                      {
00198                             if (textPtr)
00199                                    *textPtr++ = nyb(p[1]) * 16 +
00200                                           nyb(p[2]);
00201                             p += 3;
00202                      }
00203                      else
00204                      {
00205                             if (textPtr)
00206                                    *textPtr++ = *p;
00207 
00208                             p++;
00209                      }
00210 
00211                      (*textLen)++;
00212               }
00213 
00214               paramList=paramList->next;
00215        }
00216 
00217        if (charsetPtr)
00218               *charsetPtr=0;
00219        if (langPtr)
00220               *langPtr=0;
00221        if (textPtr)
00222               *textPtr=0;
00223 }
00224 
00225 /*
00226 ** Retrieve RFC 2231 information from a specific rfc2045attr list
00227 **
00228 ** Returns 0 success, -1 for failure
00229 */
00230 
00231 static int rfc2231_decode(struct rfc2045attr *attrList,
00232                        const char *name,
00233 
00234                        char **chsetPtr,
00235                        char **langPtr,
00236                        char **textPtr)
00237 {
00238        int chsetLen;
00239        int langLen;
00240        int textLen;
00241 
00242        struct rfc2231param *paramList;
00243 
00244        if (rfc2231_paramCreate(attrList, name, &paramList) < 0)
00245               return -1;
00246 
00247        rfc2231_paramDecode(paramList, NULL, NULL, NULL,
00248                          &chsetLen,
00249                          &langLen,
00250                          &textLen);
00251 
00252        if (chsetPtr)
00253               *chsetPtr=NULL;
00254 
00255        if (langPtr)
00256               *langPtr=NULL;
00257 
00258        if (textPtr)
00259               *textPtr=NULL;
00260 
00261 
00262        if ((chsetPtr && (*chsetPtr=malloc(chsetLen)) == NULL)
00263            || (langPtr && (*langPtr=malloc(langLen)) == NULL)
00264            || (textPtr && (*textPtr=malloc(textLen)) == NULL))
00265        {
00266               rfc2231_paramDestroy(paramList);
00267 
00268               if (*chsetPtr)
00269                      free(*chsetPtr);
00270 
00271               if (*langPtr)
00272                      free(*langPtr);
00273 
00274               if (*textPtr)
00275                      free(*textPtr);
00276               return (-1);
00277        }
00278 
00279        rfc2231_paramDecode(paramList,
00280                          chsetPtr ? *chsetPtr:NULL,
00281                          langPtr ? *langPtr:NULL,
00282                          textPtr ? *textPtr:NULL,
00283                          &chsetLen,
00284                          &langLen,
00285                          &textLen);
00286        return 0;
00287 }
00288 
00289 int rfc2231_decodeType(struct rfc2045 *rfc, const char *name,
00290                      char **chsetPtr,
00291                      char **langPtr,
00292                      char **textPtr)
00293 {
00294        return rfc2231_decode(rfc->content_type_attr, name,
00295                            chsetPtr, langPtr, textPtr);
00296 }
00297 
00298 int rfc2231_decodeDisposition(struct rfc2045 *rfc, const char *name,
00299                            char **chsetPtr,
00300                            char **langPtr,
00301                            char **textPtr)
00302 {
00303        return rfc2231_decode(rfc->content_disposition_attr, name,
00304                            chsetPtr, langPtr, textPtr);
00305 }
00306 
00307 static int conv_unicode(char **text, const char *fromChset,
00308                      const char *toChset)
00309 {
00310        int err;
00311        char *p;
00312 
00313        if (!toChset)
00314               toChset=unicode_default_chset();
00315 
00316        if (!fromChset || !*fromChset)
00317               return 0;
00318 
00319        p=libmail_u_convert_tobuf(*text, fromChset, toChset, &err);
00320 
00321        if (p && err)
00322        {
00323               free(p);
00324               p=NULL;
00325        }
00326 
00327        if (!p)
00328               return (-1);
00329 
00330        free(*text);
00331        *text=p;
00332        return (0);
00333 }
00334 
00335 int rfc2231_udecodeType(struct rfc2045 *rfc, const char *name,
00336                      const char *myCharset,
00337                      char **textPtr)
00338 {
00339        char *text, *chset;
00340 
00341        if (rfc2231_decodeType(rfc, name, &chset, NULL, &text) < 0)
00342               return (-1);
00343 
00344        if (conv_unicode(&text, chset, myCharset) < 0)
00345        {
00346               free(text);
00347               free(chset);
00348               return (-1);
00349        }
00350 
00351        *textPtr=text;
00352        free(chset);
00353        return (0);
00354 }
00355 
00356 int rfc2231_udecodeDisposition(struct rfc2045 *rfc, const char *name,
00357                             const char *myCharset,
00358                             char **textPtr)
00359 {
00360        char *text, *chset;
00361 
00362        if (rfc2231_decodeDisposition(rfc, name, &chset, NULL, &text) < 0)
00363               return (-1);
00364 
00365        if (conv_unicode(&text, chset, myCharset) < 0)
00366        {
00367               free(text);
00368               free(chset);
00369               return (-1);
00370        }
00371 
00372        *textPtr=text;
00373        free(chset);
00374        return (0);
00375 }