unmime.c (4300B)
1 /* 2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client 3 * Copyright (C) 1999-2012 Hiroyuki Yamamoto and the Claws Mail team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 #include <glib.h> 21 #include <string.h> 22 #include <ctype.h> 23 24 #include "utils.h" 25 #include "codeconv.h" 26 #include "quoted-printable.h" 27 28 #define ENCODED_WORD_BEGIN "=?" 29 #define ENCODED_WORD_END "?=" 30 31 /* Decodes headers based on RFC2045 and RFC2047. */ 32 33 gchar *unmime_header(const gchar *encoded_str, gboolean addr_field) 34 { 35 const gchar *p = encoded_str; 36 const gchar *eword_begin_p, *encoding_begin_p, *text_begin_p, 37 *eword_end_p; 38 gchar charset[32]; 39 gchar encoding; 40 gchar *conv_str; 41 GString *outbuf; 42 gchar *out_str; 43 gsize out_len; 44 int in_quote = FALSE; 45 46 cm_return_val_if_fail(encoded_str != NULL, NULL); 47 48 outbuf = g_string_sized_new(strlen(encoded_str) * 2); 49 50 while (*p != '\0') { 51 gchar *decoded_text = NULL; 52 const gchar *quote_p; 53 gint len; 54 55 eword_begin_p = strstr(p, ENCODED_WORD_BEGIN); 56 if (!eword_begin_p) { 57 g_string_append(outbuf, p); 58 break; 59 } 60 61 quote_p = p; 62 while ((quote_p = strchr(quote_p, '"')) != NULL) { 63 if (quote_p && quote_p < eword_begin_p) { 64 /* Found a quote before the encoded word. */ 65 in_quote = !in_quote; 66 quote_p++; 67 } 68 if (quote_p >= eword_begin_p) 69 break; 70 } 71 72 encoding_begin_p = strchr(eword_begin_p + 2, '?'); 73 if (!encoding_begin_p) { 74 g_string_append(outbuf, p); 75 break; 76 } 77 text_begin_p = strchr(encoding_begin_p + 1, '?'); 78 if (!text_begin_p) { 79 g_string_append(outbuf, p); 80 break; 81 } 82 eword_end_p = strstr(text_begin_p + 1, ENCODED_WORD_END); 83 if (!eword_end_p) { 84 g_string_append(outbuf, p); 85 break; 86 } 87 88 if (p == encoded_str) { 89 g_string_append_len(outbuf, p, eword_begin_p - p); 90 p = eword_begin_p; 91 } else { 92 /* ignore spaces between encoded words */ 93 const gchar *sp; 94 95 for (sp = p; sp < eword_begin_p; sp++) { 96 if (!g_ascii_isspace(*sp)) { 97 g_string_append_len 98 (outbuf, p, eword_begin_p - p); 99 p = eword_begin_p; 100 break; 101 } 102 } 103 } 104 105 len = MIN(sizeof(charset) - 1, 106 encoding_begin_p - (eword_begin_p + 2)); 107 memcpy(charset, eword_begin_p + 2, len); 108 charset[len] = '\0'; 109 encoding = g_ascii_toupper(*(encoding_begin_p + 1)); 110 111 if (encoding == 'B') { 112 gchar *tmp; 113 tmp = g_strndup(text_begin_p + 1, eword_end_p - (text_begin_p + 1) + 1); 114 decoded_text = g_base64_decode(tmp, &out_len); 115 g_free(tmp); 116 } else if (encoding == 'Q') { 117 decoded_text = g_malloc 118 (eword_end_p - (text_begin_p + 1) + 1); 119 len = qp_decode_q_encoding 120 (decoded_text, text_begin_p + 1, 121 eword_end_p - (text_begin_p + 1)); 122 } else { 123 g_string_append_len(outbuf, p, eword_end_p + 2 - p); 124 p = eword_end_p + 2; 125 continue; 126 } 127 128 /* An encoded word MUST not appear within a quoted string, 129 * so quoting that word after decoding should be safe. 130 * We check there are no quotes just to be sure. If there 131 * are, well, the comma won't pose a problem, probably. 132 */ 133 if (addr_field && strchr(decoded_text, ',') && !in_quote && 134 !strchr(decoded_text, '"')) { 135 gchar *tmp = g_strdup_printf("\"%s\"", decoded_text); 136 g_free(decoded_text); 137 decoded_text = tmp; 138 } 139 140 /* convert to UTF-8 */ 141 conv_str = conv_codeset_strdup(decoded_text, charset, NULL); 142 if (!conv_str || !g_utf8_validate(conv_str, -1, NULL)) { 143 g_free(conv_str); 144 conv_str = g_malloc(len + 1); 145 conv_utf8todisp(conv_str, len + 1, decoded_text); 146 } 147 g_string_append(outbuf, conv_str); 148 g_free(conv_str); 149 150 g_free(decoded_text); 151 152 p = eword_end_p + 2; 153 } 154 155 out_len = outbuf->len; 156 out_str = g_string_free(outbuf, FALSE); 157 158 return g_realloc(out_str, out_len + 1); 159 }