summaryrefslogtreecommitdiffabout
path: root/libetpan/src/low-level/mime/mailmime_content.c
Unidiff
Diffstat (limited to 'libetpan/src/low-level/mime/mailmime_content.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/low-level/mime/mailmime_content.c2381
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
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 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
567static int
568mailmime_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
629static int mailmime_multipart_close_parse(const char * message, size_t length,
630 size_t * index);
631
632static int
633mailmime_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
680enum {
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
688static 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
777enum {
778 MULTIPART_NEXT_STATE_0,
779 MULTIPART_NEXT_STATE_1,
780 MULTIPART_NEXT_STATE_2
781};
782
783int 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
837static int
838mailmime_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
1279enum {
1280 MAILMIME_DEFAULT_TYPE_TEXT_PLAIN,
1281 MAILMIME_DEFAULT_TYPE_MESSAGE
1282};
1283
1284
1285int 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
1352char * 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
1380static 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
1428static 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
1687static 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
1744int 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
1769static 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
1789int 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
1892static 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
1903static inline char to_char(const char * hexa)
1904{
1905 return (hexa_to_char(hexa[0]) << 4) | hexa_to_char(hexa[1]);
1906}
1907
1908enum {
1909 STATE_NORMAL,
1910 STATE_CODED,
1911 STATE_OUT,
1912 STATE_CR,
1913};
1914
1915
1916static 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
1928int 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
2227int 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
2272int 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
2294int 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, &section_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}