Changeset 3191

Show
Ignore:
Timestamp:
12/23/07 18:14:00
Author:
pvanhoof
Message:
        • Ported a patch for the rfc2047 decoder from Jacky gtkdict at yahoo.com.cn
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/ChangeLog

    r3187 r3191  
    44        two libs are not going to be supported in Tinymail 1.0 
    55        * Improvements to the NAMESPACE, LIST and LSUB things 
     6        * Ported a patch for the rfc2047 decoder from Jacky gtkdict at yahoo.com.cn 
    67 
    782007-12-22  Philip Van Hoof <pvanhoof@gnome.org> 
  • trunk/libtinymail-camel/camel-lite/camel/camel-mime-utils.c

    r3137 r3191  
    822822} 
    823823 
     824static void 
     825print_hex (unsigned char *data, size_t len) 
     826{ 
     827        size_t i, x; 
     828        unsigned char *p = data; 
     829        char high, low; 
     830 
     831        x = 0; 
     832        printf ("%04u    ", x); 
     833        for (i = 0; i < len; i++) { 
     834                high = *p >> 4; 
     835                high = (high<10) ? high + '0' : high + 'a' - 10; 
     836 
     837                low = *p & 0x0f; 
     838                low = (low<10) ? low + '0' : low + 'a' - 10; 
     839 
     840                printf ("0x%c%c  ", high, low); 
     841 
     842                p++; 
     843                x++; 
     844                if (i % 8 == 7) { 
     845                        printf ("\n%04u    ", x); 
     846                } 
     847        } 
     848        printf ("\n"); 
     849} 
     850 
     851static size_t 
     852conv_to_utf8 (const char *encname, char *in, size_t inlen, char *out, size_t outlen) 
     853{ 
     854        char *charset, *inbuf, *outbuf; 
     855        iconv_t ic; 
     856        size_t inbuf_len, outbuf_len, ret; 
     857 
     858        charset = (char *) e_iconv_charset_name (encname); 
     859 
     860        ic = e_iconv_open ("UTF-8", charset); 
     861        if (ic == (iconv_t) -1) { 
     862                printf ("e_iconv_open() error\n"); 
     863                return (size_t)-1; 
     864        } 
     865 
     866        inbuf = in; 
     867        inbuf_len = inlen; 
     868 
     869        outbuf = out; 
     870        outbuf_len = outlen; 
     871 
     872        ret = e_iconv (ic, (const char **) &inbuf, &inbuf_len, &outbuf, &outbuf_len); 
     873        if (ret == (size_t)-1) { 
     874                printf ("e_iconv() error! source charset is %s, target charset is %s\n", charset, "UTF-8"); 
     875                printf ("converted %u bytes, but last %u bytes can't convert!!\n", inlen - inbuf_len, inbuf_len); 
     876                printf ("source data:\n"); 
     877                print_hex (in, inlen); 
     878 
     879                *outbuf = '\0'; 
     880                printf ("target string is \"%s\"\n", out); 
     881 
     882                return (size_t)-1; 
     883        } 
     884 
     885        ret = outlen - outbuf_len; 
     886        out[ret] = '\0'; 
     887 
     888        e_iconv_close (ic); 
     889 
     890        return ret; 
     891} 
     892 
    824893/* decode rfc 2047 encoded string segment */ 
     894#define DECWORD_LEN 1024 
     895#define UTF8_DECWORD_LEN 2048 
     896 
    825897static char * 
    826898rfc2047_decode_word(const char *in, size_t len) 
    827899{ 
    828         const char *inptr = in+2; 
    829         const char *inend = in+len-2; 
    830         const char *inbuf; 
    831         const char *charset; 
    832         char *encname, *p; 
    833         int tmplen; 
    834         size_t ret; 
    835         char *decword = NULL; 
    836         char *decoded = NULL; 
    837         char *outbase = NULL; 
    838         char *outbuf; 
    839         size_t inlen, outlen; 
    840         gboolean retried = FALSE; 
    841         iconv_t ic; 
    842         int idx = 0; 
     900        char prev_charset[32], curr_charset[32]; 
     901        char encode; 
     902        char *start, *inptr, *inend; 
     903        char decword[DECWORD_LEN], utf8_decword[UTF8_DECWORD_LEN]; 
     904        char *decword_ptr, *utf8_decword_ptr; 
     905        size_t inlen, outlen, ret; 
    843906 
    844907        d(printf("rfc2047: decoding '%.*s'\n", len, in)); 
    845908 
     909        prev_charset[0] = curr_charset[0] = '\0'; 
     910 
     911        decword_ptr = decword; 
     912        utf8_decword_ptr = utf8_decword; 
     913 
    846914        /* quick check to see if this could possibly be a real encoded word */ 
    847  
    848         if (len < 8 || !(in[0] == '=' && in[1] == '?')) { 
     915        if (len < 8 
     916            || !(in[0] == '=' && in[1] == '?' 
     917                 && in[len-1] == '=' && in[len-2] == '?')) { 
    849918                d(printf("invalid\n")); 
    850919                return NULL; 
    851920        } 
    852921 
    853         /* skip past the charset to the encoding type */ 
    854         inptr = memchr (inptr, '?', inend-inptr); 
    855         if (inptr != NULL && inptr < inend + 2 && inptr[2] == '?') { 
    856                 d(printf("found ?, encoding is '%c'\n", inptr[0])); 
     922        inptr = (char *) in; 
     923        inend = (char *) (in + len); 
     924        outlen = sizeof(utf8_decword); 
     925 
     926        while (inptr < inend) { 
     927                /* begin */ 
     928                inptr = memchr (inptr, '?', inend-inptr); 
     929                if (!inptr || *(inptr-1) != '=') { 
     930                        return NULL; 
     931                } 
     932 
    857933                inptr++; 
    858                 tmplen = inend-inptr-2; 
    859                 decword = g_alloca (tmplen); /* this will always be more-than-enough room */ 
    860                 switch(toupper(inptr[0])) { 
     934 
     935                /* charset */ 
     936                start = inptr; 
     937                inptr = memchr (inptr, '?', inend-inptr); 
     938                if (!inptr) { 
     939                        return NULL; 
     940                } 
     941                strncpy (curr_charset, start, inptr-start); /* maybe overflow */ 
     942                curr_charset[inptr-start] = '\0'; 
     943                if (prev_charset[0] == '\0') { /* first charset in multi encode words */ 
     944                        strcpy (prev_charset, curr_charset); 
     945                } 
     946                d(printf ("curr_charset = %s\n", curr_charset)); 
     947 
     948                /* if (charset.perv != charset.curr) iconv perv to utf8 */ 
     949                if (prev_charset[0] != '\0' && strcmp(prev_charset, curr_charset)) { 
     950                        inlen = decword_ptr - decword; 
     951                        ret = conv_to_utf8 (prev_charset, decword, inlen, utf8_decword_ptr, outlen); 
     952                        if (ret == (size_t)-1) { 
     953                                printf ("conv_to_utf8() error!\n"); 
     954                                return NULL; 
     955                        } 
     956 
     957                        utf8_decword_ptr += ret; 
     958                        outlen = outlen - ret; 
     959 
     960                        decword_ptr = decword; /* reset decword_ptr */ 
     961                        strcpy (prev_charset, curr_charset); 
     962                } 
     963 
     964                /* encode */ 
     965                inptr++; 
     966                encode = *inptr; 
     967                inptr++; 
     968                if (*inptr != '?') { 
     969                        return NULL; 
     970                } 
     971 
     972                /* text */ 
     973                inptr++; 
     974                start = inptr; 
     975                inptr = memchr (inptr, '?', inend-inptr); 
     976                if (!inptr || *(inptr+1) != '=') { 
     977                        return NULL; 
     978                } 
     979 
     980                /* decode */ 
     981                switch(encode) { 
     982 
    861983                case 'Q': 
    862                         inlen = quoted_decode((const unsigned char *) inptr+2, tmplen, (unsigned char *) decword); 
     984                case 'q': 
     985                        inlen = quoted_decode(start, inptr-start, decword_ptr); 
    863986                        break; 
    864                 case 'B': { 
    865                         int state = 0; 
    866                         unsigned int save = 0; 
    867  
    868                         inlen = camel_base64_decode_step((unsigned char *) inptr+2, tmplen, (unsigned char *) decword, &state, &save); 
    869                         /* if state != 0 then error? */ 
     987                case 'B': 
     988                case 'b': 
     989                        { 
     990                                int state = 0; 
     991                                unsigned int save = 0; 
     992 
     993                                inlen = camel_base64_decode_step(start, inptr-start, decword_ptr, &state, &save); 
     994                                /* if state != 0 then error? */ 
     995                        } 
    870996                        break; 
    871                 } 
    872997                default: 
    873998                        /* uhhh, unknown encoding type - probably an invalid encoded word string */ 
     
    8761001                d(printf("The encoded length = %d\n", inlen)); 
    8771002                if (inlen > 0) { 
    878                         /* yuck, all this snot is to setup iconv! */ 
    879                         tmplen = inptr - in - 3; 
    880                         encname = g_alloca (tmplen + 1); 
    881                         memcpy (encname, in + 2, tmplen); 
    882                         encname[tmplen] = '\0'; 
    883  
    884                         /* rfc2231 updates rfc2047 encoded words... 
    885                          * The ABNF given in RFC 2047 for encoded-words is: 
    886                          *   encoded-word := "=?" charset "?" encoding "?" encoded-text "?=" 
    887                          * This specification changes this ABNF to: 
    888                          *   encoded-word := "=?" charset ["*" language] "?" encoding "?" encoded-text "?=" 
    889                          */ 
    890  
    891                         /* trim off the 'language' part if it's there... */ 
    892                         p = strchr (encname, '*'); 
    893                         if (p) 
    894                                 *p = '\0'; 
    895  
    896                         charset = e_iconv_charset_name (encname); 
    897  
    898                         inbuf = decword; 
    899  
    900                         outlen = inlen * 6 + 16; 
    901                         outbase = g_alloca (outlen); 
    902                         outbuf = outbase; 
    903  
    904                 retry: 
    905                         ic = e_iconv_open ("UTF-8", charset); 
    906                         if (ic != (iconv_t) -1) { 
    907                                 ret = e_iconv (ic, &inbuf, &inlen, &outbuf, &outlen); 
    908                                 if (ret != (size_t) -1) { 
    909                                         e_iconv (ic, NULL, 0, &outbuf, &outlen); 
    910                                         *outbuf = 0; 
    911                                         decoded = g_strdup (outbase); 
    912                                 } else { 
    913                                         perror ("iconv"); 
    914                                         e_iconv (ic, NULL, 0, &outbuf, &outlen); 
    915                                         *outbuf = 0; 
    916                                         decoded = g_strdup (outbase); 
    917                                         /* decoded = g_strdup (inbuf); */ 
    918                                 } 
    919  
    920                                 e_iconv_close (ic); 
    921                         } else { 
    922                                 w(g_warning ("Cannot decode charset, header display may be corrupt: %s: %s", 
    923                                              charset, strerror (errno))); 
    924  
    925                                 if (!retried) { 
    926                                         charset = e_iconv_locale_charset (); 
    927                                         if (!charset) 
    928                                                 charset = "iso-8859-1"; 
    929  
    930                                         retried = TRUE; 
    931                                         goto retry; 
    932                                 } 
    933  
    934                                 /* we return the encoded word here because we've got to return valid utf8 */ 
    935                                 decoded = g_strndup (in, inlen); 
    936                         } 
    937                 } 
    938         } 
    939  
    940         d(printf("decoded '%s'\n", decoded)); 
    941  
    942         return decoded; 
     1003                        decword_ptr += inlen; 
     1004                } else { 
     1005                        return NULL; 
     1006                } 
     1007 
     1008                inptr += 2;     /* skip '?=' */ 
     1009        } /* end of "while (inptr < inend)" */ 
     1010 
     1011        /* at last, iconv to utf8 */ 
     1012        inlen = decword_ptr - decword; 
     1013        ret = conv_to_utf8 (curr_charset, decword, inlen, utf8_decword_ptr, outlen); 
     1014        if (ret == (size_t)-1) { 
     1015                printf ("conv_to_utf8() error!\n"); 
     1016                return NULL; 
     1017        } 
     1018 
     1019        utf8_decword_ptr += ret; 
     1020        *utf8_decword_ptr = '\0'; 
     1021 
     1022        d(printf("decoded '%s'\n", utf8_decword)); 
     1023 
     1024        return strdup (utf8_decword); 
    9431025} 
    9441026 
     
    10151097} 
    10161098 
     1099typedef enum { 
     1100        BEGIN, 
     1101        BEGIN_SPACE, 
     1102        NOENCODED_WORD, 
     1103        ENCODED_WORD_CHARSET, 
     1104        ENCODED_WORD_ENCODED_TEXT, 
     1105        ENCODED_WORD_END, 
     1106        ENCODED_WORD_END_SPACE, 
     1107        END 
     1108} StatsType; 
     1109 
    10171110/* decodes a simple text, rfc822 + rfc2047 */ 
    10181111static char * 
     
    10201113{ 
    10211114        GString *out; 
    1022         const char *inptr, *inend, *start, *chunk, *locale_charset
    1023         GString *(* append) (GString *, const char *, gssize)
     1115        StatsType stats
     1116        const char *inptr, *inend, *start, *locale_charset;
    10241117        char *dword = NULL; 
    1025         guint32 mask; 
    10261118 
    10271119        locale_charset = e_iconv_locale_charset (); 
    1028  
    1029         if (ctext) { 
    1030                 mask = (CAMEL_MIME_IS_SPECIAL | CAMEL_MIME_IS_SPACE | CAMEL_MIME_IS_CTRL); 
    1031                 append = append_quoted_pair; 
    1032         } else { 
    1033                 mask = (CAMEL_MIME_IS_LWSP); 
    1034                 append = g_string_append_len; 
    1035         } 
    10361120 
    10371121        out = g_string_new (""); 
    10381122        inptr = in; 
    10391123        inend = inptr + inlen; 
    1040         chunk = NULL; 
    1041  
    1042         while (inptr < inend) { 
    1043                 start = inptr; 
    1044                 while (inptr < inend && camel_mime_is_type (*inptr, mask)) 
    1045                         inptr++; 
    1046  
    1047                 if (inptr == inend) { 
    1048                         append (out, start, inptr - start); 
     1124 
     1125        stats = BEGIN; 
     1126 
     1127        /* we'll get multi encoded word, and then decode them! */ 
     1128        while (stats != END) { 
     1129                switch (stats) { 
     1130                case BEGIN: 
     1131                        if (isspace(*inptr)) { 
     1132                                stats = BEGIN_SPACE; 
     1133                                start = inptr; 
     1134                        } else if (*inptr == '=' && *(inptr+1) == '?') { 
     1135                                stats = ENCODED_WORD_CHARSET; 
     1136                                start = inptr; 
     1137                                inptr++; 
     1138                        } else if (*inptr == '\0') { 
     1139                                stats = END; 
     1140                        } else { //if (isgraph(*inptr)) { // we accept multi-byte encode 
     1141                                stats = NOENCODED_WORD; 
     1142                                start = inptr; 
     1143                        } 
    10491144                        break; 
    1050                 } else if (dword == NULL) { 
    1051                         append (out, start, inptr - start); 
    1052                 } else { 
    1053                         chunk = start; 
    1054                 } 
    1055  
    1056                 start = inptr; 
    1057                 while (inptr < inend && !camel_mime_is_type (*inptr, mask)) 
    1058                         inptr++; 
    1059  
    1060                 dword = rfc2047_decode_word(start, inptr-start); 
    1061                 if (dword) { 
    1062                         g_string_append(out, dword); 
    1063                         g_free(dword); 
    1064                 } else { 
    1065                         if (!chunk) 
    1066                                 chunk = start; 
    1067  
    1068                         if ((default_charset == NULL || !append_8bit (out, chunk, inptr-chunk, default_charset)) 
    1069                             && (locale_charset == NULL || !append_8bit(out, chunk, inptr-chunk, locale_charset))) { 
    1070  
    1071                          
    1072                                 append_latin1(out, chunk, inptr-chunk); 
    1073                         } 
    1074                 } 
    1075  
    1076                 chunk = NULL; 
     1145 
     1146                case BEGIN_SPACE: 
     1147                        if (isspace(*inptr)) { 
     1148                                /* do nothing */ 
     1149                        } else if (*inptr == '=' && *(inptr+1) == '?') { 
     1150                                stats = ENCODED_WORD_CHARSET; 
     1151                                start = inptr; 
     1152                                inptr++; 
     1153                        } else if (*inptr == '\0') { 
     1154                                stats = END; 
     1155                        } else { //if (isgraph(*inptr)) { // we accept multi-byte encode 
     1156                                stats = NOENCODED_WORD; 
     1157                                start = inptr; 
     1158                        } 
     1159                        break; 
     1160 
     1161                case NOENCODED_WORD: 
     1162                        if (isspace(*inptr)) { 
     1163                                /* do nothing */ 
     1164                        } else if (*inptr == '=' && *(inptr+1) == '?') { 
     1165                                if ((default_charset == NULL || !append_8bit (out, start, inptr - start, default_charset)) 
     1166                                      && (locale_charset == NULL || !append_8bit (out, start, inptr - start, locale_charset))) 
     1167                                        append_latin1 (out, start, inptr - start); 
     1168 
     1169                                stats = ENCODED_WORD_CHARSET; 
     1170                                start = inptr; 
     1171                                inptr++; 
     1172                        } else if (*inptr == '\0') { 
     1173                                inptr--; 
     1174                                while (isspace(*inptr)) { 
     1175                                        inptr--; 
     1176                                } 
     1177                                if ((default_charset == NULL || !append_8bit (out, start, inptr + 1 - start, default_charset)) 
     1178                                                && (locale_charset == NULL || !append_8bit (out, start, inptr + 1 - start, locale_charset))) 
     1179                                        append_latin1 (out, start, inptr - start); 
     1180 
     1181                                stats = END; 
     1182                        } else { //if (isgraph(*inptr)) { // we accept multi-byte encode 
     1183                                /* do nothing */ 
     1184                        } 
     1185                        break; 
     1186           
     1187                case ENCODED_WORD_CHARSET: 
     1188                        if (isspace (*inptr)) { 
     1189                                stats = NOENCODED_WORD; 
     1190                        } else if (*inptr == '?') { 
     1191                                inptr++; 
     1192                                if ((*inptr == 'Q' || *inptr == 'q' 
     1193                                     || *inptr == 'B' || *inptr == 'b') 
     1194                                    && *(inptr+1) == '?') { 
     1195                                        inptr++; 
     1196                                        stats = ENCODED_WORD_ENCODED_TEXT; 
     1197                                } else { 
     1198                                        stats = NOENCODED_WORD; 
     1199                                } 
     1200                        } else if (*inptr == '\0') { 
     1201                                if ((default_charset == NULL || !append_8bit (out, start, inptr + 1 - start, default_charset)) 
     1202                                      && (locale_charset == NULL || !append_8bit (out, start, inptr + 1 - start, locale_charset))) 
     1203                                        append_latin1 (out, start, inptr - start); 
     1204 
     1205                                stats = END; 
     1206                        } else if (isgraph(*inptr)) { 
     1207                                /* do nothing */ 
     1208                        } else { 
     1209                                /* impossible */ 
     1210                        } 
     1211                        break; 
     1212 
     1213                case ENCODED_WORD_ENCODED_TEXT: 
     1214                        if (isspace (*inptr)) { 
     1215                                stats = NOENCODED_WORD; /* maybe do nothing */ 
     1216                        } else if (*inptr == '?' && *(inptr+1) == '=') { 
     1217                                /* we will decode it in stats ENCODED_WORD_END */ 
     1218                                stats = ENCODED_WORD_END; 
     1219                                inptr++; 
     1220                        } else if (*inptr == '\0') { 
     1221                                if ((default_charset == NULL || !append_8bit (out, start, inptr + 1 - start, default_charset)) 
     1222                                      && (locale_charset == NULL || !append_8bit (out, start, inptr + 1 - start, locale_charset))) 
     1223                                        append_latin1 (out, start, inptr - start); 
     1224 
     1225                                stats = END; 
     1226                        } else if (isgraph(*inptr)) { 
     1227                                /* do nothing */ 
     1228                        } else { 
     1229                                /* impossible */ 
     1230                        } 
     1231                        break; 
     1232           
     1233                case ENCODED_WORD_END: 
     1234                        if (isspace(*inptr)) { 
     1235                                /* fix some buggy mail clients */ 
     1236                                stats = ENCODED_WORD_END_SPACE; 
     1237                        } else if (*inptr == '=' && *(inptr+1) == '?') { 
     1238                                stats = ENCODED_WORD_CHARSET; 
     1239                                inptr++; 
     1240                        } else { 
     1241                                dword = rfc2047_decode_word (start, inptr - start); 
     1242                                if (dword) { 
     1243                                        g_string_append (out, dword); 
     1244                                        g_free (dword); 
     1245                                } else { 
     1246                                        if ((default_charset == NULL || !append_8bit (out, start, inptr + 1 - start, default_charset)) 
     1247                                              && (locale_charset == NULL || !append_8bit (out, start, inptr + 1 - start, locale_charset))) 
     1248                                                append_latin1 (out, start, inptr - start); 
     1249                                } 
     1250 
     1251                                if (*inptr == '\0') { 
     1252                                        stats = END; 
     1253                                } else { //if (isgraph(*inptr)) { // we accept multi-byte encode 
     1254                                        start = inptr; 
     1255                                        stats = NOENCODED_WORD; 
     1256                                } 
     1257                        } 
     1258                        break; 
     1259           
     1260                case ENCODED_WORD_END_SPACE: 
     1261                        if (isspace(*inptr)) { 
     1262                                /* do nothing */ 
     1263                        } else if (*inptr == '=' && *(inptr+1) == '?') { 
     1264                                /* yes, combine two encoded words */ 
     1265                                stats = ENCODED_WORD_CHARSET; 
     1266                                inptr++; 
     1267                        } else { 
     1268                                if (*inptr == '\0') { 
     1269                                        stats = END; 
     1270                                } else { //if (isgraph(*inptr)) { // we accept multi-byte encode 
     1271                                        stats = NOENCODED_WORD; 
     1272                                } 
     1273 
     1274                                inptr--; 
     1275                                while (isspace(*inptr)) { 
     1276                                        inptr--; 
     1277                                } 
     1278                                inptr++; 
     1279 
     1280                                dword = rfc2047_decode_word (start, inptr - start); 
     1281                                if (dword) { 
     1282                                        g_string_append (out, dword); 
     1283                                        g_free (dword); 
     1284                                } else { 
     1285                                        if ((default_charset == NULL || !append_8bit (out, start, inptr + 1 - start, default_charset)) 
     1286                                              && (locale_charset == NULL || !append_8bit (out, start, inptr + 1 - start, locale_charset))) 
     1287                                                append_latin1 (out, start, inptr - start); 
     1288                                } 
     1289 
     1290                                if (stats == NOENCODED_WORD) { 
     1291                                        start = inptr; 
     1292                                } 
     1293                        } 
     1294                        break; 
     1295           
     1296                default: 
     1297                        /* impossible */ 
     1298                        break; 
     1299                } 
     1300 
     1301                inptr++; 
    10771302        } 
    10781303 
  • trunk/libtinymail-camel/camel-lite/libedataserver/e-iconv.c

    r1672 r3191  
    144144        { "5601",           "EUC-KR"     }, 
    145145        { "zh_TW-euc",      "EUC-TW"     }, 
    146         { "zh_CN.euc",      "gb2312"     }, 
     146        { "zh_CN.euc",      "GBK"     }, 
    147147        { "zh_TW-big5",     "BIG5"       }, 
    148         { "euc-cn",         "gb2312"     }, 
     148        { "euc-cn",         "GBK"     }, 
    149149        { "big5-0",         "BIG5"       }, 
    150150        { "big5.eten-0",    "BIG5"       }, 
    151151        { "big5hkscs-0",    "BIG5HKSCS"  }, 
    152         { "gb2312-0",       "gb2312"     }, 
    153         { "gb2312.1980-0",  "gb2312"     }, 
    154         { "gb-2312",        "gb2312"     }, 
     152        { "gb2312",         "GBK"     }, 
     153        { "gb2312-0",       "GBK"     }, 
     154        { "gb2312.1980-0",  "GBK"     }, 
     155        { "gb-2312",        "GBK"     }, 
    155156        { "gb18030-0",      "gb18030"    }, 
    156157        { "gbk-0",          "GBK"        },