summaryrefslogtreecommitdiffabout
path: root/kmicromail/libetpan/mime/mailmime_decode.c
Unidiff
Diffstat (limited to 'kmicromail/libetpan/mime/mailmime_decode.c') (more/less context) (show whitespace changes)
-rw-r--r--kmicromail/libetpan/mime/mailmime_decode.c533
1 files changed, 533 insertions, 0 deletions
diff --git a/kmicromail/libetpan/mime/mailmime_decode.c b/kmicromail/libetpan/mime/mailmime_decode.c
new file mode 100644
index 0000000..3025dcb
--- a/dev/null
+++ b/kmicromail/libetpan/mime/mailmime_decode.c
@@ -0,0 +1,533 @@
1/*
2 * libEtPan! -- a mail stuff library
3 *
4 * Copyright (C) 2001, 2002 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36/*
37 RFC 2047 : MIME (Multipurpose Internet Mail Extensions) Part Three:
38 Message Header Extensions for Non-ASCII Text
39*/
40
41#include "mailmime_decode.h"
42
43#include <ctype.h>
44#include <unistd.h>
45#include <sys/mman.h>
46#include <string.h>
47#include <stdlib.h>
48
49#include "mailmime_content.h"
50
51#include "charconv.h"
52#include "mmapstring.h"
53#include "mailimf.h"
54
55#ifndef TRUE
56#define TRUE 1
57#endif
58
59#ifndef FALSE
60#define FALSE 0
61#endif
62
63static int mailmime_charset_parse(const char * message, size_t length,
64 size_t * index, char ** charset);
65
66enum {
67 MAILMIME_ENCODING_B,
68 MAILMIME_ENCODING_Q
69};
70
71static int mailmime_encoding_parse(const char * message, size_t length,
72 size_t * index, int * result);
73
74static int mailmime_etoken_parse(const char * message, size_t length,
75 size_t * index, char ** result);
76
77static int
78mailmime_non_encoded_word_parse(const char * message, size_t length,
79 size_t * index,
80 char ** result);
81
82static int
83mailmime_encoded_word_parse(const char * message, size_t length,
84 size_t * index,
85 struct mailmime_encoded_word ** result);
86
87
88enum {
89 TYPE_ERROR,
90 TYPE_WORD,
91 TYPE_ENCODED_WORD,
92};
93
94int mailmime_encoded_phrase_parse(const char * default_fromcode,
95 const char * message, size_t length,
96 size_t * index, const char * tocode,
97 char ** result)
98{
99 MMAPString * gphrase;
100 struct mailmime_encoded_word * word;
101 int first;
102 size_t cur_token;
103 int r;
104 int res;
105 char * str;
106 char * wordutf8;
107 int type;
108
109 cur_token = * index;
110
111 gphrase = mmap_string_new("");
112 if (gphrase == NULL) {
113 res = MAILIMF_ERROR_MEMORY;
114 goto err;
115 }
116
117 first = TRUE;
118
119 type = TYPE_ERROR; /* XXX - removes a gcc warning */
120
121 while (1) {
122
123 r = mailmime_encoded_word_parse(message, length, &cur_token, &word);
124 if (r == MAILIMF_NO_ERROR) {
125 if (!first) {
126 if (type != TYPE_ENCODED_WORD) {
127 if (mmap_string_append_c(gphrase, ' ') == NULL) {
128 mailmime_encoded_word_free(word);
129 res = MAILIMF_ERROR_MEMORY;
130 goto free;
131 }
132 }
133 }
134 type = TYPE_ENCODED_WORD;
135 wordutf8 = NULL;
136 r = charconv(tocode, word->wd_charset, word->wd_text,
137 strlen(word->wd_text), &wordutf8);
138 switch (r) {
139 case MAIL_CHARCONV_ERROR_MEMORY:
140 mailmime_encoded_word_free(word);
141 res = MAILIMF_ERROR_MEMORY;
142 goto free;
143
144 case MAIL_CHARCONV_ERROR_UNKNOWN_CHARSET:
145 case MAIL_CHARCONV_ERROR_CONV:
146 mailmime_encoded_word_free(word);
147 res = MAILIMF_ERROR_PARSE;
148 goto free;
149 }
150
151 if (wordutf8 != NULL) {
152 if (mmap_string_append(gphrase, wordutf8) == NULL) {
153 mailmime_encoded_word_free(word);
154 free(wordutf8);
155 res = MAILIMF_ERROR_MEMORY;
156 goto free;
157 }
158 free(wordutf8);
159 }
160 mailmime_encoded_word_free(word);
161 first = FALSE;
162 }
163 else if (r == MAILIMF_ERROR_PARSE) {
164 /* do nothing */
165 }
166 else {
167 res = r;
168 goto free;
169 }
170
171 if (r == MAILIMF_ERROR_PARSE) {
172 char * raw_word;
173
174 r = mailmime_non_encoded_word_parse(message, length,
175 &cur_token, &raw_word);
176 if (r == MAILIMF_NO_ERROR) {
177 if (!first) {
178 if (mmap_string_append_c(gphrase, ' ') == NULL) {
179 free(raw_word);
180 res = MAILIMF_ERROR_MEMORY;
181 goto free;
182 }
183 }
184 type = TYPE_WORD;
185
186 wordutf8 = NULL;
187 r = charconv(tocode, default_fromcode, raw_word,
188 strlen(raw_word), &wordutf8);
189
190 if (wordutf8 != NULL) {
191 if (mmap_string_append(gphrase, wordutf8) == NULL) {
192 free(wordutf8);
193 free(raw_word);
194 res = MAILIMF_ERROR_MEMORY;
195 goto free;
196 }
197
198 free(wordutf8);
199 }
200 free(raw_word);
201 first = FALSE;
202 }
203 else if (r == MAILIMF_ERROR_PARSE) {
204 break;
205 }
206 else {
207 res = r;
208 goto free;
209 }
210 }
211 }
212
213 if (first) {
214 res = MAILIMF_ERROR_PARSE;
215 goto free;
216 }
217
218 str = strdup(gphrase->str);
219 if (str == NULL) {
220 res = MAILIMF_ERROR_MEMORY;
221 goto free;
222 }
223 mmap_string_free(gphrase);
224
225 * result = str;
226 * index = cur_token;
227
228 return MAILIMF_NO_ERROR;
229
230 free:
231 mmap_string_free(gphrase);
232 err:
233 return res;
234}
235
236static int
237mailmime_non_encoded_word_parse(const char * message, size_t length,
238 size_t * index,
239 char ** result)
240{
241 int end;
242 size_t cur_token;
243 int res;
244 char * text;
245 int r;
246 size_t begin;
247
248 cur_token = * index;
249
250 r = mailimf_fws_parse(message, length, &cur_token);
251 if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
252 res = r;
253 goto err;
254 }
255
256 begin = cur_token;
257
258 end = FALSE;
259 while (1) {
260 if (cur_token >= length)
261 break;
262
263 switch (message[cur_token]) {
264 case ' ':
265 case '\t':
266 case '\r':
267 case '\n':
268 end = TRUE;
269 break;
270 }
271
272 if (end)
273 break;
274
275 cur_token ++;
276 }
277
278 if (cur_token - begin == 0) {
279 res = MAILIMF_ERROR_PARSE;
280 goto err;
281 }
282
283 text = malloc(cur_token - begin + 1);
284 if (text == NULL) {
285 res = MAILIMF_ERROR_MEMORY;
286 goto err;
287 }
288
289 memcpy(text, message + begin, cur_token - begin);
290 text[cur_token - begin] = '\0';
291
292 * index = cur_token;
293 * result = text;
294
295 return MAILIMF_NO_ERROR;
296
297 err:
298 return res;
299}
300
301static int mailmime_encoded_word_parse(const char * message, size_t length,
302 size_t * index,
303 struct mailmime_encoded_word ** result)
304{
305 size_t cur_token;
306 char * charset;
307 int encoding;
308 char * text;
309 size_t end_encoding;
310 char * decoded;
311 size_t decoded_len;
312 struct mailmime_encoded_word * ew;
313 int r;
314 int res;
315 int opening_quote;
316 int end;
317
318 cur_token = * index;
319
320 r = mailimf_fws_parse(message, length, &cur_token);
321 if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
322 res = r;
323 goto err;
324 }
325
326 opening_quote = FALSE;
327 r = mailimf_char_parse(message, length, &cur_token, '\"');
328 if (r == MAILIMF_NO_ERROR) {
329 opening_quote = TRUE;
330 }
331 else if (r == MAILIMF_ERROR_PARSE) {
332 /* do nothing */
333 }
334 else {
335 res = r;
336 goto err;
337 }
338
339 r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "=?");
340 if (r != MAILIMF_NO_ERROR) {
341 res = r;
342 goto err;
343 }
344
345 r = mailmime_charset_parse(message, length, &cur_token, &charset);
346 if (r != MAILIMF_NO_ERROR) {
347 res = r;
348 goto err;
349 }
350
351 r = mailimf_char_parse(message, length, &cur_token, '?');
352 if (r != MAILIMF_NO_ERROR) {
353 res = r;
354 goto free_charset;
355 }
356
357 r = mailmime_encoding_parse(message, length, &cur_token, &encoding);
358 if (r != MAILIMF_NO_ERROR) {
359 res = r;
360 goto free_charset;
361 }
362
363 r = mailimf_char_parse(message, length, &cur_token, '?');
364 if (r != MAILIMF_NO_ERROR) {
365 res = r;
366 goto free_charset;
367 }
368
369 end = FALSE;
370 end_encoding = cur_token;
371 while (1) {
372 if (end_encoding >= length)
373 break;
374
375 switch (message[end_encoding]) {
376 case '?':
377#if 0
378 case ' ':
379#endif
380 end = TRUE;
381 break;
382 }
383
384 if (end)
385 break;
386
387 end_encoding ++;
388 }
389
390 decoded_len = 0;
391 decoded = NULL;
392 switch (encoding) {
393 case MAILMIME_ENCODING_B:
394 r = mailmime_base64_body_parse(message, end_encoding,
395 &cur_token, &decoded,
396 &decoded_len);
397
398 if (r != MAILIMF_NO_ERROR) {
399 res = r;
400 goto free_charset;
401 }
402 break;
403 case MAILMIME_ENCODING_Q:
404 r = mailmime_quoted_printable_body_parse(message, end_encoding,
405 &cur_token, &decoded,
406 &decoded_len, TRUE);
407
408 if (r != MAILIMF_NO_ERROR) {
409 res = r;
410 goto free_charset;
411 }
412
413 break;
414 }
415
416 text = malloc(decoded_len + 1);
417 if (text == NULL) {
418 res = MAILIMF_ERROR_MEMORY;
419 goto free_charset;
420 }
421
422 if (decoded_len > 0)
423 memcpy(text, decoded, decoded_len);
424 text[decoded_len] = '\0';
425
426 mailmime_decoded_part_free(decoded);
427
428 r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "?=");
429 if (r != MAILIMF_NO_ERROR) {
430 res = r;
431 goto free_encoded_text;
432 }
433
434 if (opening_quote) {
435 r = mailimf_char_parse(message, length, &cur_token, '\"');
436 if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
437 res = r;
438 goto free_encoded_text;
439 }
440 }
441
442 ew = mailmime_encoded_word_new(charset, text);
443 if (ew == NULL) {
444 res = MAILIMF_ERROR_MEMORY;
445 goto free_encoded_text;
446 }
447
448 * result = ew;
449 * index = cur_token;
450
451 return MAILIMF_NO_ERROR;
452
453 free_encoded_text:
454 mailmime_encoded_text_free(text);
455 free_charset:
456 mailmime_charset_free(charset);
457 err:
458 return res;
459}
460
461static int mailmime_charset_parse(const char * message, size_t length,
462 size_t * index, char ** charset)
463{
464 return mailmime_etoken_parse(message, length, index, charset);
465}
466
467static int mailmime_encoding_parse(const char * message, size_t length,
468 size_t * index, int * result)
469{
470 size_t cur_token;
471 int encoding;
472
473 cur_token = * index;
474
475 if (cur_token >= length)
476 return MAILIMF_ERROR_PARSE;
477
478 switch ((char) toupper((unsigned char) message[cur_token])) {
479 case 'Q':
480 encoding = MAILMIME_ENCODING_Q;
481 break;
482 case 'B':
483 encoding = MAILMIME_ENCODING_B;
484 break;
485 default:
486 return MAILIMF_ERROR_INVAL;
487 }
488
489 cur_token ++;
490
491 * result = encoding;
492 * index = cur_token;
493
494 return MAILIMF_NO_ERROR;
495}
496
497int is_etoken_char(char ch)
498{
499 unsigned char uch = ch;
500
501 if (uch < 31)
502 return FALSE;
503
504 switch (uch) {
505 case ' ':
506 case '(':
507 case ')':
508 case '<':
509 case '>':
510 case '@':
511 case ',':
512 case ';':
513 case ':':
514 case '"':
515 case '/':
516 case '[':
517 case ']':
518 case '?':
519 case '.':
520 case '=':
521 return FALSE;
522 }
523
524 return TRUE;
525}
526
527static int mailmime_etoken_parse(const char * message, size_t length,
528 size_t * index, char ** result)
529{
530 return mailimf_custom_string_parse(message, length,
531 index, result,
532 is_etoken_char);
533}