summaryrefslogtreecommitdiffabout
path: root/libetpan/src/low-level/mime/mailmime.c
Unidiff
Diffstat (limited to 'libetpan/src/low-level/mime/mailmime.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/low-level/mime/mailmime.c1408
1 files changed, 1408 insertions, 0 deletions
diff --git a/libetpan/src/low-level/mime/mailmime.c b/libetpan/src/low-level/mime/mailmime.c
new file mode 100644
index 0000000..4bade55
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime.c
@@ -0,0 +1,1408 @@
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 "mailmime.h"
37
38/*
39 RFC 2045
40 RFC 2046
41 RFC 2047
42 RFC 2048
43 RFC 2049
44 RFC 2231
45 RFC 2387
46 RFC 2424
47 RFC 2557
48
49 RFC 2183 Content-Disposition
50
51 RFC 1766 Language
52 */
53
54#include <ctype.h>
55#include <stdlib.h>
56#include <string.h>
57
58#include "mailmime_types.h"
59#include "mailmime_disposition.h"
60#include "mailimf.h"
61
62#ifndef TRUE
63#define TRUE 1
64#endif
65
66#ifndef FALSE
67#define FALSE 0
68#endif
69
70static int mailmime_attribute_parse(const char * message, size_t length,
71 size_t * index,
72 char ** result);
73static int
74mailmime_composite_type_parse(const char * message, size_t length,
75 size_t * index,
76 struct mailmime_composite_type ** result);
77
78static int is_text(char ch);
79
80static int
81mailmime_discrete_type_parse(const char * message, size_t length,
82 size_t * index,
83 struct mailmime_discrete_type ** result);
84
85static int mailmime_mechanism_parse(const char * message, size_t length,
86 size_t * index,
87 struct mailmime_mechanism ** result);
88
89static int mailmime_subtype_parse(const char * message, size_t length,
90 size_t * index, char ** result);
91
92static int is_token(char ch);
93
94static int mailmime_token_parse(const char * message, size_t length,
95 size_t * index,
96 char ** token);
97
98static int is_tspecials(char ch);
99
100static int mailmime_type_parse(const char * message, size_t length,
101 size_t * index,
102 struct mailmime_type ** result);
103
104/*
105int mailmime_version_parse(const char * message, guint32 length,
106 guint32 * index,
107 guint32 * result);
108*/
109
110/*
111static gboolean mailmime_x_token_parse(gconst char * message, guint32 length,
112 guint32 * index,
113 gchar ** result);
114*/
115
116/* ********************************************************************** */
117
118/*
119x attribute := token
120 ; Matching of attributes
121 ; is ALWAYS case-insensitive.
122*/
123
124static int mailmime_attribute_parse(const char * message, size_t length,
125 size_t * index,
126 char ** result)
127{
128 return mailmime_token_parse(message, length, index, result);
129}
130
131/*
132x composite-type := "message" / "multipart" / extension-token
133*/
134
135static int
136mailmime_composite_type_parse(const char * message, size_t length,
137 size_t * index,
138 struct mailmime_composite_type ** result)
139{
140 char * extension_token;
141 int type;
142 struct mailmime_composite_type * ct;
143 size_t cur_token;
144 int r;
145 int res;
146
147 cur_token = * index;
148
149 extension_token = NULL;
150
151 type = MAILMIME_COMPOSITE_TYPE_ERROR; /* XXX - removes a gcc warning */
152
153 r = mailimf_token_case_insensitive_parse(message, length,
154 &cur_token, "message");
155 if (r == MAILIMF_NO_ERROR)
156 type = MAILMIME_COMPOSITE_TYPE_MESSAGE;
157
158 if (r == MAILIMF_ERROR_PARSE) {
159 r = mailimf_token_case_insensitive_parse(message, length,
160 &cur_token, "multipart");
161 if (r == MAILIMF_NO_ERROR)
162 type = MAILMIME_COMPOSITE_TYPE_MULTIPART;
163 }
164
165 if (r != MAILIMF_NO_ERROR) {
166 res = r;
167 goto err;
168 }
169
170 ct = mailmime_composite_type_new(type, extension_token);
171 if (ct == NULL) {
172 res = MAILIMF_ERROR_MEMORY;
173 goto free_extension;
174 }
175
176 * result = ct;
177 * index = cur_token;
178
179 return MAILIMF_NO_ERROR;
180
181 free_extension:
182 if (extension_token != NULL)
183 mailmime_extension_token_free(extension_token);
184 err:
185 return res;
186}
187
188/*
189x content := "Content-Type" ":" type "/" subtype
190 *(";" parameter)
191 ; Matching of media type and subtype
192 ; is ALWAYS case-insensitive.
193*/
194
195int mailmime_content_parse(const char * message, size_t length,
196 size_t * index,
197 struct mailmime_content ** result)
198{
199 size_t cur_token;
200 struct mailmime_type * type;
201 char * subtype;
202 clist * parameters_list;
203 struct mailmime_content * content;
204 int r;
205 int res;
206
207 cur_token = * index;
208
209 mailimf_cfws_parse(message, length, &cur_token);
210
211 r = mailmime_type_parse(message, length, &cur_token, &type);
212 if (r != MAILIMF_NO_ERROR) {
213 res = r;
214 goto err;
215 }
216
217 r = mailimf_unstrict_char_parse(message, length, &cur_token, '/');
218 switch (r) {
219 case MAILIMF_NO_ERROR:
220 r = mailimf_cfws_parse(message, length, &cur_token);
221 if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
222 res = r;
223 goto free_type;
224 }
225
226 r = mailmime_subtype_parse(message, length, &cur_token, &subtype);
227 if (r != MAILIMF_NO_ERROR) {
228 res = r;
229 goto free_type;
230 }
231 break;
232
233 case MAILIMF_ERROR_PARSE:
234 subtype = strdup("unknown");
235 break;
236
237 default:
238 res = r;
239 goto free_type;
240 }
241
242 parameters_list = clist_new();
243 if (parameters_list == NULL) {
244 res = MAILIMF_ERROR_MEMORY;
245 goto free_type;
246 }
247
248 while (1) {
249 size_t final_token;
250 struct mailmime_parameter * parameter;
251
252 final_token = cur_token;
253 r = mailimf_unstrict_char_parse(message, length, &cur_token, ';');
254 if (r != MAILIMF_NO_ERROR) {
255 cur_token = final_token;
256 break;
257 }
258
259 r = mailimf_cfws_parse(message, length, &cur_token);
260 if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
261 res = r;
262 goto free_type;
263 }
264
265 r = mailmime_parameter_parse(message, length, &cur_token, &parameter);
266 if (r == MAILIMF_NO_ERROR) {
267 /* do nothing */
268 }
269 else if (r == MAILIMF_ERROR_PARSE) {
270 cur_token = final_token;
271 break;
272 }
273 else {
274 res = r;
275 goto err;
276 }
277
278 r = clist_append(parameters_list, parameter);
279 if (r < 0) {
280 mailmime_parameter_free(parameter);
281 res = MAILIMF_ERROR_MEMORY;
282 goto free_parameters;
283 }
284 }
285
286 content = mailmime_content_new(type, subtype, parameters_list);
287 if (content == NULL) {
288 res = MAILIMF_ERROR_MEMORY;
289 goto free_parameters;
290 }
291
292 * result = content;
293 * index = cur_token;
294
295 return MAILIMF_NO_ERROR;
296
297 free_parameters:
298 clist_foreach(parameters_list, (clist_func) mailmime_parameter_free, NULL);
299 clist_free(parameters_list);
300
301 mailmime_subtype_free(subtype);
302 free_type:
303 mailmime_type_free(type);
304 err:
305 return res;
306}
307
308/*
309x description := "Content-Description" ":" *text
310*/
311
312static int is_text(char ch)
313{
314 unsigned char uch = (unsigned char) ch;
315
316 if (uch < 1)
317 return FALSE;
318
319 if ((uch == 10) || (uch == 13))
320 return FALSE;
321
322 return TRUE;
323}
324
325int mailmime_description_parse(const char * message, size_t length,
326 size_t * index,
327 char ** result)
328{
329 return mailimf_custom_string_parse(message, length,
330 index, result,
331 is_text);
332}
333
334/*
335x discrete-type := "text" / "image" / "audio" / "video" /
336 "application" / extension-token
337*/
338
339/* currently porting */
340
341static int
342mailmime_discrete_type_parse(const char * message, size_t length,
343 size_t * index,
344 struct mailmime_discrete_type ** result)
345{
346 char * extension;
347 int type;
348 struct mailmime_discrete_type * discrete_type;
349 size_t cur_token;
350 int r;
351 int res;
352
353 cur_token = * index;
354
355 extension = NULL;
356
357 type = MAILMIME_DISCRETE_TYPE_ERROR; /* XXX - removes a gcc warning */
358
359 r = mailimf_token_case_insensitive_parse(message, length,
360 &cur_token, "text");
361 if (r == MAILIMF_NO_ERROR)
362 type = MAILMIME_DISCRETE_TYPE_TEXT;
363
364 if (r == MAILIMF_ERROR_PARSE) {
365 r = mailimf_token_case_insensitive_parse(message, length,
366 &cur_token, "image");
367 if (r == MAILIMF_NO_ERROR)
368 type = MAILMIME_DISCRETE_TYPE_IMAGE;
369 }
370
371 if (r == MAILIMF_ERROR_PARSE) {
372 r = mailimf_token_case_insensitive_parse(message, length,
373 &cur_token, "audio");
374 if (r == MAILIMF_NO_ERROR)
375 type = MAILMIME_DISCRETE_TYPE_AUDIO;
376 }
377
378 if (r == MAILIMF_ERROR_PARSE) {
379 r = mailimf_token_case_insensitive_parse(message, length,
380 &cur_token, "video");
381 if (r == MAILIMF_NO_ERROR)
382 type = MAILMIME_DISCRETE_TYPE_VIDEO;
383 }
384
385 if (r == MAILIMF_ERROR_PARSE) {
386 r = mailimf_token_case_insensitive_parse(message, length,
387 &cur_token, "application");
388 if (r == MAILIMF_NO_ERROR)
389 type = MAILMIME_DISCRETE_TYPE_APPLICATION;
390 }
391
392 if (r == MAILIMF_ERROR_PARSE) {
393 r = mailmime_extension_token_parse(message, length,
394 &cur_token, &extension);
395 if (r == MAILIMF_NO_ERROR)
396 type = MAILMIME_DISCRETE_TYPE_EXTENSION;
397 }
398
399 if (r != MAILIMF_NO_ERROR) {
400 res = r;
401 goto err;
402 }
403
404 discrete_type = mailmime_discrete_type_new(type, extension);
405 if (discrete_type == NULL) {
406 res = MAILIMF_ERROR_MEMORY;
407 goto free;
408 }
409
410 * result = discrete_type;
411 * index = cur_token;
412
413 return MAILIMF_NO_ERROR;
414
415 free:
416 mailmime_extension_token_free(extension);
417 err:
418 return res;
419}
420
421/*
422x encoding := "Content-Transfer-Encoding" ":" mechanism
423*/
424
425int mailmime_encoding_parse(const char * message, size_t length,
426 size_t * index,
427 struct mailmime_mechanism ** result)
428{
429 return mailmime_mechanism_parse(message, length, index, result);
430}
431
432/*
433x entity-headers := [ content CRLF ]
434 [ encoding CRLF ]
435 [ id CRLF ]
436 [ description CRLF ]
437 *( MIME-extension-field CRLF )
438 */
439
440enum {
441 FIELD_STATE_START,
442 FIELD_STATE_T,
443 FIELD_STATE_D
444};
445
446static int guess_field_type(char * name)
447{
448 int state;
449
450 if (* name == 'M')
451 return MAILMIME_FIELD_VERSION;
452
453 if (strncasecmp(name, "Content-", 8) != 0)
454 return MAILMIME_FIELD_NONE;
455
456 name += 8;
457
458 state = FIELD_STATE_START;
459
460 while (1) {
461
462 switch (state) {
463
464 case FIELD_STATE_START:
465 switch ((char) toupper((unsigned char) * name)) {
466 case 'T':
467 state = FIELD_STATE_T;
468 break;
469 case 'I':
470 return MAILMIME_FIELD_ID;
471 case 'D':
472 state = FIELD_STATE_D;
473 break;
474 case 'L':
475 return MAILMIME_FIELD_LANGUAGE;
476 default:
477 return MAILMIME_FIELD_NONE;
478 }
479 break;
480
481 case FIELD_STATE_T:
482 switch ((char) toupper((unsigned char) * name)) {
483 case 'Y':
484 return MAILMIME_FIELD_TYPE;
485 case 'R':
486 return MAILMIME_FIELD_TRANSFER_ENCODING;
487 default:
488 return MAILMIME_FIELD_NONE;
489 }
490 break;
491
492 case FIELD_STATE_D:
493 switch ((char) toupper((unsigned char) * name)) {
494 case 'E':
495 return MAILMIME_FIELD_DESCRIPTION;
496 case 'I':
497 return MAILMIME_FIELD_DISPOSITION;
498 default:
499 return MAILMIME_FIELD_NONE;
500 }
501 break;
502 }
503 name ++;
504 }
505}
506
507int
508mailmime_field_parse(struct mailimf_optional_field * field,
509 struct mailmime_field ** result)
510{
511 char * name;
512 char * value;
513 int guessed_type;
514 size_t cur_token;
515 struct mailmime_content * content;
516 struct mailmime_mechanism * encoding;
517 char * id;
518 char * description;
519 uint32_t version;
520 struct mailmime_field * mime_field;
521 struct mailmime_language * language;
522 struct mailmime_disposition * disposition;
523 int res;
524 int r;
525
526 name = field->fld_name;
527 value = field->fld_value;
528 cur_token = 0;
529
530 content = NULL;
531 encoding = NULL;
532 id = NULL;
533 description = NULL;
534 version = 0;
535 disposition = NULL;
536 language = NULL;
537
538 guessed_type = guess_field_type(name);
539
540 switch (guessed_type) {
541 case MAILMIME_FIELD_TYPE:
542 if (strcasecmp(name, "Content-Type") != 0)
543 return MAILIMF_ERROR_PARSE;
544 r = mailmime_content_parse(value, strlen(value), &cur_token, &content);
545 if (r != MAILIMF_NO_ERROR)
546 return r;
547 break;
548
549 case MAILMIME_FIELD_TRANSFER_ENCODING:
550 if (strcasecmp(name, "Content-Transfer-Encoding") != 0)
551 return MAILIMF_ERROR_PARSE;
552 r = mailmime_encoding_parse(value, strlen(value), &cur_token, &encoding);
553 if (r != MAILIMF_NO_ERROR)
554 return r;
555 break;
556
557 case MAILMIME_FIELD_ID:
558 if (strcasecmp(name, "Content-ID") != 0)
559 return MAILIMF_ERROR_PARSE;
560 r = mailmime_id_parse(value, strlen(value), &cur_token, &id);
561 if (r != MAILIMF_NO_ERROR)
562 return r;
563 break;
564
565 case MAILMIME_FIELD_DESCRIPTION:
566 if (strcasecmp(name, "Content-Description") != 0)
567 return MAILIMF_ERROR_PARSE;
568 r = mailmime_description_parse(value, strlen(value),
569 &cur_token, &description);
570 if (r != MAILIMF_NO_ERROR)
571 return r;
572 break;
573
574 case MAILMIME_FIELD_VERSION:
575 if (strcasecmp(name, "MIME-Version") != 0)
576 return MAILIMF_ERROR_PARSE;
577 r = mailmime_version_parse(value, strlen(value), &cur_token, &version);
578 if (r != MAILIMF_NO_ERROR)
579 return r;
580 break;
581
582 case MAILMIME_FIELD_DISPOSITION:
583 if (strcasecmp(name, "Content-Disposition") != 0)
584 return MAILIMF_ERROR_PARSE;
585 r = mailmime_disposition_parse(value, strlen(value),
586 &cur_token, &disposition);
587 if (r != MAILIMF_NO_ERROR)
588 return r;
589 break;
590
591 case MAILMIME_FIELD_LANGUAGE:
592 if (strcasecmp(name, "Content-Language") != 0)
593 return MAILIMF_ERROR_PARSE;
594 r = mailmime_language_parse(value, strlen(value), &cur_token, &language);
595 if (r != MAILIMF_NO_ERROR)
596 return r;
597 break;
598
599 default:
600 return MAILIMF_ERROR_PARSE;
601 }
602
603 mime_field = mailmime_field_new(guessed_type, content, encoding,
604 id, description, version, disposition,
605 language);
606 if (mime_field == NULL) {
607 res = MAILIMF_ERROR_MEMORY;
608 goto free;
609 }
610
611 * result = mime_field;
612
613 return MAILIMF_NO_ERROR;
614
615 free:
616 if (content != NULL)
617 mailmime_content_free(content);
618 if (encoding != NULL)
619 mailmime_encoding_free(encoding);
620 if (id != NULL)
621 mailmime_id_free(id);
622 if (description != NULL)
623 mailmime_description_free(description);
624 return res;
625}
626
627/*
628x extension-token := ietf-token / x-token
629*/
630
631int
632mailmime_extension_token_parse(const char * message, size_t length,
633 size_t * index, char ** result)
634{
635 return mailmime_token_parse(message, length, index, result);
636}
637
638/*
639 hex-octet := "=" 2(DIGIT / "A" / "B" / "C" / "D" / "E" / "F")
640 ; Octet must be used for characters > 127, =,
641 ; SPACEs or TABs at the ends of lines, and is
642 ; recommended for any character not listed in
643 ; RFC 2049 as "mail-safe".
644*/
645
646/*
647x iana-token := <A publicly-defined extension token. Tokens
648 of this form must be registered with IANA
649 as specified in RFC 2048.>
650*/
651
652/*
653x ietf-token := <An extension token defined by a
654 standards-track RFC and registered
655 with IANA.>
656*/
657
658/*
659x id := "Content-ID" ":" msg-id
660*/
661
662int mailmime_id_parse(const char * message, size_t length,
663 size_t * index, char ** result)
664{
665 return mailimf_msg_id_parse(message, length, index, result);
666}
667
668/*
669x mechanism := "7bit" / "8bit" / "binary" /
670 "quoted-printable" / "base64" /
671 ietf-token / x-token
672*/
673
674static int mailmime_mechanism_parse(const char * message, size_t length,
675 size_t * index,
676 struct mailmime_mechanism ** result)
677{
678 char * token;
679 int type;
680 struct mailmime_mechanism * mechanism;
681 size_t cur_token;
682 int r;
683 int res;
684
685 cur_token = * index;
686
687 type = MAILMIME_MECHANISM_ERROR; /* XXX - removes a gcc warning */
688
689 token = NULL;
690 r = mailimf_token_case_insensitive_parse(message, length,
691 &cur_token, "7bit");
692 if (r == MAILIMF_NO_ERROR)
693 type = MAILMIME_MECHANISM_7BIT;
694
695 if (r == MAILIMF_ERROR_PARSE) {
696 r = mailimf_token_case_insensitive_parse(message, length,
697 &cur_token, "8bit");
698 if (r == MAILIMF_NO_ERROR)
699 type = MAILMIME_MECHANISM_8BIT;
700 }
701
702 if (r == MAILIMF_ERROR_PARSE) {
703 r = mailimf_token_case_insensitive_parse(message, length,
704 &cur_token, "binary");
705 if (r == MAILIMF_NO_ERROR)
706 type = MAILMIME_MECHANISM_BINARY;
707 }
708
709 if (r == MAILIMF_ERROR_PARSE) {
710 r = mailimf_token_case_insensitive_parse(message, length,
711 &cur_token, "quoted-printable");
712 if (r == MAILIMF_NO_ERROR)
713 type = MAILMIME_MECHANISM_QUOTED_PRINTABLE;
714 }
715
716 if (r == MAILIMF_ERROR_PARSE) {
717 r = mailimf_token_case_insensitive_parse(message, length,
718 &cur_token, "base64");
719 if (r == MAILIMF_NO_ERROR)
720 type = MAILMIME_MECHANISM_BASE64;
721 }
722
723 if (r == MAILIMF_ERROR_PARSE) {
724 r = mailmime_token_parse(message, length, &cur_token, &token);
725 if (r == MAILIMF_NO_ERROR)
726 type = MAILMIME_MECHANISM_TOKEN;
727 }
728
729 if (r != MAILIMF_NO_ERROR) {
730 res = r;
731 goto err;
732 }
733
734 mechanism = mailmime_mechanism_new(type, token);
735 if (mechanism == NULL) {
736 res = MAILIMF_ERROR_MEMORY;
737 goto free;
738 }
739
740 * result = mechanism;
741 * index = cur_token;
742
743 return MAILIMF_NO_ERROR;
744
745 free:
746 if (token != NULL)
747 mailmime_token_free(token);
748 err:
749 return res;
750}
751
752/*
753x MIME-extension-field := <Any RFC 822 header field which
754 begins with the string
755 "Content-">
756*/
757
758/*
759in headers
760
761x MIME-message-headers := entity-headers
762 fields
763 version CRLF
764 ; The ordering of the header
765 ; fields implied by this BNF
766 ; definition should be ignored.
767*/
768
769/*
770in message
771
772x MIME-part-headers := entity-headers
773 [fields]
774 ; Any field not beginning with
775 ; "content-" can have no defined
776 ; meaning and may be ignored.
777 ; The ordering of the header
778 ; fields implied by this BNF
779 ; definition should be ignored.
780*/
781
782#if 0
783int
784mailmime_unparsed_fields_parse(struct mailimf_unparsed_fields *
785 fields,
786 struct mailmime_fields **
787 result)
788{
789 clistiter * cur;
790 struct mailmime_fields * mime_fields;
791 clist * list;
792 int r;
793 int res;
794
795 list = clist_new();
796 if (list == NULL) {
797 res = MAILIMF_ERROR_MEMORY;
798 goto err;
799 }
800
801 if (fields->list == NULL) {
802 res = MAILIMF_ERROR_PARSE;
803 goto err;
804 }
805
806 for(cur = clist_begin(fields->list) ; cur != NULL ;
807 cur = clist_next(cur)) {
808 struct mailimf_optional_field * field = cur->data;
809 struct mailmime_field * mime_field;
810
811 r = mailmime_field_parse(field, &mime_field);
812 if (r == MAILIMF_NO_ERROR) {
813 r = clist_append(list, mime_field);
814 if (r < 0) {
815 mailmime_field_free(mime_field);
816 res = MAILIMF_ERROR_MEMORY;
817 goto free_list;
818 }
819 }
820 }
821
822 if (clist_begin(list) == NULL) {
823 res = MAILIMF_ERROR_PARSE;
824 goto free_list;
825 }
826
827 mime_fields = mailmime_fields_new(list);
828 if (mime_fields == NULL) {
829 res = MAILIMF_ERROR_MEMORY;
830 goto free_list;
831 }
832
833 * result = mime_fields;
834
835 return MAILIMF_NO_ERROR;
836
837 free_list:
838 clist_foreach(list, (clist_func) mailmime_field_free, NULL);
839 clist_free(list);
840 err:
841 return res;
842}
843#endif
844
845int
846mailmime_fields_parse(struct mailimf_fields *
847 fields,
848 struct mailmime_fields **
849 result)
850{
851 clistiter * cur;
852 struct mailmime_fields * mime_fields;
853 clist * list;
854 int r;
855 int res;
856
857 list = clist_new();
858 if (list == NULL) {
859 res = MAILIMF_ERROR_MEMORY;
860 goto err;
861 }
862
863 for(cur = clist_begin(fields->fld_list) ; cur != NULL ;
864 cur = clist_next(cur)) {
865 struct mailimf_field * field;
866 struct mailmime_field * mime_field;
867
868 field = clist_content(cur);
869
870 if (field->fld_type == MAILIMF_FIELD_OPTIONAL_FIELD) {
871 r = mailmime_field_parse(field->fld_data.fld_optional_field,
872 &mime_field);
873 if (r == MAILIMF_NO_ERROR) {
874 r = clist_append(list, mime_field);
875 if (r < 0) {
876 mailmime_field_free(mime_field);
877 res = MAILIMF_ERROR_MEMORY;
878 goto free_list;
879 }
880 }
881 else if (r == MAILIMF_ERROR_PARSE) {
882 /* do nothing */
883 }
884 else {
885 res = r;
886 goto free_list;
887 }
888 }
889 }
890
891 if (clist_begin(list) == NULL) {
892 res = MAILIMF_ERROR_PARSE;
893 goto free_list;
894 }
895
896 mime_fields = mailmime_fields_new(list);
897 if (mime_fields == NULL) {
898 res = MAILIMF_ERROR_MEMORY;
899 goto free_list;
900 }
901
902 * result = mime_fields;
903
904 return MAILIMF_NO_ERROR;
905
906 free_list:
907 clist_foreach(list, (clist_func) mailmime_field_free, NULL);
908 clist_free(list);
909 err:
910 return res;
911}
912
913/*
914x parameter := attribute "=" value
915*/
916
917int mailmime_parameter_parse(const char * message, size_t length,
918 size_t * index,
919 struct mailmime_parameter ** result)
920{
921 char * attribute;
922 char * value;
923 struct mailmime_parameter * parameter;
924 size_t cur_token;
925 int r;
926 int res;
927
928 cur_token = * index;
929
930 r = mailmime_attribute_parse(message, length, &cur_token, &attribute);
931 if (r != MAILIMF_NO_ERROR) {
932 res = r;
933 goto err;
934 }
935
936 r = mailimf_unstrict_char_parse(message, length, &cur_token, '=');
937 if (r != MAILIMF_NO_ERROR) {
938 res = r;
939 goto free_attr;
940 }
941
942 r = mailimf_cfws_parse(message, length, &cur_token);
943 if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
944 res = r;
945 goto free_attr;
946 }
947
948 r = mailmime_value_parse(message, length, &cur_token, &value);
949 if (r != MAILIMF_NO_ERROR) {
950 res = r;
951 goto free_attr;
952 }
953
954 parameter = mailmime_parameter_new(attribute, value);
955 if (parameter == NULL) {
956 res = MAILIMF_ERROR_MEMORY;
957 goto free_value;
958 }
959
960 * result = parameter;
961 * index = cur_token;
962
963 return MAILIMF_NO_ERROR;
964
965 free_value:
966 mailmime_value_free(value);
967 free_attr:
968 mailmime_attribute_free(attribute);
969 err:
970 return res;
971}
972
973/*
974 ptext := hex-octet / safe-char
975*/
976
977/*
978 qp-line := *(qp-segment transport-padding CRLF)
979 qp-part transport-padding
980*/
981
982/*
983 qp-part := qp-section
984 ; Maximum length of 76 characters
985*/
986
987/*
988 qp-section := [*(ptext / SPACE / TAB) ptext]
989*/
990
991/*
992 qp-segment := qp-section *(SPACE / TAB) "="
993 ; Maximum length of 76 characters
994*/
995
996/*
997 quoted-printable := qp-line *(CRLF qp-line)
998*/
999
1000/*
1001 safe-char := <any octet with decimal value of 33 through
1002 60 inclusive, and 62 through 126>
1003 ; Characters not listed as "mail-safe" in
1004 ; RFC 2049 are also not recommended.
1005*/
1006
1007/*
1008x subtype := extension-token / iana-token
1009*/
1010
1011static int mailmime_subtype_parse(const char * message, size_t length,
1012 size_t * index, char ** result)
1013{
1014 return mailmime_extension_token_parse(message, length, index, result);
1015}
1016
1017/*
1018x token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
1019 or tspecials>
1020*/
1021
1022static int is_token(char ch)
1023{
1024 unsigned char uch = (unsigned char) ch;
1025
1026 if (uch > 0x7F)
1027 return FALSE;
1028
1029 if (uch == ' ')
1030 return FALSE;
1031
1032 if (is_tspecials(ch))
1033 return FALSE;
1034
1035 return TRUE;
1036}
1037
1038
1039static int mailmime_token_parse(const char * message, size_t length,
1040 size_t * index,
1041 char ** token)
1042{
1043 return mailimf_custom_string_parse(message, length,
1044 index, token,
1045 is_token);
1046}
1047
1048/*
1049 transport-padding := *LWSP-char
1050 ; Composers MUST NOT generate
1051 ; non-zero length transport
1052 ; padding, but receivers MUST
1053 ; be able to handle padding
1054 ; added by message transports.
1055*/
1056
1057/*
1058enum {
1059 LWSP_1,
1060 LWSP_2,
1061 LWSP_3,
1062 LWSP_4,
1063 LWSP_OK
1064};
1065
1066gboolean mailmime_transport_padding_parse(gconst char * message, guint32 length,
1067 guint32 * index)
1068{
1069 guint32 cur_token;
1070 gint state;
1071 guint32 last_valid_pos;
1072
1073 cur_token = * index;
1074
1075 if (cur_token >= length)
1076 return FALSE;
1077
1078 state = LWSP_1;
1079
1080 while (state != LWSP_OUT) {
1081
1082 if (cur_token >= length)
1083 return FALSE;
1084
1085 switch (state) {
1086 case LWSP_1:
1087 last_valid_pos = cur_token;
1088
1089 switch (message[cur_token]) {
1090 case '\r':
1091 state = LWSP_2;
1092 break;
1093 case '\n':
1094 state = LWSP_3;
1095 break;
1096 case ' ':
1097 case '\t':
1098 state = LWSP_4;
1099 break;
1100 default:
1101 state = LWSP_OK;
1102 break;
1103 }
1104 case LWSP_2:
1105 switch (message[cur_token]) {
1106 case '\n':
1107 state = LWSP_3;
1108 break;
1109 default:
1110 state = LWSP_OUT;
1111 cur_token = last_valid_pos;
1112 break;
1113 }
1114 case LWSP_3:
1115 switch (message[cur_token]) {
1116 case ' ':
1117 case '\t':
1118 state = LWSP_1;
1119 break;
1120 default:
1121 state = LWSP_OUT;
1122 cur_token = last_valid_pos;
1123 break;
1124 }
1125
1126 cur_token ++;
1127 }
1128 }
1129
1130 * index = cur_token;
1131
1132 return TRUE;
1133}
1134*/
1135
1136/*
1137x tspecials := "(" / ")" / "<" / ">" / "@" /
1138 "," / ";" / ":" / "\" / <">
1139 "/" / "[" / "]" / "?" / "="
1140 ; Must be in quoted-string,
1141 ; to use within parameter values
1142*/
1143
1144static int is_tspecials(char ch)
1145{
1146 switch (ch) {
1147 case '(':
1148 case ')':
1149 case '<':
1150 case '>':
1151 case '@':
1152 case ',':
1153 case ';':
1154 case ':':
1155 case '\\':
1156 case '\"':
1157 case '/':
1158 case '[':
1159 case ']':
1160 case '?':
1161 case '=':
1162 return TRUE;
1163 default:
1164 return FALSE;
1165 }
1166}
1167
1168/*
1169x type := discrete-type / composite-type
1170*/
1171
1172static int mailmime_type_parse(const char * message, size_t length,
1173 size_t * index,
1174 struct mailmime_type ** result)
1175{
1176 struct mailmime_discrete_type * discrete_type;
1177 struct mailmime_composite_type * composite_type;
1178 size_t cur_token;
1179 struct mailmime_type * mime_type;
1180 int type;
1181 int res;
1182 int r;
1183
1184 cur_token = * index;
1185
1186 discrete_type = NULL;
1187 composite_type = NULL;
1188
1189 type = MAILMIME_TYPE_ERROR; /* XXX - removes a gcc warning */
1190
1191 r = mailmime_composite_type_parse(message, length, &cur_token,
1192 &composite_type);
1193 if (r == MAILIMF_NO_ERROR)
1194 type = MAILMIME_TYPE_COMPOSITE_TYPE;
1195
1196 if (r == MAILIMF_ERROR_PARSE) {
1197 r = mailmime_discrete_type_parse(message, length, &cur_token,
1198 &discrete_type);
1199 if (r == MAILIMF_NO_ERROR)
1200 type = MAILMIME_TYPE_DISCRETE_TYPE;
1201 }
1202
1203 if (r != MAILIMF_NO_ERROR) {
1204 res = r;
1205 goto err;
1206 }
1207
1208 mime_type = mailmime_type_new(type, discrete_type, composite_type);
1209 if (mime_type == NULL) {
1210 res = r;
1211 goto free;
1212 }
1213
1214 * result = mime_type;
1215 * index = cur_token;
1216
1217 return MAILIMF_NO_ERROR;
1218
1219 free:
1220 if (discrete_type != NULL)
1221 mailmime_discrete_type_free(discrete_type);
1222 if (composite_type != NULL)
1223 mailmime_composite_type_free(composite_type);
1224 err:
1225 return res;
1226}
1227
1228/*
1229x value := token / quoted-string
1230*/
1231
1232int mailmime_value_parse(const char * message, size_t length,
1233 size_t * index, char ** result)
1234{
1235 int r;
1236
1237 r = mailmime_token_parse(message, length, index, result);
1238
1239 if (r == MAILIMF_ERROR_PARSE)
1240 r = mailimf_quoted_string_parse(message, length, index, result);
1241
1242 if (r != MAILIMF_NO_ERROR)
1243 return r;
1244
1245 return MAILIMF_NO_ERROR;
1246}
1247
1248/*
1249x version := "MIME-Version" ":" 1*DIGIT "." 1*DIGIT
1250*/
1251
1252int mailmime_version_parse(const char * message, size_t length,
1253 size_t * index,
1254 uint32_t * result)
1255{
1256 size_t cur_token;
1257 uint32_t hi;
1258 uint32_t low;
1259 uint32_t version;
1260 int r;
1261
1262 cur_token = * index;
1263
1264 r = mailimf_number_parse(message, length, &cur_token, &hi);
1265 if (r != MAILIMF_NO_ERROR)
1266 return r;
1267
1268 r = mailimf_unstrict_char_parse(message, length, &cur_token, '.');
1269 if (r != MAILIMF_NO_ERROR)
1270 return r;
1271
1272 r = mailimf_cfws_parse(message, length, &cur_token);
1273 if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
1274 return r;
1275
1276 r = mailimf_number_parse(message, length, &cur_token, &low);
1277 if (r != MAILIMF_NO_ERROR)
1278 return r;
1279
1280 version = (hi << 16) + low;
1281
1282 * result = version;
1283 * index = cur_token;
1284
1285 return MAILIMF_NO_ERROR;
1286}
1287
1288/*
1289x x-token := <The two characters "X-" or "x-" followed, with
1290 no intervening white space, by any token>
1291*/
1292
1293/*
1294static gboolean mailmime_x_token_parse(gconst char * message, guint32 length,
1295 guint32 * index,
1296 gchar ** result)
1297{
1298 guint32 cur_token;
1299 gchar * token;
1300 gchar * x_token;
1301 gboolean min_x;
1302
1303 cur_token = * index;
1304
1305 if (!mailimf_char_parse(message, length, &cur_token, 'x')) {
1306 if (!mailimf_char_parse(message, length, &cur_token, 'X'))
1307 return FALSE;
1308 min_x = FALSE;
1309 }
1310 else
1311 min_x = TRUE;
1312
1313 if (!mailimf_char_parse(message, length, &cur_token, '-'))
1314 return FALSE;
1315
1316 if (!mailmime_token_parse(message, length, &cur_token, &token))
1317 return FALSE;
1318
1319 if (min_x)
1320 x_token = g_strconcat("x-", token, NULL);
1321 else
1322 x_token = g_strconcat("X-", token, NULL);
1323 mailmime_token_free(token);
1324
1325 if (x_token == NULL)
1326 return FALSE;
1327
1328 * result = x_token;
1329 * index = cur_token;
1330
1331 return TRUE;
1332}
1333*/
1334
1335
1336int mailmime_language_parse(const char * message, size_t length,
1337 size_t * index,
1338 struct mailmime_language ** result)
1339{
1340 size_t cur_token;
1341 int r;
1342 int res;
1343 clist * list;
1344 int first;
1345 struct mailmime_language * language;
1346
1347 cur_token = * index;
1348
1349 list = clist_new();
1350 if (list == NULL) {
1351 res = MAILIMF_ERROR_MEMORY;
1352 goto err;
1353 }
1354
1355 first = TRUE;
1356
1357 while (1) {
1358 char * atom;
1359
1360 r = mailimf_unstrict_char_parse(message, length, &cur_token, ',');
1361 if (r == MAILIMF_NO_ERROR) {
1362 /* do nothing */
1363 }
1364 else if (r == MAILIMF_ERROR_PARSE) {
1365 break;
1366 }
1367 else {
1368 res = r;
1369 goto err;
1370 }
1371
1372 r = mailimf_atom_parse(message, length, &cur_token, &atom);
1373 if (r == MAILIMF_NO_ERROR) {
1374 /* do nothing */
1375 }
1376 else if (r == MAILIMF_ERROR_PARSE) {
1377 break;
1378 }
1379 else {
1380 res = r;
1381 goto err;
1382 }
1383
1384 r = clist_append(list, atom);
1385 if (r < 0) {
1386 mailimf_atom_free(atom);
1387 res = MAILIMF_ERROR_MEMORY;
1388 goto free;
1389 }
1390 }
1391
1392 language = mailmime_language_new(list);
1393 if (language == NULL) {
1394 res = MAILIMF_ERROR_MEMORY;
1395 goto free;
1396 }
1397
1398 * result = language;
1399 * index = cur_token;
1400
1401 return MAILIMF_NO_ERROR;
1402
1403 free:
1404 clist_foreach(list, (clist_func) mailimf_atom_free, NULL);
1405 clist_free(list);
1406 err:
1407 return res;
1408}