author | zautrix <zautrix> | 2005-03-18 20:17:03 (UTC) |
---|---|---|
committer | zautrix <zautrix> | 2005-03-18 20:17:03 (UTC) |
commit | 9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf (patch) (unidiff) | |
tree | 2528e6cc740225ca0f47d5ac8ff70f7d3bb10621 /libetpan/src/low-level/mime/mailmime_content.c | |
parent | 9319998f20f03dcc217fbb39656755dc65226276 (diff) | |
download | kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.zip kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.tar.gz kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.tar.bz2 |
Initial revision
Diffstat (limited to 'libetpan/src/low-level/mime/mailmime_content.c') (more/less context) (show whitespace changes)
-rw-r--r-- | libetpan/src/low-level/mime/mailmime_content.c | 2381 |
1 files changed, 2381 insertions, 0 deletions
diff --git a/libetpan/src/low-level/mime/mailmime_content.c b/libetpan/src/low-level/mime/mailmime_content.c new file mode 100644 index 0000000..6a10dfb --- a/dev/null +++ b/libetpan/src/low-level/mime/mailmime_content.c | |||
@@ -0,0 +1,2381 @@ | |||
1 | /* | ||
2 | * libEtPan! -- a mail stuff library | ||
3 | * | ||
4 | * Copyright (C) 2001, 2005 - 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 AUTHORS 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 AUTHORS 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 | #include "mailimf.h" | ||
37 | |||
38 | #include <string.h> | ||
39 | #include <stdlib.h> | ||
40 | |||
41 | #include "mailmime.h" | ||
42 | #include "mailmime_types.h" | ||
43 | #include "mmapstring.h" | ||
44 | |||
45 | #ifndef TRUE | ||
46 | #define TRUE 1 | ||
47 | #endif | ||
48 | |||
49 | #ifndef FALSE | ||
50 | #define FALSE 0 | ||
51 | #endif | ||
52 | |||
53 | /* | ||
54 | RFC 2045 | ||
55 | RFC 2046 | ||
56 | RFC 2047 | ||
57 | |||
58 | RFC 2231 | ||
59 | */ | ||
60 | |||
61 | |||
62 | static int mailmime_parse_with_default(const char * message, size_t length, | ||
63 | size_t * index, int default_type, | ||
64 | struct mailmime_content * content_type, | ||
65 | struct mailmime_fields * mime_fields, | ||
66 | struct mailmime ** result); | ||
67 | |||
68 | |||
69 | |||
70 | char * mailmime_content_charset_get(struct mailmime_content * content) | ||
71 | { | ||
72 | char * charset; | ||
73 | |||
74 | charset = mailmime_content_param_get(content, "charset"); | ||
75 | if (charset == NULL) | ||
76 | return "us-ascii"; | ||
77 | else | ||
78 | return charset; | ||
79 | } | ||
80 | |||
81 | char * mailmime_content_param_get(struct mailmime_content * content, | ||
82 | char * name) | ||
83 | { | ||
84 | clistiter * cur; | ||
85 | |||
86 | for(cur = clist_begin(content->ct_parameters) ; | ||
87 | cur != NULL ; cur = clist_next(cur)) { | ||
88 | struct mailmime_parameter * param; | ||
89 | |||
90 | param = clist_content(cur); | ||
91 | |||
92 | if (strcasecmp(param->pa_name, name) == 0) | ||
93 | return param->pa_value; | ||
94 | } | ||
95 | |||
96 | return NULL; | ||
97 | } | ||
98 | |||
99 | |||
100 | /* | ||
101 | boundary := 0*69<bchars> bcharsnospace | ||
102 | */ | ||
103 | |||
104 | /* | ||
105 | bchars := bcharsnospace / " " | ||
106 | */ | ||
107 | |||
108 | /* | ||
109 | bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" / | ||
110 | "+" / "_" / "," / "-" / "." / | ||
111 | "/" / ":" / "=" / "?" | ||
112 | */ | ||
113 | |||
114 | /* | ||
115 | body-part := <"message" as defined in RFC 822, with all | ||
116 | header fields optional, not starting with the | ||
117 | specified dash-boundary, and with the | ||
118 | delimiter not occurring anywhere in the | ||
119 | body part. Note that the semantics of a | ||
120 | part differ from the semantics of a message, | ||
121 | as described in the text.> | ||
122 | */ | ||
123 | |||
124 | /* | ||
125 | close-delimiter := delimiter "--" | ||
126 | */ | ||
127 | |||
128 | /* | ||
129 | dash-boundary := "--" boundary | ||
130 | ; boundary taken from the value of | ||
131 | ; boundary parameter of the | ||
132 | ; Content-Type field. | ||
133 | */ | ||
134 | |||
135 | /* | ||
136 | delimiter := CRLF dash-boundary | ||
137 | */ | ||
138 | |||
139 | /* | ||
140 | discard-text := *(*text CRLF) | ||
141 | ; May be ignored or discarded. | ||
142 | */ | ||
143 | |||
144 | /* | ||
145 | encapsulation := delimiter transport-padding | ||
146 | CRLF body-part | ||
147 | */ | ||
148 | |||
149 | /* | ||
150 | epilogue := discard-text | ||
151 | */ | ||
152 | |||
153 | /* | ||
154 | multipart-body := [preamble CRLF] | ||
155 | dash-boundary transport-padding CRLF | ||
156 | body-part *encapsulation | ||
157 | close-delimiter transport-padding | ||
158 | [CRLF epilogue] | ||
159 | */ | ||
160 | |||
161 | /* | ||
162 | preamble := discard-text | ||
163 | */ | ||
164 | |||
165 | /* | ||
166 | transport-padding := *LWSP-char | ||
167 | ; Composers MUST NOT generate | ||
168 | ; non-zero length transport | ||
169 | ; padding, but receivers MUST | ||
170 | ; be able to handle padding | ||
171 | ; added by message transports. | ||
172 | */ | ||
173 | |||
174 | |||
175 | /* | ||
176 | ACCESS-TYPE | ||
177 | EXPIRATION | ||
178 | SIZE | ||
179 | PERMISSION | ||
180 | */ | ||
181 | |||
182 | /* | ||
183 | 5.2.3.2. The 'ftp' and 'tftp' Access-Types | ||
184 | NAME | ||
185 | SITE | ||
186 | |||
187 | (3) Before any data are retrieved, using FTP, the user will | ||
188 | generally need to be asked to provide a login id and a | ||
189 | password for the machine named by the site parameter. | ||
190 | For security reasons, such an id and password are not | ||
191 | specified as content-type parameters, but must be | ||
192 | obtained from the user. | ||
193 | |||
194 | optional : | ||
195 | DIRECTORY | ||
196 | MODE | ||
197 | */ | ||
198 | |||
199 | /* | ||
200 | 5.2.3.3. The 'anon-ftp' Access-Type | ||
201 | */ | ||
202 | |||
203 | /* | ||
204 | 5.2.3.4. The 'local-file' Access-Type | ||
205 | NAME | ||
206 | SITE | ||
207 | */ | ||
208 | |||
209 | /* | ||
210 | 5.2.3.5. The 'mail-server' Access-Type | ||
211 | SERVER | ||
212 | SUBJECT | ||
213 | */ | ||
214 | |||
215 | |||
216 | enum { | ||
217 | PREAMBLE_STATE_A0, | ||
218 | PREAMBLE_STATE_A, | ||
219 | PREAMBLE_STATE_A1, | ||
220 | PREAMBLE_STATE_B, | ||
221 | PREAMBLE_STATE_C, | ||
222 | PREAMBLE_STATE_D, | ||
223 | PREAMBLE_STATE_E | ||
224 | }; | ||
225 | |||
226 | static int mailmime_preamble_parse(const char * message, size_t length, | ||
227 | size_t * index, int beol) | ||
228 | { | ||
229 | int state; | ||
230 | size_t cur_token; | ||
231 | |||
232 | cur_token = * index; | ||
233 | if (beol) | ||
234 | state = PREAMBLE_STATE_A0; | ||
235 | else | ||
236 | state = PREAMBLE_STATE_A; | ||
237 | |||
238 | while (state != PREAMBLE_STATE_E) { | ||
239 | |||
240 | if (cur_token >= length) | ||
241 | return MAILIMF_ERROR_PARSE; | ||
242 | |||
243 | switch (state) { | ||
244 | case PREAMBLE_STATE_A0: | ||
245 | switch (message[cur_token]) { | ||
246 | case '-': | ||
247 | state = PREAMBLE_STATE_A1; | ||
248 | break; | ||
249 | case '\r': | ||
250 | state = PREAMBLE_STATE_B; | ||
251 | break; | ||
252 | case '\n': | ||
253 | state = PREAMBLE_STATE_C; | ||
254 | break; | ||
255 | default: | ||
256 | state = PREAMBLE_STATE_A; | ||
257 | break; | ||
258 | } | ||
259 | break; | ||
260 | |||
261 | case PREAMBLE_STATE_A: | ||
262 | switch (message[cur_token]) { | ||
263 | case '\r': | ||
264 | state = PREAMBLE_STATE_B; | ||
265 | break; | ||
266 | case '\n': | ||
267 | state = PREAMBLE_STATE_C; | ||
268 | break; | ||
269 | default: | ||
270 | state = PREAMBLE_STATE_A; | ||
271 | break; | ||
272 | } | ||
273 | break; | ||
274 | |||
275 | case PREAMBLE_STATE_A1: | ||
276 | switch (message[cur_token]) { | ||
277 | case '-': | ||
278 | state = PREAMBLE_STATE_E; | ||
279 | break; | ||
280 | case '\r': | ||
281 | state = PREAMBLE_STATE_B; | ||
282 | break; | ||
283 | case '\n': | ||
284 | state = PREAMBLE_STATE_C; | ||
285 | break; | ||
286 | default: | ||
287 | state = PREAMBLE_STATE_A; | ||
288 | break; | ||
289 | } | ||
290 | break; | ||
291 | |||
292 | case PREAMBLE_STATE_B: | ||
293 | switch (message[cur_token]) { | ||
294 | case '\r': | ||
295 | state = PREAMBLE_STATE_B; | ||
296 | break; | ||
297 | case '\n': | ||
298 | state = PREAMBLE_STATE_C; | ||
299 | break; | ||
300 | case '-': | ||
301 | state = PREAMBLE_STATE_D; | ||
302 | break; | ||
303 | default: | ||
304 | state = PREAMBLE_STATE_A0; | ||
305 | break; | ||
306 | } | ||
307 | break; | ||
308 | |||
309 | case PREAMBLE_STATE_C: | ||
310 | switch (message[cur_token]) { | ||
311 | case '-': | ||
312 | state = PREAMBLE_STATE_D; | ||
313 | break; | ||
314 | case '\r': | ||
315 | state = PREAMBLE_STATE_B; | ||
316 | break; | ||
317 | case '\n': | ||
318 | state = PREAMBLE_STATE_C; | ||
319 | break; | ||
320 | default: | ||
321 | state = PREAMBLE_STATE_A0; | ||
322 | break; | ||
323 | } | ||
324 | break; | ||
325 | |||
326 | case PREAMBLE_STATE_D: | ||
327 | switch (message[cur_token]) { | ||
328 | case '-': | ||
329 | state = PREAMBLE_STATE_E; | ||
330 | break; | ||
331 | default: | ||
332 | state = PREAMBLE_STATE_A; | ||
333 | break; | ||
334 | } | ||
335 | break; | ||
336 | } | ||
337 | |||
338 | cur_token ++; | ||
339 | } | ||
340 | |||
341 | * index = cur_token; | ||
342 | |||
343 | return MAILIMF_NO_ERROR; | ||
344 | } | ||
345 | |||
346 | static int mailmime_boundary_parse(const char * message, size_t length, | ||
347 | size_t * index, char * boundary) | ||
348 | { | ||
349 | size_t cur_token; | ||
350 | size_t len; | ||
351 | |||
352 | cur_token = * index; | ||
353 | |||
354 | len = strlen(boundary); | ||
355 | |||
356 | if (cur_token + len >= length) | ||
357 | return MAILIMF_ERROR_PARSE; | ||
358 | |||
359 | if (strncmp(message + cur_token, boundary, len) != 0) | ||
360 | return MAILIMF_ERROR_PARSE; | ||
361 | |||
362 | cur_token += len; | ||
363 | |||
364 | * index = cur_token; | ||
365 | |||
366 | return MAILIMF_NO_ERROR; | ||
367 | } | ||
368 | |||
369 | static int is_wsp(char ch) | ||
370 | { | ||
371 | if ((ch == ' ') || (ch == '\t')) | ||
372 | return TRUE; | ||
373 | |||
374 | return FALSE; | ||
375 | } | ||
376 | |||
377 | static int mailmime_lwsp_parse(const char * message, size_t length, | ||
378 | size_t * index) | ||
379 | { | ||
380 | size_t cur_token; | ||
381 | |||
382 | cur_token = * index; | ||
383 | |||
384 | if (cur_token >= length) | ||
385 | return MAILIMF_ERROR_PARSE; | ||
386 | |||
387 | while (is_wsp(message[cur_token])) { | ||
388 | cur_token ++; | ||
389 | if (cur_token >= length) | ||
390 | break; | ||
391 | } | ||
392 | |||
393 | if (cur_token == * index) | ||
394 | return MAILIMF_ERROR_PARSE; | ||
395 | |||
396 | * index = cur_token; | ||
397 | |||
398 | return MAILIMF_NO_ERROR; | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | gboolean mailimf_crlf_parse(gchar * message, guint32 length, guint32 * index) | ||
403 | */ | ||
404 | |||
405 | enum { | ||
406 | BODY_PART_DASH2_STATE_0, | ||
407 | BODY_PART_DASH2_STATE_1, | ||
408 | BODY_PART_DASH2_STATE_2, | ||
409 | BODY_PART_DASH2_STATE_3, | ||
410 | BODY_PART_DASH2_STATE_4, | ||
411 | BODY_PART_DASH2_STATE_5, | ||
412 | BODY_PART_DASH2_STATE_6 | ||
413 | }; | ||
414 | |||
415 | static int | ||
416 | mailmime_body_part_dash2_parse(const char * message, size_t length, | ||
417 | size_t * index, char * boundary, | ||
418 | const char ** result, size_t * result_size) | ||
419 | { | ||
420 | int state; | ||
421 | size_t cur_token; | ||
422 | size_t size; | ||
423 | size_t begin_text; | ||
424 | size_t end_text; | ||
425 | int r; | ||
426 | |||
427 | cur_token = * index; | ||
428 | state = BODY_PART_DASH2_STATE_0; | ||
429 | |||
430 | begin_text = cur_token; | ||
431 | end_text = length; | ||
432 | |||
433 | while (state != BODY_PART_DASH2_STATE_5) { | ||
434 | |||
435 | if (cur_token >= length) | ||
436 | break; | ||
437 | |||
438 | switch(state) { | ||
439 | |||
440 | case BODY_PART_DASH2_STATE_0: | ||
441 | switch (message[cur_token]) { | ||
442 | case '\r': | ||
443 | state = BODY_PART_DASH2_STATE_1; | ||
444 | break; | ||
445 | case '\n': | ||
446 | state = BODY_PART_DASH2_STATE_2; | ||
447 | break; | ||
448 | default: | ||
449 | state = BODY_PART_DASH2_STATE_0; | ||
450 | break; | ||
451 | } | ||
452 | break; | ||
453 | |||
454 | case BODY_PART_DASH2_STATE_1: | ||
455 | switch (message[cur_token]) { | ||
456 | case '\n': | ||
457 | state = BODY_PART_DASH2_STATE_2; | ||
458 | break; | ||
459 | default: | ||
460 | state = BODY_PART_DASH2_STATE_0; | ||
461 | break; | ||
462 | } | ||
463 | break; | ||
464 | |||
465 | case BODY_PART_DASH2_STATE_2: | ||
466 | switch (message[cur_token]) { | ||
467 | case '-': | ||
468 | end_text = cur_token; | ||
469 | state = BODY_PART_DASH2_STATE_3; | ||
470 | break; | ||
471 | case '\r': | ||
472 | state = BODY_PART_DASH2_STATE_1; | ||
473 | break; | ||
474 | case '\n': | ||
475 | state = BODY_PART_DASH2_STATE_2; | ||
476 | break; | ||
477 | default: | ||
478 | state = BODY_PART_DASH2_STATE_0; | ||
479 | break; | ||
480 | } | ||
481 | break; | ||
482 | |||
483 | case BODY_PART_DASH2_STATE_3: | ||
484 | switch (message[cur_token]) { | ||
485 | case '\r': | ||
486 | state = BODY_PART_DASH2_STATE_1; | ||
487 | break; | ||
488 | case '\n': | ||
489 | state = BODY_PART_DASH2_STATE_2; | ||
490 | break; | ||
491 | case '-': | ||
492 | state = BODY_PART_DASH2_STATE_4; | ||
493 | break; | ||
494 | default: | ||
495 | state = BODY_PART_DASH2_STATE_0; | ||
496 | break; | ||
497 | } | ||
498 | break; | ||
499 | |||
500 | case BODY_PART_DASH2_STATE_4: | ||
501 | r = mailmime_boundary_parse(message, length, &cur_token, boundary); | ||
502 | if (r == MAILIMF_NO_ERROR) | ||
503 | state = BODY_PART_DASH2_STATE_5; | ||
504 | else | ||
505 | state = BODY_PART_DASH2_STATE_6; | ||
506 | |||
507 | break; | ||
508 | } | ||
509 | |||
510 | if ((state != BODY_PART_DASH2_STATE_5) && | ||
511 | (state != BODY_PART_DASH2_STATE_6)) | ||
512 | cur_token ++; | ||
513 | |||
514 | if (state == BODY_PART_DASH2_STATE_6) | ||
515 | state = BODY_PART_DASH2_STATE_0; | ||
516 | } | ||
517 | |||
518 | size = end_text - begin_text; | ||
519 | |||
520 | #if 0 | ||
521 | if (size > 0) { | ||
522 | end_text --; | ||
523 | size --; | ||
524 | } | ||
525 | #endif | ||
526 | |||
527 | if (size >= 1) { | ||
528 | if (message[end_text - 1] == '\r') { | ||
529 | end_text --; | ||
530 | size --; | ||
531 | } | ||
532 | else if (size >= 1) { | ||
533 | if (message[end_text - 1] == '\n') { | ||
534 | end_text --; | ||
535 | size --; | ||
536 | if (size >= 1) { | ||
537 | if (message[end_text - 1] == '\r') { | ||
538 | end_text --; | ||
539 | size --; | ||
540 | } | ||
541 | } | ||
542 | } | ||
543 | } | ||
544 | } | ||
545 | |||
546 | size = end_text - begin_text; | ||
547 | if (size == 0) | ||
548 | return MAILIMF_ERROR_PARSE; | ||
549 | |||
550 | #if 0 | ||
551 | body_part = mailimf_body_new(message + begin_text, size); | ||
552 | if (body_part == NULL) | ||
553 | goto err; | ||
554 | #endif | ||
555 | |||
556 | * result = message + begin_text; | ||
557 | * result_size = size; | ||
558 | * index = cur_token; | ||
559 | |||
560 | return MAILIMF_NO_ERROR; | ||
561 | #if 0 | ||
562 | err: | ||
563 | return MAILIMF_ERROR_PARSE; | ||
564 | #endif | ||
565 | } | ||
566 | |||
567 | static int | ||
568 | mailmime_body_part_dash2_transport_crlf_parse(const char * message, | ||
569 | size_t length, | ||
570 | size_t * index, char * boundary, | ||
571 | const char ** result, size_t * result_size) | ||
572 | { | ||
573 | size_t cur_token; | ||
574 | int r; | ||
575 | size_t after_boundary; | ||
576 | const char * data_str; | ||
577 | size_t data_size; | ||
578 | const char * begin_text; | ||
579 | const char * end_text; | ||
580 | |||
581 | cur_token = * index; | ||
582 | |||
583 | begin_text = message + cur_token; | ||
584 | end_text = message + cur_token; | ||
585 | |||
586 | while (1) { | ||
587 | r = mailmime_body_part_dash2_parse(message, length, &cur_token, | ||
588 | boundary, &data_str, &data_size); | ||
589 | if (r == MAILIMF_NO_ERROR) { | ||
590 | end_text = data_str + data_size; | ||
591 | } | ||
592 | else { | ||
593 | return r; | ||
594 | } | ||
595 | |||
596 | /* parse transport-padding */ | ||
597 | while (1) { | ||
598 | r = mailmime_lwsp_parse(message, length, &cur_token); | ||
599 | if (r == MAILIMF_NO_ERROR) { | ||
600 | /* do nothing */ | ||
601 | } | ||
602 | else if (r == MAILIMF_ERROR_PARSE) { | ||
603 | break; | ||
604 | } | ||
605 | else { | ||
606 | return r; | ||
607 | } | ||
608 | } | ||
609 | |||
610 | r = mailimf_crlf_parse(message, length, &cur_token); | ||
611 | if (r == MAILIMF_NO_ERROR) { | ||
612 | break; | ||
613 | } | ||
614 | else if (r == MAILIMF_ERROR_PARSE) { | ||
615 | /* do nothing */ | ||
616 | } | ||
617 | else { | ||
618 | return r; | ||
619 | } | ||
620 | } | ||
621 | |||
622 | * index = cur_token; | ||
623 | * result = begin_text; | ||
624 | * result_size = end_text - begin_text; | ||
625 | |||
626 | return MAILIMF_NO_ERROR; | ||
627 | } | ||
628 | |||
629 | static int mailmime_multipart_close_parse(const char * message, size_t length, | ||
630 | size_t * index); | ||
631 | |||
632 | static int | ||
633 | mailmime_body_part_dash2_close_parse(const char * message, | ||
634 | size_t length, | ||
635 | size_t * index, char * boundary, | ||
636 | const char ** result, size_t * result_size) | ||
637 | { | ||
638 | size_t cur_token; | ||
639 | int r; | ||
640 | size_t after_boundary; | ||
641 | const char * data_str; | ||
642 | size_t data_size; | ||
643 | const char * begin_text; | ||
644 | const char * end_text; | ||
645 | |||
646 | cur_token = * index; | ||
647 | |||
648 | begin_text = message + cur_token; | ||
649 | end_text = message + cur_token; | ||
650 | |||
651 | while (1) { | ||
652 | r = mailmime_body_part_dash2_parse(message, length, | ||
653 | &cur_token, boundary, &data_str, &data_size); | ||
654 | if (r == MAILIMF_NO_ERROR) { | ||
655 | end_text = data_str + data_size; | ||
656 | } | ||
657 | else { | ||
658 | return r; | ||
659 | } | ||
660 | |||
661 | r = mailmime_multipart_close_parse(message, length, &cur_token); | ||
662 | if (r == MAILIMF_NO_ERROR) { | ||
663 | break; | ||
664 | } | ||
665 | else if (r == MAILIMF_ERROR_PARSE) { | ||
666 | /* do nothing */ | ||
667 | } | ||
668 | else { | ||
669 | return r; | ||
670 | } | ||
671 | } | ||
672 | |||
673 | * index = cur_token; | ||
674 | * result = data_str; | ||
675 | * result_size = data_size; | ||
676 | |||
677 | return MAILIMF_NO_ERROR; | ||
678 | } | ||
679 | |||
680 | enum { | ||
681 | MULTIPART_CLOSE_STATE_0, | ||
682 | MULTIPART_CLOSE_STATE_1, | ||
683 | MULTIPART_CLOSE_STATE_2, | ||
684 | MULTIPART_CLOSE_STATE_3, | ||
685 | MULTIPART_CLOSE_STATE_4 | ||
686 | }; | ||
687 | |||
688 | static int mailmime_multipart_close_parse(const char * message, size_t length, | ||
689 | size_t * index) | ||
690 | { | ||
691 | int state; | ||
692 | size_t cur_token; | ||
693 | |||
694 | cur_token = * index; | ||
695 | state = MULTIPART_CLOSE_STATE_0; | ||
696 | |||
697 | while (state != MULTIPART_CLOSE_STATE_4) { | ||
698 | |||
699 | switch(state) { | ||
700 | |||
701 | case MULTIPART_CLOSE_STATE_0: | ||
702 | if (cur_token >= length) | ||
703 | return MAILIMF_ERROR_PARSE; | ||
704 | |||
705 | switch (message[cur_token]) { | ||
706 | case '-': | ||
707 | state = MULTIPART_CLOSE_STATE_1; | ||
708 | break; | ||
709 | default: | ||
710 | return MAILIMF_ERROR_PARSE; | ||
711 | } | ||
712 | break; | ||
713 | |||
714 | case MULTIPART_CLOSE_STATE_1: | ||
715 | if (cur_token >= length) | ||
716 | return MAILIMF_ERROR_PARSE; | ||
717 | |||
718 | switch (message[cur_token]) { | ||
719 | case '-': | ||
720 | state = MULTIPART_CLOSE_STATE_2; | ||
721 | break; | ||
722 | default: | ||
723 | return MAILIMF_ERROR_PARSE; | ||
724 | } | ||
725 | break; | ||
726 | |||
727 | case MULTIPART_CLOSE_STATE_2: | ||
728 | if (cur_token >= length) { | ||
729 | state = MULTIPART_CLOSE_STATE_4; | ||
730 | break; | ||
731 | } | ||
732 | |||
733 | switch (message[cur_token]) { | ||
734 | case ' ': | ||
735 | state = MULTIPART_CLOSE_STATE_2; | ||
736 | break; | ||
737 | case '\t': | ||
738 | state = MULTIPART_CLOSE_STATE_2; | ||
739 | break; | ||
740 | case '\r': | ||
741 | state = MULTIPART_CLOSE_STATE_3; | ||
742 | break; | ||
743 | case '\n': | ||
744 | state = MULTIPART_CLOSE_STATE_4; | ||
745 | break; | ||
746 | default: | ||
747 | state = MULTIPART_CLOSE_STATE_4; | ||
748 | break; | ||
749 | } | ||
750 | break; | ||
751 | |||
752 | case MULTIPART_CLOSE_STATE_3: | ||
753 | if (cur_token >= length) { | ||
754 | state = MULTIPART_CLOSE_STATE_4; | ||
755 | break; | ||
756 | } | ||
757 | |||
758 | switch (message[cur_token]) { | ||
759 | case '\n': | ||
760 | state = MULTIPART_CLOSE_STATE_4; | ||
761 | break; | ||
762 | default: | ||
763 | state = MULTIPART_CLOSE_STATE_4; | ||
764 | break; | ||
765 | } | ||
766 | break; | ||
767 | } | ||
768 | |||
769 | cur_token ++; | ||
770 | } | ||
771 | |||
772 | * index = cur_token; | ||
773 | |||
774 | return MAILIMF_NO_ERROR; | ||
775 | } | ||
776 | |||
777 | enum { | ||
778 | MULTIPART_NEXT_STATE_0, | ||
779 | MULTIPART_NEXT_STATE_1, | ||
780 | MULTIPART_NEXT_STATE_2 | ||
781 | }; | ||
782 | |||
783 | int mailmime_multipart_next_parse(const char * message, size_t length, | ||
784 | size_t * index) | ||
785 | { | ||
786 | int state; | ||
787 | size_t cur_token; | ||
788 | |||
789 | cur_token = * index; | ||
790 | state = MULTIPART_NEXT_STATE_0; | ||
791 | |||
792 | while (state != MULTIPART_NEXT_STATE_2) { | ||
793 | |||
794 | if (cur_token >= length) | ||
795 | return MAILIMF_ERROR_PARSE; | ||
796 | |||
797 | switch(state) { | ||
798 | |||
799 | case MULTIPART_NEXT_STATE_0: | ||
800 | switch (message[cur_token]) { | ||
801 | case ' ': | ||
802 | state = MULTIPART_NEXT_STATE_0; | ||
803 | break; | ||
804 | case '\t': | ||
805 | state = MULTIPART_NEXT_STATE_0; | ||
806 | break; | ||
807 | case '\r': | ||
808 | state = MULTIPART_NEXT_STATE_1; | ||
809 | break; | ||
810 | case '\n': | ||
811 | state = MULTIPART_NEXT_STATE_2; | ||
812 | break; | ||
813 | default: | ||
814 | return MAILIMF_ERROR_PARSE; | ||
815 | } | ||
816 | break; | ||
817 | |||
818 | case MULTIPART_NEXT_STATE_1: | ||
819 | switch (message[cur_token]) { | ||
820 | case '\n': | ||
821 | state = MULTIPART_NEXT_STATE_2; | ||
822 | break; | ||
823 | default: | ||
824 | return MAILIMF_ERROR_PARSE; | ||
825 | } | ||
826 | break; | ||
827 | } | ||
828 | |||
829 | cur_token ++; | ||
830 | } | ||
831 | |||
832 | * index = cur_token; | ||
833 | |||
834 | return MAILIMF_NO_ERROR; | ||
835 | } | ||
836 | |||
837 | static int | ||
838 | mailmime_multipart_body_parse(const char * message, size_t length, | ||
839 | size_t * index, char * boundary, | ||
840 | int default_subtype, | ||
841 | clist ** result, | ||
842 | struct mailmime_data ** p_preamble, | ||
843 | struct mailmime_data ** p_epilogue) | ||
844 | { | ||
845 | size_t cur_token; | ||
846 | clist * list; | ||
847 | int r; | ||
848 | int res; | ||
849 | #if 0 | ||
850 | size_t begin; | ||
851 | #endif | ||
852 | size_t preamble_begin; | ||
853 | size_t preamble_length; | ||
854 | size_t preamble_end; | ||
855 | #if 0 | ||
856 | int no_preamble; | ||
857 | size_t before_crlf; | ||
858 | #endif | ||
859 | size_t epilogue_begin; | ||
860 | size_t epilogue_length; | ||
861 | struct mailmime_data * preamble; | ||
862 | struct mailmime_data * epilogue; | ||
863 | size_t part_begin; | ||
864 | int final_part; | ||
865 | |||
866 | preamble = NULL; | ||
867 | epilogue = NULL; | ||
868 | |||
869 | cur_token = * index; | ||
870 | preamble_begin = cur_token; | ||
871 | |||
872 | #if 0 | ||
873 | no_preamble = FALSE; | ||
874 | #endif | ||
875 | preamble_end = preamble_begin; | ||
876 | |||
877 | #if 0 | ||
878 | r = mailmime_preamble_parse(message, length, &cur_token); | ||
879 | if (r == MAILIMF_NO_ERROR) { | ||
880 | /* do nothing */ | ||
881 | #if 0 | ||
882 | preamble_end = cur_token - 2; | ||
883 | #endif | ||
884 | } | ||
885 | else if (r == MAILIMF_ERROR_PARSE) { | ||
886 | /* do nothing */ | ||
887 | no_preamble = TRUE; | ||
888 | } | ||
889 | else { | ||
890 | res = r; | ||
891 | goto err; | ||
892 | } | ||
893 | |||
894 | while (1) { | ||
895 | |||
896 | preamble_end = cur_token; | ||
897 | r = mailmime_boundary_parse(message, length, &cur_token, boundary); | ||
898 | if (r == MAILIMF_NO_ERROR) { | ||
899 | break; | ||
900 | } | ||
901 | else if (r == MAILIMF_ERROR_PARSE) { | ||
902 | /* do nothing */ | ||
903 | } | ||
904 | else { | ||
905 | res = r; | ||
906 | goto err; | ||
907 | } | ||
908 | |||
909 | r = mailmime_preamble_parse(message, length, &cur_token); | ||
910 | if (r == MAILIMF_NO_ERROR) { | ||
911 | #if 0 | ||
912 | preamble_end = cur_token - 2; | ||
913 | #endif | ||
914 | } | ||
915 | else if (r == MAILIMF_ERROR_PARSE) { | ||
916 | no_preamble = TRUE; | ||
917 | break; | ||
918 | } | ||
919 | else { | ||
920 | res = r; | ||
921 | goto err; | ||
922 | } | ||
923 | } | ||
924 | |||
925 | if (no_preamble) { | ||
926 | #if 0 | ||
927 | preamble_end = cur_token; | ||
928 | #endif | ||
929 | } | ||
930 | else { | ||
931 | |||
932 | r = mailmime_lwsp_parse(message, length, &cur_token); | ||
933 | if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { | ||
934 | res = r; | ||
935 | goto err; | ||
936 | } | ||
937 | |||
938 | before_crlf = cur_token; | ||
939 | r = mailimf_crlf_parse(message, length, &cur_token); | ||
940 | if (r == MAILIMF_NO_ERROR) { | ||
941 | #if 0 | ||
942 | preamble_end = before_crlf; | ||
943 | #endif | ||
944 | /* remove the CR LF at the end of preamble if any */ | ||
945 | } | ||
946 | else if (r == MAILIMF_ERROR_PARSE) { | ||
947 | /* do nothing */ | ||
948 | } | ||
949 | else { | ||
950 | res = r; | ||
951 | goto err; | ||
952 | } | ||
953 | } | ||
954 | preamble_length = preamble_end - begin; | ||
955 | #endif | ||
956 | |||
957 | r = mailmime_preamble_parse(message, length, &cur_token, 1); | ||
958 | if (r == MAILIMF_NO_ERROR) { | ||
959 | while (1) { | ||
960 | |||
961 | preamble_end = cur_token; | ||
962 | r = mailmime_boundary_parse(message, length, &cur_token, boundary); | ||
963 | if (r == MAILIMF_NO_ERROR) { | ||
964 | break; | ||
965 | } | ||
966 | else if (r == MAILIMF_ERROR_PARSE) { | ||
967 | /* do nothing */ | ||
968 | } | ||
969 | else { | ||
970 | res = r; | ||
971 | goto err; | ||
972 | } | ||
973 | |||
974 | r = mailmime_preamble_parse(message, length, &cur_token, 0); | ||
975 | if (r == MAILIMF_NO_ERROR) { | ||
976 | } | ||
977 | else if (r == MAILIMF_ERROR_PARSE) { | ||
978 | break; | ||
979 | } | ||
980 | else { | ||
981 | res = r; | ||
982 | goto err; | ||
983 | } | ||
984 | } | ||
985 | } | ||
986 | |||
987 | preamble_end -= 2; | ||
988 | if (preamble_end != preamble_begin) { | ||
989 | /* try to find the real end of the preamble (strip CR LF) */ | ||
990 | if (message[preamble_end - 1] == '\n') { | ||
991 | preamble_end --; | ||
992 | if (preamble_end - 1 >= preamble_begin) { | ||
993 | if (message[preamble_end - 1] == '\r') | ||
994 | preamble_end --; | ||
995 | } | ||
996 | } | ||
997 | else if (message[preamble_end - 1] == '\r') { | ||
998 | preamble_end --; | ||
999 | } | ||
1000 | } | ||
1001 | preamble_length = preamble_end - preamble_begin; | ||
1002 | |||
1003 | part_begin = cur_token; | ||
1004 | while (1) { | ||
1005 | r = mailmime_lwsp_parse(message, length, &cur_token); | ||
1006 | if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { | ||
1007 | res = r; | ||
1008 | goto err; | ||
1009 | } | ||
1010 | #if 0 | ||
1011 | if (r == MAILIMF_ERROR_PARSE) | ||
1012 | break; | ||
1013 | #endif | ||
1014 | |||
1015 | r = mailimf_crlf_parse(message, length, &cur_token); | ||
1016 | if (r == MAILIMF_NO_ERROR) { | ||
1017 | part_begin = cur_token; | ||
1018 | } | ||
1019 | else if (r == MAILIMF_ERROR_PARSE) { | ||
1020 | /* do nothing */ | ||
1021 | break; | ||
1022 | } | ||
1023 | else { | ||
1024 | res = r; | ||
1025 | goto err; | ||
1026 | } | ||
1027 | } | ||
1028 | |||
1029 | cur_token = part_begin; | ||
1030 | |||
1031 | list = clist_new(); | ||
1032 | if (list == NULL) { | ||
1033 | res = MAILIMF_ERROR_MEMORY; | ||
1034 | goto err; | ||
1035 | } | ||
1036 | |||
1037 | final_part = 0; | ||
1038 | |||
1039 | while (!final_part) { | ||
1040 | size_t bp_token; | ||
1041 | struct mailmime * mime_bp; | ||
1042 | const char * data_str; | ||
1043 | size_t data_size; | ||
1044 | struct mailimf_fields * fields; | ||
1045 | struct mailmime_fields * mime_fields; | ||
1046 | int got_crlf; | ||
1047 | size_t after_boundary; | ||
1048 | |||
1049 | #if 0 | ||
1050 | /* XXX - begin */ | ||
1051 | r = mailmime_body_part_dash2_parse(message, length, &cur_token, | ||
1052 | boundary, &data_str, &data_size); | ||
1053 | if (r == MAILIMF_NO_ERROR) { | ||
1054 | /* do nothing */ | ||
1055 | } | ||
1056 | else if (r == MAILIMF_ERROR_PARSE) { | ||
1057 | break; | ||
1058 | } | ||
1059 | else { | ||
1060 | res = r; | ||
1061 | goto free; | ||
1062 | } | ||
1063 | |||
1064 | after_boundary = cur_token; | ||
1065 | got_crlf = 0; | ||
1066 | /* parse transport-padding */ | ||
1067 | while (1) { | ||
1068 | r = mailmime_lwsp_parse(message, length, &cur_token); | ||
1069 | if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { | ||
1070 | res = r; | ||
1071 | goto free; | ||
1072 | } | ||
1073 | |||
1074 | r = mailimf_crlf_parse(message, length, &cur_token); | ||
1075 | if (r == MAILIMF_NO_ERROR) { | ||
1076 | got_crlf = 1; | ||
1077 | break; | ||
1078 | } | ||
1079 | else if (r == MAILIMF_ERROR_PARSE) { | ||
1080 | /* do nothing */ | ||
1081 | break; | ||
1082 | } | ||
1083 | else { | ||
1084 | res = r; | ||
1085 | goto free; | ||
1086 | } | ||
1087 | } | ||
1088 | if (after_boundary != cur_token) { | ||
1089 | if (!got_crlf) { | ||
1090 | r = mailimf_crlf_parse(message, length, &cur_token); | ||
1091 | if (r == MAILIMF_NO_ERROR) { | ||
1092 | got_crlf = 1; | ||
1093 | break; | ||
1094 | } | ||
1095 | } | ||
1096 | } | ||
1097 | /* XXX - end */ | ||
1098 | #endif | ||
1099 | |||
1100 | r = mailmime_body_part_dash2_transport_crlf_parse(message, length, | ||
1101 | &cur_token, boundary, &data_str, &data_size); | ||
1102 | if (r == MAILIMF_ERROR_PARSE) { | ||
1103 | r = mailmime_body_part_dash2_close_parse(message, length, | ||
1104 | &cur_token, boundary, &data_str, &data_size); | ||
1105 | if (r == MAILIMF_NO_ERROR) { | ||
1106 | final_part = 1; | ||
1107 | } | ||
1108 | } | ||
1109 | |||
1110 | if (r == MAILIMF_NO_ERROR) { | ||
1111 | bp_token = 0; | ||
1112 | |||
1113 | r = mailimf_optional_fields_parse(data_str, data_size, | ||
1114 | &bp_token, &fields); | ||
1115 | if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { | ||
1116 | res = r; | ||
1117 | goto free; | ||
1118 | } | ||
1119 | |||
1120 | r = mailimf_crlf_parse(data_str, data_size, &bp_token); | ||
1121 | if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { | ||
1122 | mailimf_fields_free(fields); | ||
1123 | res = r; | ||
1124 | goto free; | ||
1125 | } | ||
1126 | |||
1127 | mime_fields = NULL; | ||
1128 | r = mailmime_fields_parse(fields, &mime_fields); | ||
1129 | mailimf_fields_free(fields); | ||
1130 | if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { | ||
1131 | res = r; | ||
1132 | goto free; | ||
1133 | } | ||
1134 | |||
1135 | r = mailmime_parse_with_default(data_str, data_size, | ||
1136 | &bp_token, default_subtype, NULL, | ||
1137 | mime_fields, &mime_bp); | ||
1138 | if (r == MAILIMF_NO_ERROR) { | ||
1139 | r = clist_append(list, mime_bp); | ||
1140 | if (r < 0) { | ||
1141 | mailmime_free(mime_bp); | ||
1142 | res = MAILIMF_ERROR_MEMORY; | ||
1143 | goto free; | ||
1144 | } | ||
1145 | } | ||
1146 | else if (r == MAILIMF_ERROR_PARSE) { | ||
1147 | mailmime_fields_free(mime_fields); | ||
1148 | break; | ||
1149 | } | ||
1150 | else { | ||
1151 | mailmime_fields_free(mime_fields); | ||
1152 | res = r; | ||
1153 | goto free; | ||
1154 | } | ||
1155 | |||
1156 | r = mailmime_multipart_next_parse(message, length, &cur_token); | ||
1157 | if (r == MAILIMF_NO_ERROR) { | ||
1158 | /* do nothing */ | ||
1159 | } | ||
1160 | } | ||
1161 | else { | ||
1162 | res = r; | ||
1163 | goto free; | ||
1164 | } | ||
1165 | |||
1166 | #if 0 | ||
1167 | else if (r == MAILIMF_ERROR_PARSE) { | ||
1168 | r = mailmime_body_part_dash2_parse(message, length, | ||
1169 | &cur_token, boundary, &data_str, &data_size); | ||
1170 | if (r != MAILIMF_NO_ERROR) { | ||
1171 | res = r; | ||
1172 | goto free; | ||
1173 | } | ||
1174 | |||
1175 | r = mailmime_multipart_close_parse(message, length, &cur_token); | ||
1176 | if (r == MAILIMF_NO_ERROR) { | ||
1177 | break; | ||
1178 | } | ||
1179 | else if (r == MAILIMF_ERROR_PARSE) { | ||
1180 | res = r; | ||
1181 | goto free; | ||
1182 | #if 0 | ||
1183 | fprintf(stderr, "close not found, reparse %s\n", boundary); | ||
1184 | /* reparse */ | ||
1185 | continue; | ||
1186 | #endif | ||
1187 | } | ||
1188 | else { | ||
1189 | res = r; | ||
1190 | goto free; | ||
1191 | } | ||
1192 | } | ||
1193 | else { | ||
1194 | res = r; | ||
1195 | goto free; | ||
1196 | } | ||
1197 | #endif | ||
1198 | } | ||
1199 | |||
1200 | epilogue_begin = length; | ||
1201 | /* parse transport-padding */ | ||
1202 | while (1) { | ||
1203 | r = mailmime_lwsp_parse(message, length, &cur_token); | ||
1204 | if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { | ||
1205 | res = r; | ||
1206 | goto free; | ||
1207 | } | ||
1208 | |||
1209 | if (r == MAILIMF_ERROR_PARSE) | ||
1210 | break; | ||
1211 | |||
1212 | #if 0 | ||
1213 | if (r == MAILIMF_ERROR_PARSE) | ||
1214 | break; | ||
1215 | #endif | ||
1216 | |||
1217 | #if 0 | ||
1218 | before_crlf = cur_token; | ||
1219 | #endif | ||
1220 | } | ||
1221 | |||
1222 | r = mailimf_crlf_parse(message, length, &cur_token); | ||
1223 | if (r == MAILIMF_NO_ERROR) { | ||
1224 | epilogue_begin = cur_token; | ||
1225 | } | ||
1226 | else if (r != MAILIMF_ERROR_PARSE) { | ||
1227 | res = r; | ||
1228 | goto free; | ||
1229 | } | ||
1230 | |||
1231 | /* add preamble and epilogue */ | ||
1232 | |||
1233 | epilogue_length = length - epilogue_begin; | ||
1234 | |||
1235 | if (preamble_length != 0) { | ||
1236 | preamble = mailmime_data_new(MAILMIME_DATA_TEXT, | ||
1237 | MAILMIME_MECHANISM_8BIT, 1, | ||
1238 | message + preamble_begin, preamble_length, | ||
1239 | NULL); | ||
1240 | if (preamble == NULL) { | ||
1241 | res = MAILIMF_ERROR_MEMORY; | ||
1242 | goto free; | ||
1243 | } | ||
1244 | } | ||
1245 | |||
1246 | if (epilogue_length != 0) { | ||
1247 | epilogue = mailmime_data_new(MAILMIME_DATA_TEXT, | ||
1248 | MAILMIME_MECHANISM_8BIT, 1, | ||
1249 | message + epilogue_begin, epilogue_length, | ||
1250 | NULL); | ||
1251 | if (epilogue == NULL) { | ||
1252 | res = MAILIMF_ERROR_MEMORY; | ||
1253 | goto free; | ||
1254 | } | ||
1255 | } | ||
1256 | |||
1257 | /* end of preamble and epilogue */ | ||
1258 | |||
1259 | cur_token = length; | ||
1260 | |||
1261 | * result = list; | ||
1262 | * p_preamble = preamble; | ||
1263 | * p_epilogue = epilogue; | ||
1264 | * index = cur_token; | ||
1265 | |||
1266 | return MAILIMF_NO_ERROR; | ||
1267 | |||
1268 | free: | ||
1269 | if (epilogue != NULL) | ||
1270 | mailmime_data_free(epilogue); | ||
1271 | if (preamble != NULL) | ||
1272 | mailmime_data_free(preamble); | ||
1273 | clist_foreach(list, (clist_func) mailmime_free, NULL); | ||
1274 | clist_free(list); | ||
1275 | err: | ||
1276 | return res; | ||
1277 | } | ||
1278 | |||
1279 | enum { | ||
1280 | MAILMIME_DEFAULT_TYPE_TEXT_PLAIN, | ||
1281 | MAILMIME_DEFAULT_TYPE_MESSAGE | ||
1282 | }; | ||
1283 | |||
1284 | |||
1285 | int mailmime_parse(const char * message, size_t length, | ||
1286 | size_t * index, struct mailmime ** result) | ||
1287 | { | ||
1288 | struct mailmime * mime; | ||
1289 | int r; | ||
1290 | int res; | ||
1291 | struct mailmime_content * content_message; | ||
1292 | size_t cur_token; | ||
1293 | struct mailmime_fields * mime_fields; | ||
1294 | const char * data_str; | ||
1295 | size_t data_size; | ||
1296 | size_t bp_token; | ||
1297 | |||
1298 | cur_token = * index; | ||
1299 | |||
1300 | content_message = mailmime_get_content_message(); | ||
1301 | if (content_message == NULL) { | ||
1302 | res = MAILIMF_ERROR_MEMORY; | ||
1303 | goto err; | ||
1304 | } | ||
1305 | |||
1306 | #if 0 | ||
1307 | mime_fields = mailmime_fields_new_with_data(content_message, | ||
1308 | NULL, | ||
1309 | NULL, | ||
1310 | NULL, | ||
1311 | NULL, | ||
1312 | NULL); | ||
1313 | if (mime_fields == NULL) { | ||
1314 | mailmime_content_free(content_message); | ||
1315 | res = MAILIMF_ERROR_MEMORY; | ||
1316 | goto err; | ||
1317 | } | ||
1318 | #endif | ||
1319 | mime_fields = mailmime_fields_new_empty(); | ||
1320 | if (mime_fields == NULL) { | ||
1321 | mailmime_content_free(content_message); | ||
1322 | res = MAILIMF_ERROR_MEMORY; | ||
1323 | goto err; | ||
1324 | } | ||
1325 | |||
1326 | data_str = message + cur_token; | ||
1327 | data_size = length - cur_token; | ||
1328 | |||
1329 | bp_token = 0; | ||
1330 | r = mailmime_parse_with_default(data_str, data_size, | ||
1331 | &bp_token, MAILMIME_DEFAULT_TYPE_TEXT_PLAIN, | ||
1332 | content_message, mime_fields, &mime); | ||
1333 | cur_token += bp_token; | ||
1334 | if (r != MAILIMF_NO_ERROR) { | ||
1335 | mailmime_fields_free(mime_fields); | ||
1336 | res = r; | ||
1337 | goto free; | ||
1338 | } | ||
1339 | |||
1340 | * index = cur_token; | ||
1341 | * result = mime; | ||
1342 | |||
1343 | return MAILIMF_NO_ERROR; | ||
1344 | |||
1345 | free: | ||
1346 | mailmime_fields_free(mime_fields); | ||
1347 | err: | ||
1348 | return res; | ||
1349 | } | ||
1350 | |||
1351 | |||
1352 | char * mailmime_extract_boundary(struct mailmime_content * content_type) | ||
1353 | { | ||
1354 | char * boundary; | ||
1355 | |||
1356 | boundary = mailmime_content_param_get(content_type, "boundary"); | ||
1357 | |||
1358 | if (boundary != NULL) { | ||
1359 | int len; | ||
1360 | char * new_boundary; | ||
1361 | |||
1362 | len = strlen(boundary); | ||
1363 | new_boundary = malloc(len + 1); | ||
1364 | if (new_boundary == NULL) | ||
1365 | return NULL; | ||
1366 | |||
1367 | if (boundary[0] == '"') { | ||
1368 | strncpy(new_boundary, boundary + 1, len - 2); | ||
1369 | new_boundary[len - 2] = 0; | ||
1370 | } | ||
1371 | else | ||
1372 | strcpy(new_boundary, boundary); | ||
1373 | |||
1374 | boundary = new_boundary; | ||
1375 | } | ||
1376 | |||
1377 | return boundary; | ||
1378 | } | ||
1379 | |||
1380 | static void remove_unparsed_mime_headers(struct mailimf_fields * fields) | ||
1381 | { | ||
1382 | clistiter * cur; | ||
1383 | |||
1384 | cur = clist_begin(fields->fld_list); | ||
1385 | while (cur != NULL) { | ||
1386 | struct mailimf_field * field; | ||
1387 | int delete; | ||
1388 | |||
1389 | field = clist_content(cur); | ||
1390 | |||
1391 | switch (field->fld_type) { | ||
1392 | case MAILIMF_FIELD_OPTIONAL_FIELD: | ||
1393 | delete = 0; | ||
1394 | if (strncasecmp(field->fld_data.fld_optional_field->fld_name, | ||
1395 | "Content-", 8) == 0) { | ||
1396 | char * name; | ||
1397 | |||
1398 | name = field->fld_data.fld_optional_field->fld_name + 8; | ||
1399 | if ((strcasecmp(name, "Type") == 0) | ||
1400 | || (strcasecmp(name, "Transfer-Encoding") == 0) | ||
1401 | || (strcasecmp(name, "ID") == 0) | ||
1402 | || (strcasecmp(name, "Description") == 0) | ||
1403 | || (strcasecmp(name, "Disposition") == 0) | ||
1404 | || (strcasecmp(name, "Language") == 0)) { | ||
1405 | delete = 1; | ||
1406 | } | ||
1407 | } | ||
1408 | else if (strcasecmp(field->fld_data.fld_optional_field->fld_name, | ||
1409 | "MIME-Version") == 0) { | ||
1410 | delete = 1; | ||
1411 | } | ||
1412 | |||
1413 | if (delete) { | ||
1414 | cur = clist_delete(fields->fld_list, cur); | ||
1415 | mailimf_field_free(field); | ||
1416 | } | ||
1417 | else { | ||
1418 | cur = clist_next(cur); | ||
1419 | } | ||
1420 | break; | ||
1421 | |||
1422 | default: | ||
1423 | cur = clist_next(cur); | ||
1424 | } | ||
1425 | } | ||
1426 | } | ||
1427 | |||
1428 | static int mailmime_parse_with_default(const char * message, size_t length, | ||
1429 | size_t * index, int default_type, | ||
1430 | struct mailmime_content * content_type, | ||
1431 | struct mailmime_fields * mime_fields, | ||
1432 | struct mailmime ** result) | ||
1433 | { | ||
1434 | size_t cur_token; | ||
1435 | |||
1436 | int body_type; | ||
1437 | |||
1438 | int encoding; | ||
1439 | struct mailmime_data * body; | ||
1440 | char * boundary; | ||
1441 | struct mailimf_fields * fields; | ||
1442 | clist * list; | ||
1443 | struct mailmime * msg_mime; | ||
1444 | |||
1445 | struct mailmime * mime; | ||
1446 | |||
1447 | int r; | ||
1448 | int res; | ||
1449 | struct mailmime_data * preamble; | ||
1450 | struct mailmime_data * epilogue; | ||
1451 | |||
1452 | /* | ||
1453 | note that when this function is called, content type is always detached, | ||
1454 | even if the function fails | ||
1455 | */ | ||
1456 | |||
1457 | preamble = NULL; | ||
1458 | epilogue = NULL; | ||
1459 | |||
1460 | cur_token = * index; | ||
1461 | |||
1462 | /* get content type */ | ||
1463 | |||
1464 | if (content_type == NULL) { | ||
1465 | if (mime_fields != NULL) { | ||
1466 | clistiter * cur; | ||
1467 | |||
1468 | for(cur = clist_begin(mime_fields->fld_list) ; cur != NULL ; | ||
1469 | cur = clist_next(cur)) { | ||
1470 | struct mailmime_field * field; | ||
1471 | |||
1472 | field = clist_content(cur); | ||
1473 | if (field->fld_type == MAILMIME_FIELD_TYPE) { | ||
1474 | content_type = field->fld_data.fld_content; | ||
1475 | |||
1476 | /* detach content type from list */ | ||
1477 | field->fld_data.fld_content = NULL; | ||
1478 | clist_delete(mime_fields->fld_list, cur); | ||
1479 | mailmime_field_free(field); | ||
1480 | /* | ||
1481 | there may be a leak due to the detached content type | ||
1482 | in case the function fails | ||
1483 | */ | ||
1484 | break; | ||
1485 | } | ||
1486 | } | ||
1487 | } | ||
1488 | } | ||
1489 | |||
1490 | /* set default type if no content type */ | ||
1491 | |||
1492 | if (content_type == NULL) { | ||
1493 | /* content_type is detached, in any case, we will have to free it */ | ||
1494 | if (default_type == MAILMIME_DEFAULT_TYPE_TEXT_PLAIN) { | ||
1495 | content_type = mailmime_get_content_text(); | ||
1496 | if (content_type == NULL) { | ||
1497 | res = MAILIMF_ERROR_MEMORY; | ||
1498 | goto err; | ||
1499 | } | ||
1500 | } | ||
1501 | else /* message */ { | ||
1502 | body_type = MAILMIME_MESSAGE; | ||
1503 | |||
1504 | content_type = mailmime_get_content_message(); | ||
1505 | if (content_type == NULL) { | ||
1506 | res = MAILIMF_ERROR_MEMORY; | ||
1507 | goto err; | ||
1508 | } | ||
1509 | } | ||
1510 | } | ||
1511 | |||
1512 | /* get the body type */ | ||
1513 | |||
1514 | boundary = NULL; /* XXX - removes a gcc warning */ | ||
1515 | |||
1516 | switch (content_type->ct_type->tp_type) { | ||
1517 | case MAILMIME_TYPE_COMPOSITE_TYPE: | ||
1518 | switch (content_type->ct_type->tp_data.tp_composite_type->ct_type) { | ||
1519 | case MAILMIME_COMPOSITE_TYPE_MULTIPART: | ||
1520 | boundary = mailmime_extract_boundary(content_type); | ||
1521 | |||
1522 | if (boundary == NULL) | ||
1523 | body_type = MAILMIME_SINGLE; | ||
1524 | else | ||
1525 | body_type = MAILMIME_MULTIPLE; | ||
1526 | break; | ||
1527 | |||
1528 | case MAILMIME_COMPOSITE_TYPE_MESSAGE: | ||
1529 | |||
1530 | if (strcasecmp(content_type->ct_subtype, "rfc822") == 0) | ||
1531 | body_type = MAILMIME_MESSAGE; | ||
1532 | else | ||
1533 | body_type = MAILMIME_SINGLE; | ||
1534 | break; | ||
1535 | |||
1536 | default: | ||
1537 | res = MAILIMF_ERROR_INVAL; | ||
1538 | goto free_content; | ||
1539 | } | ||
1540 | break; | ||
1541 | |||
1542 | default: /* MAILMIME_TYPE_DISCRETE_TYPE */ | ||
1543 | body_type = MAILMIME_SINGLE; | ||
1544 | break; | ||
1545 | } | ||
1546 | |||
1547 | /* set body */ | ||
1548 | |||
1549 | if (mime_fields != NULL) | ||
1550 | encoding = mailmime_transfer_encoding_get(mime_fields); | ||
1551 | else | ||
1552 | encoding = MAILMIME_MECHANISM_8BIT; | ||
1553 | |||
1554 | cur_token = * index; | ||
1555 | body = mailmime_data_new(MAILMIME_DATA_TEXT, encoding, 1, | ||
1556 | message + cur_token, length - cur_token, | ||
1557 | NULL); | ||
1558 | if (body == NULL) { | ||
1559 | res = MAILIMF_ERROR_MEMORY; | ||
1560 | goto free_content; | ||
1561 | } | ||
1562 | |||
1563 | /* in case of composite, parse the sub-part(s) */ | ||
1564 | |||
1565 | list = NULL; | ||
1566 | msg_mime = NULL; | ||
1567 | fields = NULL; | ||
1568 | |||
1569 | switch (body_type) { | ||
1570 | case MAILMIME_MESSAGE: | ||
1571 | { | ||
1572 | struct mailmime_fields * submime_fields; | ||
1573 | |||
1574 | r = mailimf_envelope_and_optional_fields_parse(message, length, | ||
1575 | &cur_token, &fields); | ||
1576 | if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { | ||
1577 | res = r; | ||
1578 | goto free_content; | ||
1579 | } | ||
1580 | |||
1581 | r = mailimf_crlf_parse(message, length, &cur_token); | ||
1582 | if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { | ||
1583 | mailimf_fields_free(fields); | ||
1584 | res = r; | ||
1585 | goto free_content; | ||
1586 | } | ||
1587 | |||
1588 | submime_fields = NULL; | ||
1589 | r = mailmime_fields_parse(fields, &submime_fields); | ||
1590 | if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { | ||
1591 | mailimf_fields_free(fields); | ||
1592 | res = r; | ||
1593 | goto free_content; | ||
1594 | } | ||
1595 | |||
1596 | remove_unparsed_mime_headers(fields); | ||
1597 | |||
1598 | r = mailmime_parse_with_default(message, length, | ||
1599 | &cur_token, MAILMIME_DEFAULT_TYPE_TEXT_PLAIN, | ||
1600 | NULL, submime_fields, &msg_mime); | ||
1601 | if (r == MAILIMF_NO_ERROR) { | ||
1602 | /* do nothing */ | ||
1603 | } | ||
1604 | else if (r == MAILIMF_ERROR_PARSE) { | ||
1605 | mailmime_fields_free(mime_fields); | ||
1606 | msg_mime = NULL; | ||
1607 | } | ||
1608 | else { | ||
1609 | mailmime_fields_free(mime_fields); | ||
1610 | res = r; | ||
1611 | goto free_content; | ||
1612 | } | ||
1613 | } | ||
1614 | |||
1615 | break; | ||
1616 | |||
1617 | case MAILMIME_MULTIPLE: | ||
1618 | { | ||
1619 | int default_subtype; | ||
1620 | |||
1621 | default_subtype = MAILMIME_DEFAULT_TYPE_TEXT_PLAIN; | ||
1622 | if (content_type != NULL) | ||
1623 | if (strcasecmp(content_type->ct_subtype, "digest") == 0) | ||
1624 | default_subtype = MAILMIME_DEFAULT_TYPE_MESSAGE; | ||
1625 | |||
1626 | cur_token = * index; | ||
1627 | r = mailmime_multipart_body_parse(message, length, | ||
1628 | &cur_token, boundary, | ||
1629 | default_subtype, | ||
1630 | &list, &preamble, &epilogue); | ||
1631 | if (r == MAILIMF_NO_ERROR) { | ||
1632 | /* do nothing */ | ||
1633 | } | ||
1634 | else if (r == MAILIMF_ERROR_PARSE) { | ||
1635 | list = clist_new(); | ||
1636 | if (list == NULL) { | ||
1637 | res = MAILIMF_ERROR_MEMORY; | ||
1638 | goto free_content; | ||
1639 | } | ||
1640 | } | ||
1641 | else { | ||
1642 | res = r; | ||
1643 | goto free_content; | ||
1644 | } | ||
1645 | |||
1646 | free(boundary); | ||
1647 | } | ||
1648 | break; | ||
1649 | |||
1650 | default: /* MAILMIME_SINGLE */ | ||
1651 | /* do nothing */ | ||
1652 | break; | ||
1653 | } | ||
1654 | |||
1655 | mime = mailmime_new(body_type, message, length, | ||
1656 | mime_fields, content_type, | ||
1657 | body, preamble, /* preamble */ | ||
1658 | epilogue, /* epilogue */ | ||
1659 | list, fields, msg_mime); | ||
1660 | if (mime == NULL) { | ||
1661 | res = MAILIMF_ERROR_MEMORY; | ||
1662 | goto free; | ||
1663 | } | ||
1664 | |||
1665 | * result = mime; | ||
1666 | * index = length; | ||
1667 | |||
1668 | return MAILIMF_NO_ERROR; | ||
1669 | |||
1670 | free: | ||
1671 | if (epilogue != NULL) | ||
1672 | mailmime_data_free(epilogue); | ||
1673 | if (preamble != NULL) | ||
1674 | mailmime_data_free(preamble); | ||
1675 | if (msg_mime != NULL) | ||
1676 | mailmime_free(msg_mime); | ||
1677 | if (list != NULL) { | ||
1678 | clist_foreach(list, (clist_func) mailmime_free, NULL); | ||
1679 | clist_free(list); | ||
1680 | } | ||
1681 | free_content: | ||
1682 | mailmime_content_free(content_type); | ||
1683 | err: | ||
1684 | return res; | ||
1685 | } | ||
1686 | |||
1687 | static int mailmime_get_section_list(struct mailmime * mime, | ||
1688 | clistiter * list, struct mailmime ** result) | ||
1689 | { | ||
1690 | uint32_t id; | ||
1691 | struct mailmime * data; | ||
1692 | struct mailmime * submime; | ||
1693 | |||
1694 | if (list == NULL) { | ||
1695 | * result = mime; | ||
1696 | return MAILIMF_NO_ERROR; | ||
1697 | } | ||
1698 | |||
1699 | id = * ((uint32_t *) clist_content(list)); | ||
1700 | |||
1701 | data = NULL; | ||
1702 | switch (mime->mm_type) { | ||
1703 | case MAILMIME_SINGLE: | ||
1704 | return MAILIMF_ERROR_INVAL; | ||
1705 | |||
1706 | case MAILMIME_MULTIPLE: | ||
1707 | data = clist_nth_data(mime->mm_data.mm_multipart.mm_mp_list, id - 1); | ||
1708 | if (data == NULL) | ||
1709 | return MAILIMF_ERROR_INVAL; | ||
1710 | |||
1711 | if (clist_next(list) != NULL) | ||
1712 | return mailmime_get_section_list(data, clist_next(list), result); | ||
1713 | else { | ||
1714 | * result = data; | ||
1715 | return MAILIMF_NO_ERROR; | ||
1716 | } | ||
1717 | |||
1718 | case MAILMIME_MESSAGE: | ||
1719 | submime = mime->mm_data.mm_message.mm_msg_mime; | ||
1720 | switch (submime->mm_type) { | ||
1721 | case MAILMIME_MULTIPLE: | ||
1722 | data = clist_nth_data(submime->mm_data.mm_multipart.mm_mp_list, id - 1); | ||
1723 | if (data == NULL) | ||
1724 | return MAILIMF_ERROR_INVAL; | ||
1725 | return mailmime_get_section_list(data, clist_next(list), result); | ||
1726 | |||
1727 | default: | ||
1728 | if (id != 1) | ||
1729 | return MAILIMF_ERROR_INVAL; | ||
1730 | |||
1731 | data = submime; | ||
1732 | if (data == NULL) | ||
1733 | return MAILIMF_ERROR_INVAL; | ||
1734 | |||
1735 | return mailmime_get_section_list(data, clist_next(list), result); | ||
1736 | } | ||
1737 | break; | ||
1738 | |||
1739 | default: | ||
1740 | return MAILIMF_ERROR_INVAL; | ||
1741 | } | ||
1742 | } | ||
1743 | |||
1744 | int mailmime_get_section(struct mailmime * mime, | ||
1745 | struct mailmime_section * section, | ||
1746 | struct mailmime ** result) | ||
1747 | { | ||
1748 | return mailmime_get_section_list(mime, | ||
1749 | clist_begin(section->sec_list), result); | ||
1750 | } | ||
1751 | |||
1752 | |||
1753 | |||
1754 | |||
1755 | |||
1756 | |||
1757 | |||
1758 | |||
1759 | |||
1760 | |||
1761 | |||
1762 | |||
1763 | |||
1764 | |||
1765 | |||
1766 | /* ************************************************************************* */ | ||
1767 | /* MIME part decoding */ | ||
1768 | |||
1769 | static inline signed char get_base64_value(char ch) | ||
1770 | { | ||
1771 | if ((ch >= 'A') && (ch <= 'Z')) | ||
1772 | return ch - 'A'; | ||
1773 | if ((ch >= 'a') && (ch <= 'z')) | ||
1774 | return ch - 'a' + 26; | ||
1775 | if ((ch >= '0') && (ch <= '9')) | ||
1776 | return ch - '0' + 52; | ||
1777 | switch (ch) { | ||
1778 | case '+': | ||
1779 | return 62; | ||
1780 | case '/': | ||
1781 | return 63; | ||
1782 | case '=': /* base64 padding */ | ||
1783 | return -1; | ||
1784 | default: | ||
1785 | return -1; | ||
1786 | } | ||
1787 | } | ||
1788 | |||
1789 | int mailmime_base64_body_parse(const char * message, size_t length, | ||
1790 | size_t * index, char ** result, | ||
1791 | size_t * result_len) | ||
1792 | { | ||
1793 | size_t cur_token; | ||
1794 | size_t i; | ||
1795 | char chunk[4]; | ||
1796 | int chunk_index; | ||
1797 | char out[3]; | ||
1798 | MMAPString * mmapstr; | ||
1799 | int res; | ||
1800 | int r; | ||
1801 | size_t written; | ||
1802 | |||
1803 | cur_token = * index; | ||
1804 | chunk_index = 0; | ||
1805 | written = 0; | ||
1806 | |||
1807 | mmapstr = mmap_string_sized_new((length - cur_token) * 3 / 4); | ||
1808 | if (mmapstr == NULL) { | ||
1809 | res = MAILIMF_ERROR_MEMORY; | ||
1810 | goto err; | ||
1811 | } | ||
1812 | |||
1813 | i = 0; | ||
1814 | while (1) { | ||
1815 | signed char value; | ||
1816 | |||
1817 | value = -1; | ||
1818 | while (value == -1) { | ||
1819 | |||
1820 | if (cur_token >= length) | ||
1821 | break; | ||
1822 | |||
1823 | value = get_base64_value(message[cur_token]); | ||
1824 | cur_token ++; | ||
1825 | } | ||
1826 | |||
1827 | if (value == -1) | ||
1828 | break; | ||
1829 | |||
1830 | chunk[chunk_index] = value; | ||
1831 | chunk_index ++; | ||
1832 | |||
1833 | if (chunk_index == 4) { | ||
1834 | out[0] = (chunk[0] << 2) | (chunk[1] >> 4); | ||
1835 | out[1] = (chunk[1] << 4) | (chunk[2] >> 2); | ||
1836 | out[2] = (chunk[2] << 6) | (chunk[3]); | ||
1837 | |||
1838 | chunk[0] = 0; | ||
1839 | chunk[1] = 0; | ||
1840 | chunk[2] = 0; | ||
1841 | chunk[3] = 0; | ||
1842 | |||
1843 | chunk_index = 0; | ||
1844 | |||
1845 | if (mmap_string_append_len(mmapstr, out, 3) == NULL) { | ||
1846 | res = MAILIMF_ERROR_MEMORY; | ||
1847 | goto free; | ||
1848 | } | ||
1849 | written += 3; | ||
1850 | } | ||
1851 | } | ||
1852 | |||
1853 | if (chunk_index != 0) { | ||
1854 | size_t len; | ||
1855 | |||
1856 | len = 0; | ||
1857 | out[0] = (chunk[0] << 2) | (chunk[1] >> 4); | ||
1858 | len ++; | ||
1859 | |||
1860 | if (chunk_index >= 3) { | ||
1861 | out[1] = (chunk[1] << 4) | (chunk[2] >> 2); | ||
1862 | len ++; | ||
1863 | } | ||
1864 | |||
1865 | if (mmap_string_append_len(mmapstr, out, len) == NULL) { | ||
1866 | res = MAILIMF_ERROR_MEMORY; | ||
1867 | goto free; | ||
1868 | } | ||
1869 | written += len; | ||
1870 | } | ||
1871 | |||
1872 | r = mmap_string_ref(mmapstr); | ||
1873 | if (r < 0) { | ||
1874 | res = MAILIMF_ERROR_MEMORY; | ||
1875 | goto free; | ||
1876 | } | ||
1877 | |||
1878 | * index = cur_token; | ||
1879 | * result = mmapstr->str; | ||
1880 | * result_len = written; | ||
1881 | |||
1882 | return MAILIMF_NO_ERROR; | ||
1883 | |||
1884 | free: | ||
1885 | mmap_string_free(mmapstr); | ||
1886 | err: | ||
1887 | return res; | ||
1888 | } | ||
1889 | |||
1890 | |||
1891 | |||
1892 | static inline int hexa_to_char(char hexdigit) | ||
1893 | { | ||
1894 | if ((hexdigit >= '0') && (hexdigit <= '9')) | ||
1895 | return hexdigit - '0'; | ||
1896 | if ((hexdigit >= 'a') && (hexdigit <= 'f')) | ||
1897 | return hexdigit - 'a' + 10; | ||
1898 | if ((hexdigit >= 'A') && (hexdigit <= 'F')) | ||
1899 | return hexdigit - 'A' + 10; | ||
1900 | return 0; | ||
1901 | } | ||
1902 | |||
1903 | static inline char to_char(const char * hexa) | ||
1904 | { | ||
1905 | return (hexa_to_char(hexa[0]) << 4) | hexa_to_char(hexa[1]); | ||
1906 | } | ||
1907 | |||
1908 | enum { | ||
1909 | STATE_NORMAL, | ||
1910 | STATE_CODED, | ||
1911 | STATE_OUT, | ||
1912 | STATE_CR, | ||
1913 | }; | ||
1914 | |||
1915 | |||
1916 | static int write_decoded_qp(MMAPString * mmapstr, | ||
1917 | const char * start, size_t count) | ||
1918 | { | ||
1919 | if (mmap_string_append_len(mmapstr, start, count) == NULL) | ||
1920 | return MAILIMF_ERROR_MEMORY; | ||
1921 | |||
1922 | return MAILIMF_NO_ERROR; | ||
1923 | } | ||
1924 | |||
1925 | |||
1926 | #define WRITE_MAX_QP 512 | ||
1927 | |||
1928 | int mailmime_quoted_printable_body_parse(const char * message, size_t length, | ||
1929 | size_t * index, char ** result, | ||
1930 | size_t * result_len, int in_header) | ||
1931 | { | ||
1932 | size_t cur_token; | ||
1933 | int state; | ||
1934 | int r; | ||
1935 | char ch; | ||
1936 | size_t count; | ||
1937 | const char * start; | ||
1938 | MMAPString * mmapstr; | ||
1939 | int res; | ||
1940 | size_t written; | ||
1941 | |||
1942 | state = STATE_NORMAL; | ||
1943 | cur_token = * index; | ||
1944 | |||
1945 | count = 0; | ||
1946 | start = message + cur_token; | ||
1947 | written = 0; | ||
1948 | |||
1949 | mmapstr = mmap_string_sized_new(length - cur_token); | ||
1950 | if (mmapstr == NULL) { | ||
1951 | res = MAILIMF_ERROR_MEMORY; | ||
1952 | goto err; | ||
1953 | } | ||
1954 | |||
1955 | #if 0 | ||
1956 | if (length >= 1) { | ||
1957 | if (message[length - 1] == '\n') { | ||
1958 | length --; | ||
1959 | if (length >= 1) | ||
1960 | if (message[length - 1] == '\r') { | ||
1961 | length --; | ||
1962 | } | ||
1963 | } | ||
1964 | } | ||
1965 | #endif | ||
1966 | |||
1967 | while (state != STATE_OUT) { | ||
1968 | |||
1969 | if (cur_token >= length) { | ||
1970 | state = STATE_OUT; | ||
1971 | break; | ||
1972 | } | ||
1973 | |||
1974 | switch (state) { | ||
1975 | |||
1976 | case STATE_CODED: | ||
1977 | |||
1978 | if (count > 0) { | ||
1979 | r = write_decoded_qp(mmapstr, start, count); | ||
1980 | if (r != MAILIMF_NO_ERROR) { | ||
1981 | res = r; | ||
1982 | goto free; | ||
1983 | } | ||
1984 | written += count; | ||
1985 | count = 0; | ||
1986 | } | ||
1987 | |||
1988 | switch (message[cur_token]) { | ||
1989 | case '=': | ||
1990 | if (cur_token + 1 >= length) { | ||
1991 | /* error but ignore it */ | ||
1992 | state = STATE_NORMAL; | ||
1993 | start = message + cur_token; | ||
1994 | cur_token ++; | ||
1995 | count ++; | ||
1996 | break; | ||
1997 | } | ||
1998 | |||
1999 | switch (message[cur_token + 1]) { | ||
2000 | |||
2001 | case '\n': | ||
2002 | cur_token += 2; | ||
2003 | |||
2004 | start = message + cur_token; | ||
2005 | |||
2006 | state = STATE_NORMAL; | ||
2007 | break; | ||
2008 | |||
2009 | case '\r': | ||
2010 | if (cur_token + 2 >= length) { | ||
2011 | state = STATE_OUT; | ||
2012 | break; | ||
2013 | } | ||
2014 | |||
2015 | if (message[cur_token + 2] == '\n') | ||
2016 | cur_token += 3; | ||
2017 | else | ||
2018 | cur_token += 2; | ||
2019 | |||
2020 | start = message + cur_token; | ||
2021 | |||
2022 | state = STATE_NORMAL; | ||
2023 | |||
2024 | break; | ||
2025 | |||
2026 | default: | ||
2027 | if (cur_token + 2 >= length) { | ||
2028 | /* error but ignore it */ | ||
2029 | cur_token ++; | ||
2030 | |||
2031 | start = message + cur_token; | ||
2032 | |||
2033 | count ++; | ||
2034 | state = STATE_NORMAL; | ||
2035 | break; | ||
2036 | } | ||
2037 | |||
2038 | #if 0 | ||
2039 | /* flush before writing additionnal information */ | ||
2040 | r = write_decoded_qp(mmapstr, start, count); | ||
2041 | if (r != MAILIMF_NO_ERROR) { | ||
2042 | res = r; | ||
2043 | goto free; | ||
2044 | } | ||
2045 | written += count; | ||
2046 | count = 0; | ||
2047 | #endif | ||
2048 | |||
2049 | ch = to_char(message + cur_token + 1); | ||
2050 | |||
2051 | if (mmap_string_append_c(mmapstr, ch) == NULL) { | ||
2052 | res = MAILIMF_ERROR_MEMORY; | ||
2053 | goto free; | ||
2054 | } | ||
2055 | |||
2056 | cur_token += 3; | ||
2057 | written ++; | ||
2058 | |||
2059 | start = message + cur_token; | ||
2060 | |||
2061 | state = STATE_NORMAL; | ||
2062 | break; | ||
2063 | } | ||
2064 | break; | ||
2065 | } | ||
2066 | break; /* end of STATE_ENCODED */ | ||
2067 | |||
2068 | case STATE_NORMAL: | ||
2069 | |||
2070 | switch (message[cur_token]) { | ||
2071 | |||
2072 | case '=': | ||
2073 | state = STATE_CODED; | ||
2074 | break; | ||
2075 | |||
2076 | case '\n': | ||
2077 | /* flush before writing additionnal information */ | ||
2078 | if (count > 0) { | ||
2079 | r = write_decoded_qp(mmapstr, start, count); | ||
2080 | if (r != MAILIMF_NO_ERROR) { | ||
2081 | res = r; | ||
2082 | goto free; | ||
2083 | } | ||
2084 | written += count; | ||
2085 | |||
2086 | count = 0; | ||
2087 | } | ||
2088 | |||
2089 | r = write_decoded_qp(mmapstr, "\r\n", 2); | ||
2090 | if (r != MAILIMF_NO_ERROR) { | ||
2091 | res = r; | ||
2092 | goto free; | ||
2093 | } | ||
2094 | written += 2; | ||
2095 | cur_token ++; | ||
2096 | start = message + cur_token; | ||
2097 | break; | ||
2098 | |||
2099 | case '\r': | ||
2100 | state = STATE_CR; | ||
2101 | cur_token ++; | ||
2102 | break; | ||
2103 | |||
2104 | case '_': | ||
2105 | if (in_header) { | ||
2106 | if (count > 0) { | ||
2107 | r = write_decoded_qp(mmapstr, start, count); | ||
2108 | if (r != MAILIMF_NO_ERROR) { | ||
2109 | res = r; | ||
2110 | goto free; | ||
2111 | } | ||
2112 | written += count; | ||
2113 | count = 0; | ||
2114 | } | ||
2115 | |||
2116 | if (mmap_string_append_c(mmapstr, ' ') == NULL) { | ||
2117 | res = MAILIMF_ERROR_MEMORY; | ||
2118 | goto free; | ||
2119 | } | ||
2120 | |||
2121 | written ++; | ||
2122 | cur_token ++; | ||
2123 | start = message + cur_token; | ||
2124 | |||
2125 | break; | ||
2126 | } | ||
2127 | /* WARINING : must be followed by switch default action */ | ||
2128 | |||
2129 | default: | ||
2130 | if (count >= WRITE_MAX_QP) { | ||
2131 | r = write_decoded_qp(mmapstr, start, count); | ||
2132 | if (r != MAILIMF_NO_ERROR) { | ||
2133 | res = r; | ||
2134 | goto free; | ||
2135 | } | ||
2136 | written += count; | ||
2137 | count = 0; | ||
2138 | start = message + cur_token; | ||
2139 | } | ||
2140 | |||
2141 | count ++; | ||
2142 | cur_token ++; | ||
2143 | break; | ||
2144 | } | ||
2145 | break; /* end of STATE_NORMAL */ | ||
2146 | |||
2147 | case STATE_CR: | ||
2148 | switch (message[cur_token]) { | ||
2149 | |||
2150 | case '\n': | ||
2151 | /* flush before writing additionnal information */ | ||
2152 | if (count > 0) { | ||
2153 | r = write_decoded_qp(mmapstr, start, count); | ||
2154 | if (r != MAILIMF_NO_ERROR) { | ||
2155 | res = r; | ||
2156 | goto free; | ||
2157 | } | ||
2158 | written += count; | ||
2159 | count = 0; | ||
2160 | } | ||
2161 | |||
2162 | r = write_decoded_qp(mmapstr, "\r\n", 2); | ||
2163 | if (r != MAILIMF_NO_ERROR) { | ||
2164 | res = r; | ||
2165 | goto free; | ||
2166 | } | ||
2167 | written += 2; | ||
2168 | cur_token ++; | ||
2169 | start = message + cur_token; | ||
2170 | state = STATE_NORMAL; | ||
2171 | break; | ||
2172 | |||
2173 | default: | ||
2174 | /* flush before writing additionnal information */ | ||
2175 | if (count > 0) { | ||
2176 | r = write_decoded_qp(mmapstr, start, count); | ||
2177 | if (r != MAILIMF_NO_ERROR) { | ||
2178 | res = r; | ||
2179 | goto free; | ||
2180 | } | ||
2181 | written += count; | ||
2182 | count = 0; | ||
2183 | } | ||
2184 | |||
2185 | start = message + cur_token; | ||
2186 | |||
2187 | r = write_decoded_qp(mmapstr, "\r\n", 2); | ||
2188 | if (r != MAILIMF_NO_ERROR) { | ||
2189 | res = r; | ||
2190 | goto free; | ||
2191 | } | ||
2192 | written += 2; | ||
2193 | state = STATE_NORMAL; | ||
2194 | } | ||
2195 | break; /* end of STATE_CR */ | ||
2196 | } | ||
2197 | } | ||
2198 | |||
2199 | if (count > 0) { | ||
2200 | r = write_decoded_qp(mmapstr, start, count); | ||
2201 | if (r != MAILIMF_NO_ERROR) { | ||
2202 | res = r; | ||
2203 | goto free; | ||
2204 | } | ||
2205 | written += count; | ||
2206 | count = 0; | ||
2207 | } | ||
2208 | |||
2209 | r = mmap_string_ref(mmapstr); | ||
2210 | if (r < 0) { | ||
2211 | res = MAILIMF_ERROR_MEMORY; | ||
2212 | goto free; | ||
2213 | } | ||
2214 | |||
2215 | * index = cur_token; | ||
2216 | * result = mmapstr->str; | ||
2217 | * result_len = written; | ||
2218 | |||
2219 | return MAILIMF_NO_ERROR; | ||
2220 | |||
2221 | free: | ||
2222 | mmap_string_free(mmapstr); | ||
2223 | err: | ||
2224 | return res; | ||
2225 | } | ||
2226 | |||
2227 | int mailmime_binary_body_parse(const char * message, size_t length, | ||
2228 | size_t * index, char ** result, | ||
2229 | size_t * result_len) | ||
2230 | { | ||
2231 | MMAPString * mmapstr; | ||
2232 | size_t cur_token; | ||
2233 | int r; | ||
2234 | int res; | ||
2235 | |||
2236 | cur_token = * index; | ||
2237 | |||
2238 | if (length >= 1) { | ||
2239 | if (message[length - 1] == '\n') { | ||
2240 | length --; | ||
2241 | if (length >= 1) | ||
2242 | if (message[length - 1] == '\r') | ||
2243 | length --; | ||
2244 | } | ||
2245 | } | ||
2246 | |||
2247 | mmapstr = mmap_string_new_len(message + cur_token, length - cur_token); | ||
2248 | if (mmapstr == NULL) { | ||
2249 | res = MAILIMF_ERROR_MEMORY; | ||
2250 | goto err; | ||
2251 | } | ||
2252 | |||
2253 | r = mmap_string_ref(mmapstr); | ||
2254 | if (r < 0) { | ||
2255 | res = MAILIMF_ERROR_MEMORY; | ||
2256 | goto free; | ||
2257 | } | ||
2258 | |||
2259 | * index = length; | ||
2260 | * result = mmapstr->str; | ||
2261 | * result_len = length - cur_token; | ||
2262 | |||
2263 | return MAILIMF_NO_ERROR; | ||
2264 | |||
2265 | free: | ||
2266 | mmap_string_free(mmapstr); | ||
2267 | err: | ||
2268 | return res; | ||
2269 | } | ||
2270 | |||
2271 | |||
2272 | int mailmime_part_parse(const char * message, size_t length, | ||
2273 | size_t * index, | ||
2274 | int encoding, char ** result, size_t * result_len) | ||
2275 | { | ||
2276 | switch (encoding) { | ||
2277 | case MAILMIME_MECHANISM_BASE64: | ||
2278 | return mailmime_base64_body_parse(message, length, index, | ||
2279 | result, result_len); | ||
2280 | |||
2281 | case MAILMIME_MECHANISM_QUOTED_PRINTABLE: | ||
2282 | return mailmime_quoted_printable_body_parse(message, length, index, | ||
2283 | result, result_len, FALSE); | ||
2284 | |||
2285 | case MAILMIME_MECHANISM_7BIT: | ||
2286 | case MAILMIME_MECHANISM_8BIT: | ||
2287 | case MAILMIME_MECHANISM_BINARY: | ||
2288 | default: | ||
2289 | return mailmime_binary_body_parse(message, length, index, | ||
2290 | result, result_len); | ||
2291 | } | ||
2292 | } | ||
2293 | |||
2294 | int mailmime_get_section_id(struct mailmime * mime, | ||
2295 | struct mailmime_section ** result) | ||
2296 | { | ||
2297 | clist * list; | ||
2298 | int res; | ||
2299 | struct mailmime_section * section_id; | ||
2300 | int r; | ||
2301 | |||
2302 | if (mime->mm_parent == NULL) { | ||
2303 | list = clist_new(); | ||
2304 | if (list == NULL) { | ||
2305 | res = MAILIMF_ERROR_MEMORY; | ||
2306 | goto err; | ||
2307 | } | ||
2308 | |||
2309 | section_id = mailmime_section_new(list); | ||
2310 | if (section_id == NULL) { | ||
2311 | res = MAILIMF_ERROR_MEMORY; | ||
2312 | goto err; | ||
2313 | } | ||
2314 | } | ||
2315 | else { | ||
2316 | uint32_t id; | ||
2317 | uint32_t * p_id; | ||
2318 | clistiter * cur; | ||
2319 | struct mailmime * parent; | ||
2320 | |||
2321 | r = mailmime_get_section_id(mime->mm_parent, §ion_id); | ||
2322 | if (r != MAILIMF_NO_ERROR) { | ||
2323 | res = r; | ||
2324 | goto err; | ||
2325 | } | ||
2326 | |||
2327 | parent = mime->mm_parent; | ||
2328 | switch (parent->mm_type) { | ||
2329 | case MAILMIME_MULTIPLE: | ||
2330 | id = 1; | ||
2331 | for(cur = clist_begin(parent->mm_data.mm_multipart.mm_mp_list) ; | ||
2332 | cur != NULL ; cur = clist_next(cur)) { | ||
2333 | if (clist_content(cur) == mime) | ||
2334 | break; | ||
2335 | id ++; | ||
2336 | } | ||
2337 | |||
2338 | p_id = malloc(sizeof(* p_id)); | ||
2339 | if (p_id == NULL) { | ||
2340 | res = MAILIMF_ERROR_MEMORY; | ||
2341 | goto free; | ||
2342 | } | ||
2343 | * p_id = id; | ||
2344 | |||
2345 | r = clist_append(section_id->sec_list, p_id); | ||
2346 | if (r < 0) { | ||
2347 | free(p_id); | ||
2348 | res = MAILIMF_ERROR_MEMORY; | ||
2349 | goto free; | ||
2350 | } | ||
2351 | break; | ||
2352 | |||
2353 | case MAILMIME_MESSAGE: | ||
2354 | if ((mime->mm_type == MAILMIME_SINGLE) || | ||
2355 | (mime->mm_type == MAILMIME_MESSAGE)) { | ||
2356 | p_id = malloc(sizeof(* p_id)); | ||
2357 | if (p_id == NULL) { | ||
2358 | res = MAILIMF_ERROR_MEMORY; | ||
2359 | goto free; | ||
2360 | } | ||
2361 | * p_id = 1; | ||
2362 | |||
2363 | r = clist_append(section_id->sec_list, p_id); | ||
2364 | if (r < 0) { | ||
2365 | free(p_id); | ||
2366 | res = MAILIMF_ERROR_MEMORY; | ||
2367 | goto free; | ||
2368 | } | ||
2369 | } | ||
2370 | } | ||
2371 | } | ||
2372 | |||
2373 | * result = section_id; | ||
2374 | |||
2375 | return MAILIMF_NO_ERROR; | ||
2376 | |||
2377 | free: | ||
2378 | mailmime_section_free(section_id); | ||
2379 | err: | ||
2380 | return res; | ||
2381 | } | ||