summaryrefslogtreecommitdiffabout
path: root/kmicromail/libetpan/mime/mailmime_content.c
Unidiff
Diffstat (limited to 'kmicromail/libetpan/mime/mailmime_content.c') (more/less context) (show whitespace changes)
-rw-r--r--kmicromail/libetpan/mime/mailmime_content.c2164
1 files changed, 2164 insertions, 0 deletions
diff --git a/kmicromail/libetpan/mime/mailmime_content.c b/kmicromail/libetpan/mime/mailmime_content.c
new file mode 100644
index 0000000..c73812d
--- a/dev/null
+++ b/kmicromail/libetpan/mime/mailmime_content.c
@@ -0,0 +1,2164 @@
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#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
62static 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
70char * 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
81char * 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/*
2005.2.3.3. The 'anon-ftp' Access-Type
201*/
202
203/*
2045.2.3.4. The 'local-file' Access-Type
205NAME
206SITE
207*/
208
209/*
2105.2.3.5. The 'mail-server' Access-Type
211SERVER
212SUBJECT
213*/
214
215
216enum {
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
226static 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
346static 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
369static int is_wsp(char ch)
370{
371 if ((ch == ' ') || (ch == '\t'))
372 return TRUE;
373
374 return FALSE;
375}
376
377static 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/*
402gboolean mailimf_crlf_parse(gchar * message, guint32 length, guint32 * index)
403*/
404
405enum {
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
415static int
416mailmime_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 end_text --;
519 if (end_text >= 1)
520 if (message[end_text - 1] == '\r')
521 end_text --;
522
523 size = end_text - begin_text;
524
525#if 0
526 body_part = mailimf_body_new(message + begin_text, size);
527 if (body_part == NULL)
528 goto err;
529#endif
530
531 * result = message + begin_text;
532 * result_size = size;
533 * index = cur_token;
534
535 return MAILIMF_NO_ERROR;
536#if 0
537 err:
538 return MAILIMF_ERROR_PARSE;
539#endif
540}
541
542enum {
543 MULTIPART_CLOSE_STATE_0,
544 MULTIPART_CLOSE_STATE_1,
545 MULTIPART_CLOSE_STATE_2,
546 MULTIPART_CLOSE_STATE_3,
547 MULTIPART_CLOSE_STATE_4
548};
549
550static int mailmime_multipart_close_parse(const char * message, size_t length,
551 size_t * index)
552{
553 int state;
554 size_t cur_token;
555
556 cur_token = * index;
557 state = MULTIPART_CLOSE_STATE_0;
558
559 while (state != MULTIPART_CLOSE_STATE_4) {
560
561 switch(state) {
562
563 case MULTIPART_CLOSE_STATE_0:
564 if (cur_token >= length)
565 return MAILIMF_ERROR_PARSE;
566
567 switch (message[cur_token]) {
568 case '-':
569 state = MULTIPART_CLOSE_STATE_1;
570 break;
571 default:
572 return MAILIMF_ERROR_PARSE;
573 }
574 break;
575
576 case MULTIPART_CLOSE_STATE_1:
577 if (cur_token >= length)
578 return MAILIMF_ERROR_PARSE;
579
580 switch (message[cur_token]) {
581 case '-':
582 state = MULTIPART_CLOSE_STATE_2;
583 break;
584 default:
585 return MAILIMF_ERROR_PARSE;
586 }
587 break;
588
589 case MULTIPART_CLOSE_STATE_2:
590 if (cur_token >= length) {
591 state = MULTIPART_CLOSE_STATE_4;
592 break;
593 }
594
595 switch (message[cur_token]) {
596 case ' ':
597 state = MULTIPART_CLOSE_STATE_2;
598 break;
599 case '\t':
600 state = MULTIPART_CLOSE_STATE_2;
601 break;
602 case '\r':
603 state = MULTIPART_CLOSE_STATE_3;
604 break;
605 case '\n':
606 state = MULTIPART_CLOSE_STATE_4;
607 break;
608 default:
609 state = MULTIPART_CLOSE_STATE_4;
610 break;
611 }
612 break;
613
614 case MULTIPART_CLOSE_STATE_3:
615 if (cur_token >= length) {
616 state = MULTIPART_CLOSE_STATE_4;
617 break;
618 }
619
620 switch (message[cur_token]) {
621 case '\n':
622 state = MULTIPART_CLOSE_STATE_4;
623 break;
624 default:
625 state = MULTIPART_CLOSE_STATE_4;
626 break;
627 }
628 break;
629 }
630
631 cur_token ++;
632 }
633
634 * index = cur_token;
635
636 return MAILIMF_NO_ERROR;
637}
638
639enum {
640 MULTIPART_NEXT_STATE_0,
641 MULTIPART_NEXT_STATE_1,
642 MULTIPART_NEXT_STATE_2
643};
644
645int mailmime_multipart_next_parse(const char * message, size_t length,
646 size_t * index)
647{
648 int state;
649 size_t cur_token;
650
651 cur_token = * index;
652 state = MULTIPART_NEXT_STATE_0;
653
654 while (state != MULTIPART_NEXT_STATE_2) {
655
656 if (cur_token >= length)
657 return MAILIMF_ERROR_PARSE;
658
659 switch(state) {
660
661 case MULTIPART_NEXT_STATE_0:
662 switch (message[cur_token]) {
663 case ' ':
664 state = MULTIPART_NEXT_STATE_0;
665 break;
666 case '\t':
667 state = MULTIPART_NEXT_STATE_0;
668 break;
669 case '\r':
670 state = MULTIPART_NEXT_STATE_1;
671 break;
672 case '\n':
673 state = MULTIPART_NEXT_STATE_2;
674 break;
675 default:
676 return MAILIMF_ERROR_PARSE;
677 }
678 break;
679
680 case MULTIPART_NEXT_STATE_1:
681 switch (message[cur_token]) {
682 case '\n':
683 state = MULTIPART_NEXT_STATE_2;
684 break;
685 default:
686 return MAILIMF_ERROR_PARSE;
687 }
688 break;
689 }
690
691 cur_token ++;
692 }
693
694 * index = cur_token;
695
696 return MAILIMF_NO_ERROR;
697}
698
699static int
700mailmime_multipart_body_parse(const char * message, size_t length,
701 size_t * index, char * boundary,
702 int default_subtype,
703 clist ** result,
704 struct mailmime_data ** p_preamble,
705 struct mailmime_data ** p_epilogue)
706{
707 size_t cur_token;
708 clist * list;
709 int r;
710 int res;
711#if 0
712 size_t begin;
713#endif
714 size_t preamble_begin;
715 size_t preamble_length;
716 size_t preamble_end;
717#if 0
718 int no_preamble;
719 size_t before_crlf;
720#endif
721 size_t epilogue_begin;
722 size_t epilogue_length;
723 struct mailmime_data * preamble;
724 struct mailmime_data * epilogue;
725 size_t part_begin;
726
727 preamble = NULL;
728 epilogue = NULL;
729
730 cur_token = * index;
731 preamble_begin = cur_token;
732
733#if 0
734 no_preamble = FALSE;
735#endif
736 preamble_end = preamble_begin;
737
738#if 0
739 r = mailmime_preamble_parse(message, length, &cur_token);
740 if (r == MAILIMF_NO_ERROR) {
741 /* do nothing */
742#if 0
743 preamble_end = cur_token - 2;
744#endif
745 }
746 else if (r == MAILIMF_ERROR_PARSE) {
747 /* do nothing */
748 no_preamble = TRUE;
749 }
750 else {
751 res = r;
752 goto err;
753 }
754
755 while (1) {
756
757 preamble_end = cur_token;
758 r = mailmime_boundary_parse(message, length, &cur_token, boundary);
759 if (r == MAILIMF_NO_ERROR) {
760 break;
761 }
762 else if (r == MAILIMF_ERROR_PARSE) {
763 /* do nothing */
764 }
765 else {
766 res = r;
767 goto err;
768 }
769
770 r = mailmime_preamble_parse(message, length, &cur_token);
771 if (r == MAILIMF_NO_ERROR) {
772#if 0
773 preamble_end = cur_token - 2;
774#endif
775 }
776 else if (r == MAILIMF_ERROR_PARSE) {
777 no_preamble = TRUE;
778 break;
779 }
780 else {
781 res = r;
782 goto err;
783 }
784 }
785
786 if (no_preamble) {
787#if 0
788 preamble_end = cur_token;
789#endif
790 }
791 else {
792
793 r = mailmime_lwsp_parse(message, length, &cur_token);
794 if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
795 res = r;
796 goto err;
797 }
798
799 before_crlf = cur_token;
800 r = mailimf_crlf_parse(message, length, &cur_token);
801 if (r == MAILIMF_NO_ERROR) {
802#if 0
803 preamble_end = before_crlf;
804#endif
805 /* remove the CR LF at the end of preamble if any */
806 }
807 else if (r == MAILIMF_ERROR_PARSE) {
808 /* do nothing */
809 }
810 else {
811 res = r;
812 goto err;
813 }
814 }
815 preamble_length = preamble_end - begin;
816#endif
817
818 r = mailmime_preamble_parse(message, length, &cur_token, 1);
819 if (r == MAILIMF_NO_ERROR) {
820 while (1) {
821
822 preamble_end = cur_token;
823 r = mailmime_boundary_parse(message, length, &cur_token, boundary);
824 if (r == MAILIMF_NO_ERROR) {
825 break;
826 }
827 else if (r == MAILIMF_ERROR_PARSE) {
828 /* do nothing */
829 }
830 else {
831 res = r;
832 goto err;
833 }
834
835 r = mailmime_preamble_parse(message, length, &cur_token, 0);
836 if (r == MAILIMF_NO_ERROR) {
837 }
838 else if (r == MAILIMF_ERROR_PARSE) {
839 break;
840 }
841 else {
842 res = r;
843 goto err;
844 }
845 }
846 }
847
848 preamble_end -= 2;
849 if (preamble_end != preamble_begin) {
850 /* try to find the real end of the preamble (strip CR LF) */
851 if (message[preamble_end - 1] == '\n') {
852 preamble_end --;
853 if (preamble_end - 1 >= preamble_begin) {
854 if (message[preamble_end - 1] == '\r')
855 preamble_end --;
856 }
857 }
858 else if (message[preamble_end - 1] == '\r') {
859 preamble_end --;
860 }
861 }
862 preamble_length = preamble_end - preamble_begin;
863
864 part_begin = cur_token;
865 while (1) {
866 r = mailmime_lwsp_parse(message, length, &cur_token);
867 if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
868 res = r;
869 goto err;
870 }
871#if 0
872 if (r == MAILIMF_ERROR_PARSE)
873 break;
874#endif
875
876 r = mailimf_crlf_parse(message, length, &cur_token);
877 if (r == MAILIMF_NO_ERROR) {
878 part_begin = cur_token;
879 }
880 else if (r == MAILIMF_ERROR_PARSE) {
881 /* do nothing */
882 break;
883 }
884 else {
885 res = r;
886 goto err;
887 }
888 }
889
890 cur_token = part_begin;
891
892 list = clist_new();
893 if (list == NULL) {
894 res = MAILIMF_ERROR_MEMORY;
895 goto err;
896 }
897
898 while (1) {
899 size_t bp_token;
900 struct mailmime * mime_bp;
901 const char * data_str;
902 size_t data_size;
903 struct mailimf_fields * fields;
904 struct mailmime_fields * mime_fields;
905
906 r = mailmime_body_part_dash2_parse(message, length, &cur_token,
907 boundary, &data_str, &data_size);
908 if (r == MAILIMF_NO_ERROR) {
909 /* do nothing */
910 }
911 else if (r == MAILIMF_ERROR_PARSE) {
912 break;
913 }
914 else {
915 res = r;
916 goto free;
917 }
918
919 bp_token = 0;
920
921
922 r = mailimf_optional_fields_parse(data_str, data_size,
923 &bp_token, &fields);
924 if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
925 res = r;
926 goto free;
927 }
928
929 r = mailimf_crlf_parse(data_str, data_size, &bp_token);
930 if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
931 mailimf_fields_free(fields);
932 res = r;
933 goto free;
934 }
935
936 mime_fields = NULL;
937 r = mailmime_fields_parse(fields, &mime_fields);
938 mailimf_fields_free(fields);
939 if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
940 res = r;
941 goto free;
942 }
943
944 r = mailmime_parse_with_default(data_str, data_size,
945 &bp_token, default_subtype, NULL,
946 mime_fields, &mime_bp);
947 if (r == MAILIMF_NO_ERROR) {
948 r = clist_append(list, mime_bp);
949 if (r < 0) {
950 mailmime_free(mime_bp);
951 res = MAILIMF_ERROR_MEMORY;
952 goto free;
953 }
954 }
955 else if (r == MAILIMF_ERROR_PARSE) {
956 mailmime_fields_free(mime_fields);
957 break;
958 }
959 else {
960 mailmime_fields_free(mime_fields);
961 res = r;
962 goto free;
963 }
964
965 r = mailmime_multipart_next_parse(message, length, &cur_token);
966 if (r == MAILIMF_NO_ERROR) {
967 /* do nothing */
968 }
969 else if (r == MAILIMF_ERROR_PARSE) {
970 r = mailmime_multipart_close_parse(message, length, &cur_token);
971 if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
972 res = r;
973 goto free;
974 }
975 break;
976 }
977 else {
978 res = r;
979 goto free;
980 }
981 }
982
983 epilogue_begin = length;
984 /* parse transport-padding */
985 while (1) {
986 r = mailmime_lwsp_parse(message, length, &cur_token);
987 if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
988 res = r;
989 goto free;
990 }
991#if 0
992 if (r == MAILIMF_ERROR_PARSE)
993 break;
994#endif
995
996#if 0
997 before_crlf = cur_token;
998#endif
999 r = mailimf_crlf_parse(message, length, &cur_token);
1000 if (r == MAILIMF_NO_ERROR) {
1001 epilogue_begin = cur_token;
1002 break;
1003 }
1004 else if (r == MAILIMF_ERROR_PARSE) {
1005 /* do nothing */
1006 break;
1007 }
1008 else {
1009 res = r;
1010 goto free;
1011 }
1012 }
1013
1014 /* add preamble and epilogue */
1015
1016 epilogue_length = length - epilogue_begin;
1017
1018 if (preamble_length != 0) {
1019 preamble = mailmime_data_new(MAILMIME_DATA_TEXT,
1020 MAILMIME_MECHANISM_8BIT, 1,
1021 message + preamble_begin, preamble_length,
1022 NULL);
1023 if (preamble == NULL) {
1024 res = MAILIMF_ERROR_MEMORY;
1025 goto free;
1026 }
1027 }
1028
1029 if (epilogue_length != 0) {
1030 epilogue = mailmime_data_new(MAILMIME_DATA_TEXT,
1031 MAILMIME_MECHANISM_8BIT, 1,
1032 message + epilogue_begin, epilogue_length,
1033 NULL);
1034 if (epilogue == NULL) {
1035 res = MAILIMF_ERROR_MEMORY;
1036 goto free;
1037 }
1038 }
1039
1040 /* end of preamble and epilogue */
1041
1042 cur_token = length;
1043
1044 * result = list;
1045 * p_preamble = preamble;
1046 * p_epilogue = epilogue;
1047 * index = cur_token;
1048
1049 return MAILIMF_NO_ERROR;
1050
1051 free:
1052 if (epilogue != NULL)
1053 mailmime_data_free(epilogue);
1054 if (preamble != NULL)
1055 mailmime_data_free(preamble);
1056 clist_foreach(list, (clist_func) mailmime_free, NULL);
1057 clist_free(list);
1058 err:
1059 return res;
1060}
1061
1062enum {
1063 MAILMIME_DEFAULT_TYPE_TEXT_PLAIN,
1064 MAILMIME_DEFAULT_TYPE_MESSAGE
1065};
1066
1067
1068int mailmime_parse(const char * message, size_t length,
1069 size_t * index, struct mailmime ** result)
1070{
1071 struct mailmime * mime;
1072 int r;
1073 int res;
1074 struct mailmime_content * content_message;
1075 size_t cur_token;
1076 struct mailmime_fields * mime_fields;
1077 const char * data_str;
1078 size_t data_size;
1079 size_t bp_token;
1080
1081 cur_token = * index;
1082
1083 content_message = mailmime_get_content_message();
1084 if (content_message == NULL) {
1085 res = MAILIMF_ERROR_MEMORY;
1086 goto err;
1087 }
1088
1089#if 0
1090 mime_fields = mailmime_fields_new_with_data(content_message,
1091 NULL,
1092 NULL,
1093 NULL,
1094 NULL,
1095 NULL);
1096 if (mime_fields == NULL) {
1097 mailmime_content_free(content_message);
1098 res = MAILIMF_ERROR_MEMORY;
1099 goto err;
1100 }
1101#endif
1102 mime_fields = mailmime_fields_new_empty();
1103 if (mime_fields == NULL) {
1104 mailmime_content_free(content_message);
1105 res = MAILIMF_ERROR_MEMORY;
1106 goto err;
1107 }
1108
1109 data_str = message + cur_token;
1110 data_size = length - cur_token;
1111
1112 bp_token = 0;
1113 r = mailmime_parse_with_default(data_str, data_size,
1114 &bp_token, MAILMIME_DEFAULT_TYPE_TEXT_PLAIN,
1115 content_message, mime_fields, &mime);
1116 cur_token += bp_token;
1117 if (r != MAILIMF_NO_ERROR) {
1118 mailmime_fields_free(mime_fields);
1119 res = r;
1120 goto free;
1121 }
1122
1123 * index = cur_token;
1124 * result = mime;
1125
1126 return MAILIMF_NO_ERROR;
1127
1128 free:
1129 mailmime_fields_free(mime_fields);
1130 err:
1131 return res;
1132}
1133
1134
1135char * mailmime_extract_boundary(struct mailmime_content * content_type)
1136{
1137 char * boundary;
1138
1139 boundary = mailmime_content_param_get(content_type, "boundary");
1140
1141 if (boundary != NULL) {
1142 int len;
1143 char * new_boundary;
1144
1145 len = strlen(boundary);
1146 new_boundary = malloc(len + 1);
1147 if (new_boundary == NULL)
1148 return NULL;
1149
1150 if (boundary[0] == '"') {
1151 strncpy(new_boundary, boundary + 1, len - 2);
1152 new_boundary[len - 2] = 0;
1153 }
1154 else
1155 strcpy(new_boundary, boundary);
1156
1157 boundary = new_boundary;
1158 }
1159
1160 return boundary;
1161}
1162
1163static void remove_unparsed_mime_headers(struct mailimf_fields * fields)
1164{
1165 clistiter * cur;
1166
1167 cur = clist_begin(fields->fld_list);
1168 while (cur != NULL) {
1169 struct mailimf_field * field;
1170 int delete;
1171
1172 field = clist_content(cur);
1173
1174 switch (field->fld_type) {
1175 case MAILIMF_FIELD_OPTIONAL_FIELD:
1176 delete = 0;
1177 if (strncasecmp(field->fld_data.fld_optional_field->fld_name,
1178 "Content-", 8) == 0) {
1179 char * name;
1180
1181 name = field->fld_data.fld_optional_field->fld_name + 8;
1182 if ((strcasecmp(name, "Type") == 0)
1183 || (strcasecmp(name, "Transfer-Encoding") == 0)
1184 || (strcasecmp(name, "ID") == 0)
1185 || (strcasecmp(name, "Description") == 0)
1186 || (strcasecmp(name, "Disposition") == 0)
1187 || (strcasecmp(name, "Language") == 0)) {
1188 delete = 1;
1189 }
1190 }
1191 else if (strcasecmp(field->fld_data.fld_optional_field->fld_name,
1192 "MIME-Version") == 0) {
1193 delete = 1;
1194 }
1195
1196 if (delete) {
1197 cur = clist_delete(fields->fld_list, cur);
1198 mailimf_field_free(field);
1199 }
1200 else {
1201 cur = clist_next(cur);
1202 }
1203 break;
1204
1205 default:
1206 cur = clist_next(cur);
1207 }
1208 }
1209}
1210
1211static int mailmime_parse_with_default(const char * message, size_t length,
1212 size_t * index, int default_type,
1213 struct mailmime_content * content_type,
1214 struct mailmime_fields * mime_fields,
1215 struct mailmime ** result)
1216{
1217 size_t cur_token;
1218
1219 int body_type;
1220
1221 int encoding;
1222 struct mailmime_data * body;
1223 char * boundary;
1224 struct mailimf_fields * fields;
1225 clist * list;
1226 struct mailmime * msg_mime;
1227
1228 struct mailmime * mime;
1229
1230 int r;
1231 int res;
1232 struct mailmime_data * preamble;
1233 struct mailmime_data * epilogue;
1234
1235 /*
1236 note that when this function is called, content type is always detached,
1237 even if the function fails
1238 */
1239
1240 preamble = NULL;
1241 epilogue = NULL;
1242
1243 cur_token = * index;
1244
1245 /* get content type */
1246
1247 if (content_type == NULL) {
1248 if (mime_fields != NULL) {
1249 clistiter * cur;
1250
1251 for(cur = clist_begin(mime_fields->fld_list) ; cur != NULL ;
1252 cur = clist_next(cur)) {
1253 struct mailmime_field * field;
1254
1255 field = clist_content(cur);
1256 if (field->fld_type == MAILMIME_FIELD_TYPE) {
1257 content_type = field->fld_data.fld_content;
1258
1259 /* detach content type from list */
1260 field->fld_data.fld_content = NULL;
1261 clist_delete(mime_fields->fld_list, cur);
1262 mailmime_field_free(field);
1263 /*
1264 there may be a leak due to the detached content type
1265 in case the function fails
1266 */
1267 break;
1268 }
1269 }
1270 }
1271 }
1272
1273 /* set default type if no content type */
1274
1275 if (content_type == NULL) {
1276 /* content_type is detached, in any case, we will have to free it */
1277 if (default_type == MAILMIME_DEFAULT_TYPE_TEXT_PLAIN) {
1278 content_type = mailmime_get_content_text();
1279 if (content_type == NULL) {
1280 res = MAILIMF_ERROR_MEMORY;
1281 goto err;
1282 }
1283 }
1284 else /* message */ {
1285 body_type = MAILMIME_MESSAGE;
1286
1287 content_type = mailmime_get_content_message();
1288 if (content_type == NULL) {
1289 res = MAILIMF_ERROR_MEMORY;
1290 goto err;
1291 }
1292 }
1293 }
1294
1295 /* get the body type */
1296
1297 boundary = NULL; /* XXX - removes a gcc warning */
1298
1299 switch (content_type->ct_type->tp_type) {
1300 case MAILMIME_TYPE_COMPOSITE_TYPE:
1301 switch (content_type->ct_type->tp_data.tp_composite_type->ct_type) {
1302 case MAILMIME_COMPOSITE_TYPE_MULTIPART:
1303 boundary = mailmime_extract_boundary(content_type);
1304
1305 if (boundary == NULL)
1306 body_type = MAILMIME_SINGLE;
1307 else
1308 body_type = MAILMIME_MULTIPLE;
1309 break;
1310
1311 case MAILMIME_COMPOSITE_TYPE_MESSAGE:
1312
1313 if (strcasecmp(content_type->ct_subtype, "rfc822") == 0)
1314 body_type = MAILMIME_MESSAGE;
1315 else
1316 body_type = MAILMIME_SINGLE;
1317 break;
1318
1319 default:
1320 res = MAILIMF_ERROR_INVAL;
1321 goto free_content;
1322 }
1323 break;
1324
1325 default: /* MAILMIME_TYPE_DISCRETE_TYPE */
1326 body_type = MAILMIME_SINGLE;
1327 break;
1328 }
1329
1330 /* set body */
1331
1332 if (mime_fields != NULL)
1333 encoding = mailmime_transfer_encoding_get(mime_fields);
1334 else
1335 encoding = MAILMIME_MECHANISM_8BIT;
1336
1337 cur_token = * index;
1338 body = mailmime_data_new(MAILMIME_DATA_TEXT, encoding, 1,
1339 message + cur_token, length - cur_token,
1340 NULL);
1341 if (body == NULL) {
1342 res = MAILIMF_ERROR_MEMORY;
1343 goto free_content;
1344 }
1345
1346 /* in case of composite, parse the sub-part(s) */
1347
1348 list = NULL;
1349 msg_mime = NULL;
1350 fields = NULL;
1351
1352 switch (body_type) {
1353 case MAILMIME_MESSAGE:
1354 {
1355 struct mailmime_fields * submime_fields;
1356
1357 r = mailimf_envelope_and_optional_fields_parse(message, length,
1358 &cur_token, &fields);
1359 if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
1360 res = r;
1361 goto free_content;
1362 }
1363
1364 r = mailimf_crlf_parse(message, length, &cur_token);
1365 if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
1366 mailimf_fields_free(fields);
1367 res = r;
1368 goto free_content;
1369 }
1370
1371 submime_fields = NULL;
1372 r = mailmime_fields_parse(fields, &submime_fields);
1373 if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
1374 mailimf_fields_free(fields);
1375 res = r;
1376 goto free_content;
1377 }
1378
1379 remove_unparsed_mime_headers(fields);
1380
1381 r = mailmime_parse_with_default(message, length,
1382 &cur_token, MAILMIME_DEFAULT_TYPE_TEXT_PLAIN,
1383 NULL, submime_fields, &msg_mime);
1384 if (r == MAILIMF_NO_ERROR) {
1385 /* do nothing */
1386 }
1387 else if (r == MAILIMF_ERROR_PARSE) {
1388 mailmime_fields_free(mime_fields);
1389 msg_mime = NULL;
1390 }
1391 else {
1392 mailmime_fields_free(mime_fields);
1393 res = r;
1394 goto free_content;
1395 }
1396 }
1397
1398 break;
1399
1400 case MAILMIME_MULTIPLE:
1401 {
1402 int default_subtype;
1403
1404 default_subtype = MAILMIME_DEFAULT_TYPE_TEXT_PLAIN;
1405 if (content_type != NULL)
1406 if (strcasecmp(content_type->ct_subtype, "digest") == 0)
1407 default_subtype = MAILMIME_DEFAULT_TYPE_MESSAGE;
1408
1409 cur_token = * index;
1410 r = mailmime_multipart_body_parse(message, length,
1411 &cur_token, boundary,
1412 default_subtype,
1413 &list, &preamble, &epilogue);
1414 if (r == MAILIMF_NO_ERROR) {
1415 /* do nothing */
1416 }
1417 else if (r == MAILIMF_ERROR_PARSE) {
1418 list = clist_new();
1419 if (list == NULL) {
1420 res = MAILIMF_ERROR_MEMORY;
1421 goto free_content;
1422 }
1423 }
1424 else {
1425 res = r;
1426 goto free_content;
1427 }
1428
1429 free(boundary);
1430 }
1431 break;
1432
1433 default: /* MAILMIME_SINGLE */
1434 /* do nothing */
1435 break;
1436 }
1437
1438 mime = mailmime_new(body_type, message, length,
1439 mime_fields, content_type,
1440 body, preamble, /* preamble */
1441 epilogue, /* epilogue */
1442 list, fields, msg_mime);
1443 if (mime == NULL) {
1444 res = MAILIMF_ERROR_MEMORY;
1445 goto free;
1446 }
1447
1448 * result = mime;
1449 * index = length;
1450
1451 return MAILIMF_NO_ERROR;
1452
1453 free:
1454 if (epilogue != NULL)
1455 mailmime_data_free(epilogue);
1456 if (preamble != NULL)
1457 mailmime_data_free(preamble);
1458 if (msg_mime != NULL)
1459 mailmime_free(msg_mime);
1460 if (list != NULL) {
1461 clist_foreach(list, (clist_func) mailmime_free, NULL);
1462 clist_free(list);
1463 }
1464 free_content:
1465 mailmime_content_free(content_type);
1466 err:
1467 return res;
1468}
1469
1470static int mailmime_get_section_list(struct mailmime * mime,
1471 clistiter * list, struct mailmime ** result)
1472{
1473 uint32_t id;
1474 struct mailmime * data;
1475 struct mailmime * submime;
1476
1477 if (list == NULL) {
1478 * result = mime;
1479 return MAILIMF_NO_ERROR;
1480 }
1481
1482 id = * ((uint32_t *) clist_content(list));
1483
1484 data = NULL;
1485 switch (mime->mm_type) {
1486 case MAILMIME_SINGLE:
1487 return MAILIMF_ERROR_INVAL;
1488
1489 case MAILMIME_MULTIPLE:
1490 data = clist_nth_data(mime->mm_data.mm_multipart.mm_mp_list, id - 1);
1491 if (data == NULL)
1492 return MAILIMF_ERROR_INVAL;
1493
1494 if (clist_next(list) != NULL)
1495 return mailmime_get_section_list(data, clist_next(list), result);
1496 else {
1497 * result = data;
1498 return MAILIMF_NO_ERROR;
1499 }
1500
1501 case MAILMIME_MESSAGE:
1502 submime = mime->mm_data.mm_message.mm_msg_mime;
1503 switch (submime->mm_type) {
1504 case MAILMIME_MULTIPLE:
1505 data = clist_nth_data(submime->mm_data.mm_multipart.mm_mp_list, id - 1);
1506 if (data == NULL)
1507 return MAILIMF_ERROR_INVAL;
1508 return mailmime_get_section_list(data, clist_next(list), result);
1509
1510 default:
1511 if (id != 1)
1512 return MAILIMF_ERROR_INVAL;
1513
1514 data = submime;
1515 if (data == NULL)
1516 return MAILIMF_ERROR_INVAL;
1517
1518 return mailmime_get_section_list(data, clist_next(list), result);
1519 }
1520 break;
1521
1522 default:
1523 return MAILIMF_ERROR_INVAL;
1524 }
1525}
1526
1527int mailmime_get_section(struct mailmime * mime,
1528 struct mailmime_section * section,
1529 struct mailmime ** result)
1530{
1531 return mailmime_get_section_list(mime,
1532 clist_begin(section->sec_list), result);
1533}
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549/* ************************************************************************* */
1550/* MIME part decoding */
1551
1552static inline signed char get_base64_value(char ch)
1553{
1554 if ((ch >= 'A') && (ch <= 'Z'))
1555 return ch - 'A';
1556 if ((ch >= 'a') && (ch <= 'z'))
1557 return ch - 'a' + 26;
1558 if ((ch >= '0') && (ch <= '9'))
1559 return ch - '0' + 52;
1560 switch (ch) {
1561 case '+':
1562 return 62;
1563 case '/':
1564 return 63;
1565 case '=': /* base64 padding */
1566 return -1;
1567 default:
1568 return -1;
1569 }
1570}
1571
1572int mailmime_base64_body_parse(const char * message, size_t length,
1573 size_t * index, char ** result,
1574 size_t * result_len)
1575{
1576 size_t cur_token;
1577 size_t i;
1578 char chunk[4];
1579 int chunk_index;
1580 char out[3];
1581 MMAPString * mmapstr;
1582 int res;
1583 int r;
1584 size_t written;
1585
1586 cur_token = * index;
1587 chunk_index = 0;
1588 written = 0;
1589
1590 mmapstr = mmap_string_sized_new((length - cur_token) * 3 / 4);
1591 if (mmapstr == NULL) {
1592 res = MAILIMF_ERROR_MEMORY;
1593 goto err;
1594 }
1595
1596 i = 0;
1597 while (1) {
1598 signed char value;
1599
1600 value = -1;
1601 while (value == -1) {
1602
1603 if (cur_token >= length)
1604 break;
1605
1606 value = get_base64_value(message[cur_token]);
1607 cur_token ++;
1608 }
1609
1610 if (value == -1)
1611 break;
1612
1613 chunk[chunk_index] = value;
1614 chunk_index ++;
1615
1616 if (chunk_index == 4) {
1617 out[0] = (chunk[0] << 2) | (chunk[1] >> 4);
1618 out[1] = (chunk[1] << 4) | (chunk[2] >> 2);
1619 out[2] = (chunk[2] << 6) | (chunk[3]);
1620
1621 chunk[0] = 0;
1622 chunk[1] = 0;
1623 chunk[2] = 0;
1624 chunk[3] = 0;
1625
1626 chunk_index = 0;
1627
1628 if (mmap_string_append_len(mmapstr, out, 3) == NULL) {
1629 res = MAILIMF_ERROR_MEMORY;
1630 goto free;
1631 }
1632 written += 3;
1633 }
1634 }
1635
1636 if (chunk_index != 0) {
1637 size_t len;
1638
1639 len = 0;
1640 out[0] = (chunk[0] << 2) | (chunk[1] >> 4);
1641 len ++;
1642
1643 if (chunk_index >= 3) {
1644 out[1] = (chunk[1] << 4) | (chunk[2] >> 2);
1645 len ++;
1646 }
1647
1648 if (mmap_string_append_len(mmapstr, out, len) == NULL) {
1649 res = MAILIMF_ERROR_MEMORY;
1650 goto free;
1651 }
1652 written += len;
1653 }
1654
1655 r = mmap_string_ref(mmapstr);
1656 if (r < 0) {
1657 res = MAILIMF_ERROR_MEMORY;
1658 goto free;
1659 }
1660
1661 * index = cur_token;
1662 * result = mmapstr->str;
1663 * result_len = written;
1664
1665 return MAILIMF_NO_ERROR;
1666
1667 free:
1668 mmap_string_free(mmapstr);
1669 err:
1670 return res;
1671}
1672
1673
1674
1675static inline int hexa_to_char(char hexdigit)
1676{
1677 if ((hexdigit >= '0') && (hexdigit <= '9'))
1678 return hexdigit - '0';
1679 if ((hexdigit >= 'a') && (hexdigit <= 'f'))
1680 return hexdigit - 'a' + 10;
1681 if ((hexdigit >= 'A') && (hexdigit <= 'F'))
1682 return hexdigit - 'A' + 10;
1683 return 0;
1684}
1685
1686static inline char to_char(const char * hexa)
1687{
1688 return (hexa_to_char(hexa[0]) << 4) | hexa_to_char(hexa[1]);
1689}
1690
1691enum {
1692 STATE_NORMAL,
1693 STATE_CODED,
1694 STATE_OUT,
1695 STATE_CR,
1696};
1697
1698
1699static int write_decoded_qp(MMAPString * mmapstr,
1700 const char * start, size_t count)
1701{
1702 if (mmap_string_append_len(mmapstr, start, count) == NULL)
1703 return MAILIMF_ERROR_MEMORY;
1704
1705 return MAILIMF_NO_ERROR;
1706}
1707
1708
1709#define WRITE_MAX_QP 512
1710
1711int mailmime_quoted_printable_body_parse(const char * message, size_t length,
1712 size_t * index, char ** result,
1713 size_t * result_len, int in_header)
1714{
1715 size_t cur_token;
1716 int state;
1717 int r;
1718 char ch;
1719 size_t count;
1720 const char * start;
1721 MMAPString * mmapstr;
1722 int res;
1723 size_t written;
1724
1725 state = STATE_NORMAL;
1726 cur_token = * index;
1727
1728 count = 0;
1729 start = message + cur_token;
1730 written = 0;
1731
1732 mmapstr = mmap_string_sized_new(length - cur_token);
1733 if (mmapstr == NULL) {
1734 res = MAILIMF_ERROR_MEMORY;
1735 goto err;
1736 }
1737
1738#if 0
1739 if (length >= 1) {
1740 if (message[length - 1] == '\n') {
1741 length --;
1742 if (length >= 1)
1743 if (message[length - 1] == '\r') {
1744 length --;
1745 }
1746 }
1747 }
1748#endif
1749
1750 while (state != STATE_OUT) {
1751
1752 if (cur_token >= length) {
1753 state = STATE_OUT;
1754 break;
1755 }
1756
1757 switch (state) {
1758
1759 case STATE_CODED:
1760
1761 if (count > 0) {
1762 r = write_decoded_qp(mmapstr, start, count);
1763 if (r != MAILIMF_NO_ERROR) {
1764 res = r;
1765 goto free;
1766 }
1767 written += count;
1768 count = 0;
1769 }
1770
1771 switch (message[cur_token]) {
1772 case '=':
1773 if (cur_token + 1 >= length) {
1774 /* error but ignore it */
1775 state = STATE_NORMAL;
1776 start = message + cur_token;
1777 cur_token ++;
1778 count ++;
1779 break;
1780 }
1781
1782 switch (message[cur_token + 1]) {
1783
1784 case '\n':
1785 cur_token += 2;
1786
1787 start = message + cur_token;
1788
1789 state = STATE_NORMAL;
1790 break;
1791
1792 case '\r':
1793 if (cur_token + 2 >= length) {
1794 state = STATE_OUT;
1795 break;
1796 }
1797
1798 if (message[cur_token + 2] == '\n')
1799 cur_token += 3;
1800 else
1801 cur_token += 2;
1802
1803 start = message + cur_token;
1804
1805 state = STATE_NORMAL;
1806
1807 break;
1808
1809 default:
1810 if (cur_token + 2 >= length) {
1811 /* error but ignore it */
1812 cur_token ++;
1813
1814 start = message + cur_token;
1815
1816 count ++;
1817 state = STATE_NORMAL;
1818 break;
1819 }
1820
1821#if 0
1822 /* flush before writing additionnal information */
1823 r = write_decoded_qp(mmapstr, start, count);
1824 if (r != MAILIMF_NO_ERROR) {
1825 res = r;
1826 goto free;
1827 }
1828 written += count;
1829 count = 0;
1830#endif
1831
1832 ch = to_char(message + cur_token + 1);
1833
1834 if (mmap_string_append_c(mmapstr, ch) == NULL) {
1835 res = MAILIMF_ERROR_MEMORY;
1836 goto free;
1837 }
1838
1839 cur_token += 3;
1840 written ++;
1841
1842 start = message + cur_token;
1843
1844 state = STATE_NORMAL;
1845 break;
1846 }
1847 break;
1848 }
1849 break; /* end of STATE_ENCODED */
1850
1851 case STATE_NORMAL:
1852
1853 switch (message[cur_token]) {
1854
1855 case '=':
1856 state = STATE_CODED;
1857 break;
1858
1859 case '\n':
1860 /* flush before writing additionnal information */
1861 if (count > 0) {
1862 r = write_decoded_qp(mmapstr, start, count);
1863 if (r != MAILIMF_NO_ERROR) {
1864 res = r;
1865 goto free;
1866 }
1867 written += count;
1868
1869 count = 0;
1870 }
1871
1872 r = write_decoded_qp(mmapstr, "\r\n", 2);
1873 if (r != MAILIMF_NO_ERROR) {
1874 res = r;
1875 goto free;
1876 }
1877 written += 2;
1878 cur_token ++;
1879 start = message + cur_token;
1880 break;
1881
1882 case '\r':
1883 state = STATE_CR;
1884 cur_token ++;
1885 break;
1886
1887 case '_':
1888 if (in_header) {
1889 if (count > 0) {
1890 r = write_decoded_qp(mmapstr, start, count);
1891 if (r != MAILIMF_NO_ERROR) {
1892 res = r;
1893 goto free;
1894 }
1895 written += count;
1896 count = 0;
1897 }
1898
1899 if (mmap_string_append_c(mmapstr, ' ') == NULL) {
1900 res = MAILIMF_ERROR_MEMORY;
1901 goto free;
1902 }
1903
1904 written ++;
1905 cur_token ++;
1906 start = message + cur_token;
1907
1908 break;
1909 }
1910 /* WARINING : must be followed by switch default action */
1911
1912 default:
1913 if (count >= WRITE_MAX_QP) {
1914 r = write_decoded_qp(mmapstr, start, count);
1915 if (r != MAILIMF_NO_ERROR) {
1916 res = r;
1917 goto free;
1918 }
1919 written += count;
1920 count = 0;
1921 start = message + cur_token;
1922 }
1923
1924 count ++;
1925 cur_token ++;
1926 break;
1927 }
1928 break; /* end of STATE_NORMAL */
1929
1930 case STATE_CR:
1931 switch (message[cur_token]) {
1932
1933 case '\n':
1934 /* flush before writing additionnal information */
1935 if (count > 0) {
1936 r = write_decoded_qp(mmapstr, start, count);
1937 if (r != MAILIMF_NO_ERROR) {
1938 res = r;
1939 goto free;
1940 }
1941 written += count;
1942 count = 0;
1943 }
1944
1945 r = write_decoded_qp(mmapstr, "\r\n", 2);
1946 if (r != MAILIMF_NO_ERROR) {
1947 res = r;
1948 goto free;
1949 }
1950 written += 2;
1951 cur_token ++;
1952 start = message + cur_token;
1953 state = STATE_NORMAL;
1954 break;
1955
1956 default:
1957 /* flush before writing additionnal information */
1958 if (count > 0) {
1959 r = write_decoded_qp(mmapstr, start, count);
1960 if (r != MAILIMF_NO_ERROR) {
1961 res = r;
1962 goto free;
1963 }
1964 written += count;
1965 count = 0;
1966 }
1967
1968 start = message + cur_token;
1969
1970 r = write_decoded_qp(mmapstr, "\r\n", 2);
1971 if (r != MAILIMF_NO_ERROR) {
1972 res = r;
1973 goto free;
1974 }
1975 written += 2;
1976 state = STATE_NORMAL;
1977 }
1978 break; /* end of STATE_CR */
1979 }
1980 }
1981
1982 if (count > 0) {
1983 r = write_decoded_qp(mmapstr, start, count);
1984 if (r != MAILIMF_NO_ERROR) {
1985 res = r;
1986 goto free;
1987 }
1988 written += count;
1989 count = 0;
1990 }
1991
1992 r = mmap_string_ref(mmapstr);
1993 if (r < 0) {
1994 res = MAILIMF_ERROR_MEMORY;
1995 goto free;
1996 }
1997
1998 * index = cur_token;
1999 * result = mmapstr->str;
2000 * result_len = written;
2001
2002 return MAILIMF_NO_ERROR;
2003
2004 free:
2005 mmap_string_free(mmapstr);
2006 err:
2007 return res;
2008}
2009
2010int mailmime_binary_body_parse(const char * message, size_t length,
2011 size_t * index, char ** result,
2012 size_t * result_len)
2013{
2014 MMAPString * mmapstr;
2015 size_t cur_token;
2016 int r;
2017 int res;
2018
2019 cur_token = * index;
2020
2021 if (length >= 1) {
2022 if (message[length - 1] == '\n') {
2023 length --;
2024 if (length >= 1)
2025 if (message[length - 1] == '\r')
2026 length --;
2027 }
2028 }
2029
2030 mmapstr = mmap_string_new_len(message + cur_token, length - cur_token);
2031 if (mmapstr == NULL) {
2032 res = MAILIMF_ERROR_MEMORY;
2033 goto err;
2034 }
2035
2036 r = mmap_string_ref(mmapstr);
2037 if (r < 0) {
2038 res = MAILIMF_ERROR_MEMORY;
2039 goto free;
2040 }
2041
2042 * index = length;
2043 * result = mmapstr->str;
2044 * result_len = length - cur_token;
2045
2046 return MAILIMF_NO_ERROR;
2047
2048 free:
2049 mmap_string_free(mmapstr);
2050 err:
2051 return res;
2052}
2053
2054
2055int mailmime_part_parse(const char * message, size_t length,
2056 size_t * index,
2057 int encoding, char ** result, size_t * result_len)
2058{
2059 switch (encoding) {
2060 case MAILMIME_MECHANISM_BASE64:
2061 return mailmime_base64_body_parse(message, length, index,
2062 result, result_len);
2063
2064 case MAILMIME_MECHANISM_QUOTED_PRINTABLE:
2065 return mailmime_quoted_printable_body_parse(message, length, index,
2066 result, result_len, FALSE);
2067
2068 case MAILMIME_MECHANISM_7BIT:
2069 case MAILMIME_MECHANISM_8BIT:
2070 case MAILMIME_MECHANISM_BINARY:
2071 default:
2072 return mailmime_binary_body_parse(message, length, index,
2073 result, result_len);
2074 }
2075}
2076
2077int mailmime_get_section_id(struct mailmime * mime,
2078 struct mailmime_section ** result)
2079{
2080 clist * list;
2081 int res;
2082 struct mailmime_section * section_id;
2083 int r;
2084
2085 if (mime->mm_parent == NULL) {
2086 list = clist_new();
2087 if (list == NULL) {
2088 res = MAILIMF_ERROR_MEMORY;
2089 goto err;
2090 }
2091
2092 section_id = mailmime_section_new(list);
2093 if (section_id == NULL) {
2094 res = MAILIMF_ERROR_MEMORY;
2095 goto err;
2096 }
2097 }
2098 else {
2099 uint32_t id;
2100 uint32_t * p_id;
2101 clistiter * cur;
2102 struct mailmime * parent;
2103
2104 r = mailmime_get_section_id(mime->mm_parent, &section_id);
2105 if (r != MAILIMF_NO_ERROR) {
2106 res = r;
2107 goto err;
2108 }
2109
2110 parent = mime->mm_parent;
2111 switch (parent->mm_type) {
2112 case MAILMIME_MULTIPLE:
2113 id = 1;
2114 for(cur = clist_begin(parent->mm_data.mm_multipart.mm_mp_list) ;
2115 cur != NULL ; cur = clist_next(cur)) {
2116 if (clist_content(cur) == mime)
2117 break;
2118 id ++;
2119 }
2120
2121 p_id = malloc(sizeof(* p_id));
2122 if (p_id == NULL) {
2123 res = MAILIMF_ERROR_MEMORY;
2124 goto free;
2125 }
2126 * p_id = id;
2127
2128 r = clist_append(section_id->sec_list, p_id);
2129 if (r < 0) {
2130 free(p_id);
2131 res = MAILIMF_ERROR_MEMORY;
2132 goto free;
2133 }
2134 break;
2135
2136 case MAILMIME_MESSAGE:
2137 if ((mime->mm_type == MAILMIME_SINGLE) ||
2138 (mime->mm_type == MAILMIME_MESSAGE)) {
2139 p_id = malloc(sizeof(* p_id));
2140 if (p_id == NULL) {
2141 res = MAILIMF_ERROR_MEMORY;
2142 goto free;
2143 }
2144 * p_id = 1;
2145
2146 r = clist_append(section_id->sec_list, p_id);
2147 if (r < 0) {
2148 free(p_id);
2149 res = MAILIMF_ERROR_MEMORY;
2150 goto free;
2151 }
2152 }
2153 }
2154 }
2155
2156 * result = section_id;
2157
2158 return MAILIMF_NO_ERROR;
2159
2160 free:
2161 mailmime_section_free(section_id);
2162 err:
2163 return res;
2164}