Back to index

enigmail  1.4.3
mimehdrs2.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is mozilla.org code.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1998
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  * Ramalingam Saravanan <sarava@sarava.net>
00023  * Patrick Brunschwig <patrick@mozilla-enigmail.org>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include <ctype.h>
00040 
00041 #define MOZILLA_INTERNAL_API
00042 #include "nspr.h"
00043 #include "nsCOMPtr.h"
00044 #include "msgCore.h"
00045 #include "plstr.h"
00046 #include "nsMailHeaders.h"
00047 #include "msgCore.h"
00048 #include "mimehdrs2.h"
00049 #undef MOZILLA_INTERNAL_API
00050 
00051 #include "enigmail.h"
00052 
00053 #define HEX_ESCAPE '%'
00054 
00055 #define UNHEX(C) \
00056     ((C >= '0' && C <= '9') ? C - '0' : \
00057      ((C >= 'A' && C <= 'F') ? C - 'A' + 10 : \
00058      ((C >= 'a' && C <= 'f') ? C - 'a' + 10 : 0)))
00059 
00060 
00061 static PRInt32 __nsUnescapeCount(char * str)
00062 {
00063     register char *src = str;
00064     register char *dst = str;
00065     static const char hexChars[] = "0123456789ABCDEFabcdef";
00066 
00067     char c1[] = " ";
00068     char c2[] = " ";
00069     char* const pc1 = c1;
00070     char* const pc2 = c2;
00071 
00072     while (*src)
00073     {
00074         c1[0] = *(src+1);
00075         if (*(src+1) == '\0')
00076             c2[0] = '\0';
00077         else
00078             c2[0] = *(src+2);
00079 
00080         if (*src != HEX_ESCAPE || PL_strpbrk(pc1, hexChars) == 0 ||
00081                                   PL_strpbrk(pc2, hexChars) == 0 )
00082               *dst++ = *src++;
00083         else
00084               {
00085               src++; /* walk over escape */
00086               if (*src)
00087             {
00088               *dst = UNHEX(*src) << 4;
00089               src++;
00090             }
00091               if (*src)
00092             {
00093               *dst = (*dst + UNHEX(*src));
00094               src++;
00095             }
00096               dst++;
00097         }
00098     }
00099 
00100     *dst = 0;
00101     return (int)(dst - str);
00102 
00103 } /* NET_UnEscapeCnt */
00104 
00105 static char* __nsUnescape(char * str)
00106 {
00107        __nsUnescapeCount(str);
00108        return str;
00109 }
00110 
00111 
00112 EMBool MimeHeaders_IsAsciiSpace(PRUnichar aChar) {
00113   return ((aChar == ' ') || (aChar == '\r') ||
00114           (aChar == '\n') || (aChar == '\t'));
00115 }
00116 
00117 char *
00118 MimeHeaders_get_parameter (const char *header_value, const char *parm_name,
00119                                              char **charset, char **language)
00120 {
00121   const char *str;
00122   char *s = NULL; /* parm value to be returned */
00123   PRInt32 parm_len;
00124   if (!header_value || !parm_name || !*header_value || !*parm_name)
00125        return 0;
00126 
00127   /* The format of these header lines is
00128         <token> [ ';' <token> '=' <token-or-quoted-string> ]*
00129    */
00130 
00131   if (charset) *charset = NULL;
00132   if (language) *language = NULL;
00133 
00134   str = header_value;
00135   parm_len = strlen(parm_name);
00136 
00137   /* Skip forward to first ';' */
00138   for (; *str && *str != ';' && *str != ','; str++)
00139        ;
00140   if (*str)
00141        str++;
00142   /* Skip over following whitespace */
00143   for (; *str && MimeHeaders_IsAsciiSpace(*str); str++)
00144        ;
00145   if (!*str)
00146        return 0;
00147 
00148   while (*str)
00149        {
00150          const char *token_start = str;
00151          const char *token_end = 0;
00152          const char *value_start = str;
00153          const char *value_end = 0;
00154 
00155          PR_ASSERT(!MimeHeaders_IsAsciiSpace(*str)); /* should be after whitespace already */
00156 
00157          /* Skip forward to the end of this token. */
00158          for (; *str && !MimeHeaders_IsAsciiSpace(*str) && *str != '=' && *str != ';'; str++)
00159               ;
00160          token_end = str;
00161 
00162          /* Skip over whitespace, '=', and whitespace */
00163          while (MimeHeaders_IsAsciiSpace (*str)) str++;
00164          if (*str == '=') str++;
00165          while (MimeHeaders_IsAsciiSpace (*str)) str++;
00166 
00167          if (*str != '"')
00168               {
00169                 /* The value is a token, not a quoted string. */
00170                 value_start = str;
00171                 for (value_end = str;
00172                         *value_end && !MimeHeaders_IsAsciiSpace (*value_end) && *value_end != ';';
00173                         value_end++)
00174                      ;
00175                 str = value_end;
00176               }
00177          else
00178               {
00179                 /* The value is a quoted string. */
00180                 str++;
00181                 value_start = str;
00182                 for (value_end = str; *value_end; value_end++)
00183                      {
00184                        if (*value_end == '\\')
00185                             value_end++;
00186                        else if (*value_end == '"')
00187                             break;
00188                      }
00189                 str = value_end+1;
00190               }
00191 
00192          /* See if this is the parameter we're looking for.
00193                If so, copy it and return.
00194           */
00195          if (token_end - token_start == parm_len &&
00196                 !PL_strncasecmp(token_start, parm_name, parm_len))
00197               {
00198                 s = (char *) PR_MALLOC ((value_end - value_start) + 1);
00199                 if (! s) return 0;  /* MIME_OUT_OF_MEMORY */
00200                 memcpy (s, value_start, value_end - value_start);
00201                 s [value_end - value_start] = 0;
00202                 /* if the parameter spans across multiple lines we have to strip out the
00203                       line continuatio -- jht 4/29/98 */
00204                 MIME_StripContinuations(s);
00205                 return s;
00206               }
00207          else if (token_end - token_start > parm_len &&
00208                         !PL_strncasecmp(token_start, parm_name, parm_len) &&
00209                         *(token_start+parm_len) == '*')
00210          {
00211                 /* RFC2231 - The legitimate parm format can be:
00212                       title*=us-ascii'en-us'This%20is%20weired.
00213                          or
00214                       title*0*=us-ascii'en'This%20is%20weired.%20We
00215                       title*1*=have%20to%20support%20this.
00216                       title*3="Else..."
00217                          or
00218                       title*0="Hey, what you think you are doing?"
00219                       title*1="There is no charset and language info."
00220                  */
00221                 const char *cp = token_start+parm_len+1; /* 1st char pass '*' */
00222                 EMBool needUnescape = *(token_end-1) == '*';
00223                 if ((*cp == '0' && needUnescape) || (token_end-token_start == parm_len+1))
00224                 {
00225                        const char *s_quote1 = PL_strchr(value_start, 0x27);
00226                        const char *s_quote2 = (char *) (s_quote1 ? PL_strchr(s_quote1+1, 0x27) : NULL);
00227                        PR_ASSERT(s_quote1 && s_quote2);
00228                        if (charset && s_quote1 > value_start && s_quote1 < value_end)
00229                        {
00230                               *charset = (char *) PR_MALLOC(s_quote1-value_start+1);
00231                               if (*charset)
00232                               {
00233                                      memcpy(*charset, value_start, s_quote1-value_start);
00234                                      *(*charset+(s_quote1-value_start)) = 0;
00235                               }
00236                        }
00237                        if (language && s_quote1 && s_quote2 && s_quote2 > s_quote1+1 &&
00238                               s_quote2 < value_end)
00239                        {
00240                               *language = (char *) PR_MALLOC(s_quote2-(s_quote1+1)+1);
00241                               if (*language)
00242                               {
00243                                      memcpy(*language, s_quote1+1, s_quote2-(s_quote1+1));
00244                                      *(*language+(s_quote2-(s_quote1+1))) = 0;
00245                               }
00246                        }
00247                        if (s_quote2 && s_quote2+1 < value_end)
00248                        {
00249                               PR_ASSERT(!s);
00250                               s = (char *) PR_MALLOC(value_end-(s_quote2+1)+1);
00251                               if (s)
00252                               {
00253                                      memcpy(s, s_quote2+1, value_end-(s_quote2+1));
00254                                      *(s+(value_end-(s_quote2+1))) = 0;
00255                                      if (needUnescape)
00256                                      {
00257                                             __nsUnescape(s);
00258                                             if (token_end-token_start == parm_len+1)
00259                                                    return s; /* we done; this is the simple case of
00260                                                                          encoding charset and language info
00261                                                                        */
00262                                      }
00263                               }
00264                        }
00265                 }
00266                 else if (IS_DIGIT(*cp))
00267                 {
00268                        PRInt32 len = 0;
00269                        char *ns = NULL;
00270                        if (s)
00271                        {
00272                               len = strlen(s);
00273                               ns = (char *) PR_Realloc(s, len+(value_end-value_start)+1);
00274                               if (!ns)
00275                     {
00276                                      PR_FREEIF(s);
00277                     }
00278                               else if (ns != s)
00279                                      s = ns;
00280                        }
00281                        else if (*cp == '0') /* must be; otherwise something is wrong */
00282                        {
00283                               s = (char *) PR_MALLOC(value_end-value_start+1);
00284                        }
00285                        /* else {} something is really wrong; out of memory */
00286                        if (s)
00287                        {
00288                               memcpy(s+len, value_start, value_end-value_start);
00289                               *(s+len+(value_end-value_start)) = 0;
00290                               if (needUnescape)
00291                                      __nsUnescape(s+len);
00292                        }
00293                 }
00294          }
00295 
00296          /* str now points after the end of the value.
00297                skip over whitespace, ';', whitespace. */
00298          while (MimeHeaders_IsAsciiSpace (*str)) str++;
00299          if (*str == ';') str++;
00300          while (MimeHeaders_IsAsciiSpace (*str)) str++;
00301        }
00302   return s;
00303 }
00304 
00305 /* Strip CR+LF runs within (original).
00306    Since the string at (original) can only shrink,
00307    this conversion is done in place. (original)
00308    is returned. */
00309 extern "C" char *
00310 MIME_StripContinuations(char *original)
00311 {
00312        char *p1, *p2;
00313 
00314        /* If we were given a null string, return it as is */
00315        if (!original) return NULL;
00316 
00317        /* Start source and dest pointers at the beginning */
00318        p1 = p2 = original;
00319 
00320        while(*p2)
00321        {
00322               /* p2 runs ahead at (CR and/or LF) */
00323               if ((p2[0] == '\r') || (p2[0] == '\n'))
00324               {
00325             p2++;
00326               } else {
00327             *p1++ = *p2++;
00328         }
00329        }
00330        *p1 = '\0';
00331 
00332        return original;
00333 }