1 /* -*- Mode: C -*-
2 ======================================================================
3 FILE: sspm.c Parse Mime
4 CREATOR: eric 25 June 2000
5
6 $Id: sspm.c,v 1.13 2008-01-28 22:34:38 artcancro Exp $
7 $Locker: $
8
9 The contents of this file are subject to the Mozilla Public License
10 Version 1.0 (the "License"); you may not use this file except in
11 compliance with the License. You may obtain a copy of the License at
12 http://www.mozilla.org/MPL/
13
14 Software distributed under the License is distributed on an "AS IS"
15 basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
16 the License for the specific language governing rights and
17 limitations under the License.
18
19
20 This program is free software; you can redistribute it and/or modify
21 it under the terms of either:
22
23 The LGPL as published by the Free Software Foundation, version
24 2.1, available at: http://www.fsf.org/copyleft/lesser.html
25
26 Or:
27
28 The Mozilla Public License Version 1.0. You may obtain a copy of
29 the License at http://www.mozilla.org/MPL/
30
31 The Initial Developer of the Original Code is Eric Busboom
32
33 (C) COPYRIGHT 2000, Eric Busboom <eric@softwarestudio.org>
34 http://www.softwarestudio.org
35 ======================================================================*/
36
37 #include <stdio.h>
38 #include <string.h>
39 #include "sspm.h"
40 #include <assert.h>
41 #include <ctype.h> /* for tolower */
42 #include <stdlib.h> /* for malloc, free */
43 #include <string.h> /* for strcasecmp */
44
45 #ifdef DMALLOC
46 #include "dmalloc.h"
47 #endif
48
49 #ifdef WIN32
50 #if defined(_MSC_VER) && (_MSC_VER < 1900)
51 #define snprintf _snprintf
52 #endif
53 #define strcasecmp stricmp
54 #endif
55
56 #define TMP_BUF_SIZE 1024
57
58
59 enum mime_state {
60 UNKNOWN_STATE,
61 IN_HEADER,
62 END_OF_HEADER,
63 IN_BODY,
64 OPENING_PART,
65 END_OF_PART,
66 TERMINAL_END_OF_PART,
67 END_OF_INPUT
68 };
69
70 struct mime_impl{
71 struct sspm_part *parts;
72 size_t max_parts;
73 int part_no;
74 int level;
75 const struct sspm_action_map *actions;
76 char* (*get_string)(char *s, size_t size, void* data);
77 void* get_string_data;
78 char temp[TMP_BUF_SIZE];
79 enum mime_state state;
80 };
81
82 void sspm_free_header(struct sspm_header *header);
83 void* sspm_make_multipart_part(struct mime_impl *impl,struct sspm_header *header);
84 void sspm_read_header(struct mime_impl *impl,struct sspm_header *header);
85
sspm_strdup(const char * str)86 char* sspm_strdup(const char* str){
87
88 char* s;
89
90 s = strdup(str);
91
92 return s;
93 }
94
95
96 static struct major_content_type_map
97 {
98 enum sspm_major_type type;
99 const char* str;
100
101 } major_content_type_map[] =
102 {
103 {SSPM_MULTIPART_MAJOR_TYPE,"multipart" },
104 {SSPM_TEXT_MAJOR_TYPE,"text" },
105 {SSPM_TEXT_MAJOR_TYPE,"text" },
106 {SSPM_IMAGE_MAJOR_TYPE,"image" },
107 {SSPM_AUDIO_MAJOR_TYPE,"audio" },
108 {SSPM_VIDEO_MAJOR_TYPE,"video" },
109 {SSPM_APPLICATION_MAJOR_TYPE,"application" },
110 {SSPM_MULTIPART_MAJOR_TYPE,"multipart" },
111 {SSPM_MESSAGE_MAJOR_TYPE,"message" },
112 {SSPM_UNKNOWN_MAJOR_TYPE,"" },
113 };
114
115 static struct minor_content_type_map
116 {
117 enum sspm_minor_type type;
118 const char* str;
119
120 } minor_content_type_map[] =
121 {
122 {SSPM_ANY_MINOR_TYPE,"*" },
123 {SSPM_PLAIN_MINOR_TYPE,"plain" },
124 {SSPM_RFC822_MINOR_TYPE,"rfc822" },
125 {SSPM_DIGEST_MINOR_TYPE,"digest" },
126 {SSPM_CALENDAR_MINOR_TYPE,"calendar" },
127 {SSPM_MIXED_MINOR_TYPE,"mixed" },
128 {SSPM_RELATED_MINOR_TYPE,"related" },
129 {SSPM_ALTERNATIVE_MINOR_TYPE,"alternative" },
130 {SSPM_PARALLEL_MINOR_TYPE, "parallel" },
131 {SSPM_UNKNOWN_MINOR_TYPE,"" }
132 };
133
134
135
136 struct encoding_map {
137 enum sspm_encoding encoding;
138 const char* str;
139 } sspm_encoding_map[] =
140 {
141 {SSPM_NO_ENCODING,""},
142 {SSPM_QUOTED_PRINTABLE_ENCODING,"quoted-printable"},
143 {SSPM_8BIT_ENCODING,"8bit"},
144 {SSPM_7BIT_ENCODING,"7bit"},
145 {SSPM_BINARY_ENCODING,"binary"},
146 {SSPM_BASE64_ENCODING,"base64"},
147 {SSPM_UNKNOWN_ENCODING,""}
148
149 };
150
151
sspm_get_parameter(const char * line,const char * parameter)152 char* sspm_get_parameter(const char* line, const char* parameter)
153 {
154 char *p,*s,*q;
155 static char name[1024];
156
157 /* Find where the parameter name is in the line */
158 p = strstr(line,parameter);
159
160 if( p == 0){
161 return 0;
162 }
163
164 /* skip over the parameter name, the '=' and any blank spaces */
165
166 p+=strlen(parameter);
167
168 while(*p==' ' || *p == '='){
169 p++;
170 }
171
172 /*now find the next semicolon*/
173
174 s = strchr(p,';');
175
176 /* Strip of leading quote */
177 q = strchr(p,'\"');
178
179 if(q !=0){
180 p = q+1;
181 }
182
183 if(s != 0){
184 strncpy(name,p,(size_t)s-(size_t)p);
185 } else {
186 strncpy(name,p,sizeof(name)-1);
187 name[sizeof(name)-1]='\0';
188 }
189
190 /* Strip off trailing quote, if it exists */
191
192 q = strrchr(name,'\"');
193
194 if (q != 0){
195 *q='\0';
196 }
197
198 return name;
199 }
200
sspm_property_name(const char * line)201 char* sspm_property_name(const char* line)
202 {
203 static char name[1024];
204 char *c = strchr(line,':');
205
206 if(c != 0){
207 strncpy(name,line,(size_t)c-(size_t)line);
208 name[(size_t)c-(size_t)line] = '\0';
209 return name;
210 } else {
211 return 0;
212 }
213 }
214
sspm_value(char * line)215 char* sspm_value(char* line)
216 {
217 static char value[1024];
218
219 char *c,*s, *p;
220
221 /* Find the first colon and the next semicolon */
222
223 value[0] = 0;
224 c = strchr(line,':');
225 if (!c)
226 return value;
227 s = strchr(c,';');
228
229 /* Skip the colon */
230 c++;
231
232 if (s == 0){
233 s = c+strlen(line);
234 }
235
236 for(p=value; c != s; c++){
237 if(*c!=' ' && *c!='\n'){
238 *(p++) = *c;
239 }
240 }
241
242 *p='\0';
243
244 return value;
245
246 }
247
248 static const char *mime_headers[] = {
249 "Content-Type",
250 "Content-Transfer-Encoding",
251 "Content-Disposition",
252 "Content-Id",
253 "Mime-Version",
254 0
255 };
256
257
sspm_default_new_part(void)258 void* sspm_default_new_part(void)
259 {
260 return 0;
261 }
sspm_default_add_line(void * part,struct sspm_header * header,const char * line,size_t size)262 void sspm_default_add_line(void *part, struct sspm_header *header,
263 const char* line, size_t size)
264 {
265 (void)part;
266 (void)header;
267 (void)line;
268 (void)size;
269 }
270
sspm_default_end_part(void * part)271 void* sspm_default_end_part(void* part)
272 {
273 (void)part;
274 return 0;
275 }
276
sspm_default_free_part(void * part)277 void sspm_default_free_part(void *part)
278 {
279 (void)part;
280 }
281
282
283
284 struct sspm_action_map sspm_action_map[] =
285 {
286 {SSPM_UNKNOWN_MAJOR_TYPE,SSPM_UNKNOWN_MINOR_TYPE,sspm_default_new_part,sspm_default_add_line,sspm_default_end_part,sspm_default_free_part},
287 };
288
sspm_is_mime_header(char * line)289 int sspm_is_mime_header(char *line)
290 {
291 char *name = sspm_property_name(line);
292 int i;
293
294 if(name == 0){
295 return 0;
296 }
297
298 for(i = 0; mime_headers[i] != 0; i++){
299 if(strcasecmp(name, mime_headers[i]) == 0)
300 return 1;
301 }
302
303 return 0;
304 }
305
sspm_is_mail_header(char * line)306 int sspm_is_mail_header(char* line)
307 {
308 char *name = sspm_property_name(line);
309
310 if (name != 0){
311 return 1;
312 }
313
314 return 0;
315
316 }
317
sspm_is_blank(char * line)318 int sspm_is_blank(char* line)
319 {
320 char *p;
321 char c =0;
322
323 for(p=line; *p!=0; p++){
324 if( ! (*p == ' '|| *p == '\t' || *p=='\n') ){
325 c++;
326 }
327 }
328
329 if (c==0){
330 return 1;
331 }
332
333 return 0;
334
335 }
336
sspm_is_continuation_line(char * line)337 int sspm_is_continuation_line(char* line)
338 {
339 if (line[0] == ' '|| line[0] == '\t' ) {
340 return 1;
341 }
342
343 return 0;
344 }
345
sspm_is_mime_boundary(char * line)346 int sspm_is_mime_boundary(char *line)
347 {
348 if( line[0] == '-' && line[1] == '-') {
349 return 1;
350 }
351
352 return 0;
353 }
354
sspm_is_mime_terminating_boundary(char * line)355 int sspm_is_mime_terminating_boundary(char *line)
356 {
357
358
359 if (sspm_is_mime_boundary(line) &&
360 strstr(line,"--\n")){
361 return 1;
362 }
363
364 return 0;
365 }
366
367 enum line_type {
368 EMPTY,
369 BLANK,
370 MIME_HEADER,
371 MAIL_HEADER,
372 HEADER_CONTINUATION,
373 BOUNDARY,
374 TERMINATING_BOUNDARY,
375 UNKNOWN_TYPE
376 };
377
378
get_line_type(char * line)379 static enum line_type get_line_type(char* line){
380
381 if (line == 0){
382 return EMPTY;
383 } else if(sspm_is_blank(line)){
384 return BLANK;
385 } else if (sspm_is_mime_header(line)){
386 return MIME_HEADER;
387 } else if (sspm_is_mail_header(line)){
388 return MAIL_HEADER;
389 } else if (sspm_is_continuation_line(line)){
390 return HEADER_CONTINUATION;
391 } else if (sspm_is_mime_terminating_boundary(line)){
392 return TERMINATING_BOUNDARY;
393 } else if (sspm_is_mime_boundary(line)) {
394 return BOUNDARY;
395 } else {
396 return UNKNOWN_TYPE;
397 }
398
399
400 }
401
402
get_action(struct mime_impl * impl,enum sspm_major_type major,enum sspm_minor_type minor)403 static struct sspm_action_map get_action(struct mime_impl *impl,
404 enum sspm_major_type major,
405 enum sspm_minor_type minor)
406 {
407 int i;
408
409 /* Read caller suppled action map */
410
411 if (impl->actions != 0){
412 for(i=0; impl->actions[i].major != SSPM_UNKNOWN_MAJOR_TYPE; i++){
413 if((major == impl->actions[i].major &&
414 minor == impl->actions[i].minor) ||
415 (major == impl->actions[i].major &&
416 minor == SSPM_ANY_MINOR_TYPE)){
417 return impl->actions[i];
418 }
419 }
420 }
421
422 /* Else, read default action map */
423
424 for(i=0; sspm_action_map[i].major != SSPM_UNKNOWN_MAJOR_TYPE; i++){
425 if((major == sspm_action_map[i].major &&
426 minor == sspm_action_map[i].minor) ||
427 (major == sspm_action_map[i].major &&
428 minor == SSPM_ANY_MINOR_TYPE)){
429 break;
430 }
431 }
432
433 return sspm_action_map[i];
434 }
435
436
sspm_lowercase(char * str)437 char* sspm_lowercase(char* str)
438 {
439 char* p = 0;
440 char* new;
441
442 if(str ==0){
443 return 0;
444 }
445 new = sspm_strdup(str);
446 for(p = new; *p!=0; p++){
447 *p = tolower(*p);
448 }
449
450 return new;
451 }
452
sspm_find_major_content_type(char * type)453 enum sspm_major_type sspm_find_major_content_type(char* type)
454 {
455 int i;
456
457 char* ltype = sspm_lowercase(type);
458
459 for (i=0; major_content_type_map[i].type != SSPM_UNKNOWN_MAJOR_TYPE; i++){
460 if(strncmp(ltype, major_content_type_map[i].str,
461 strlen(major_content_type_map[i].str))==0){
462 free(ltype);
463 return major_content_type_map[i].type;
464 }
465 }
466 free(ltype);
467 return major_content_type_map[i].type; /* Should return SSPM_UNKNOWN_MINOR_TYPE */
468 }
469
sspm_find_minor_content_type(char * type)470 enum sspm_minor_type sspm_find_minor_content_type(char* type)
471 {
472 int i;
473 char* ltype = sspm_lowercase(type);
474
475 char *p = strchr(ltype,'/');
476
477 if (p==0){
478 free(ltype);
479 return SSPM_UNKNOWN_MINOR_TYPE;
480 }
481
482 p++; /* Skip the '/' */
483
484 for (i=0; minor_content_type_map[i].type != SSPM_UNKNOWN_MINOR_TYPE; i++){
485 if(strncmp(p, minor_content_type_map[i].str,
486 strlen(minor_content_type_map[i].str))==0){
487 free(ltype);
488 return minor_content_type_map[i].type;
489 }
490 }
491
492 free(ltype);
493 return minor_content_type_map[i].type; /* Should return SSPM_UNKNOWN_MINOR_TYPE */
494 }
495
sspm_major_type_string(enum sspm_major_type type)496 const char* sspm_major_type_string(enum sspm_major_type type)
497 {
498 int i;
499
500 for (i=0; major_content_type_map[i].type != SSPM_UNKNOWN_MAJOR_TYPE;
501 i++){
502
503 if(type == major_content_type_map[i].type){
504 return major_content_type_map[i].str;
505 }
506 }
507
508 return major_content_type_map[i].str; /* Should return SSPM_UNKNOWN_MINOR_TYPE */
509 }
510
sspm_minor_type_string(enum sspm_minor_type type)511 const char* sspm_minor_type_string(enum sspm_minor_type type)
512 {
513 int i;
514 for (i=0; minor_content_type_map[i].type != SSPM_UNKNOWN_MINOR_TYPE;
515 i++){
516 if(type == minor_content_type_map[i].type){
517 return minor_content_type_map[i].str;
518 }
519 }
520
521 return minor_content_type_map[i].str; /* Should return SSPM_UNKNOWN_MINOR_TYPE */
522 }
523
524
sspm_encoding_string(enum sspm_encoding type)525 const char* sspm_encoding_string(enum sspm_encoding type)
526 {
527 int i;
528 for (i=0; sspm_encoding_map[i].encoding != SSPM_UNKNOWN_ENCODING;
529 i++){
530 if(type == sspm_encoding_map[i].encoding){
531 return sspm_encoding_map[i].str;
532 }
533 }
534
535 return sspm_encoding_map[i].str; /* Should return SSPM_UNKNOWN_MINOR_TYPE */
536 }
537
538 /* Interpret a header line and add its data to the header
539 structure. */
sspm_build_header(struct sspm_header * header,char * line)540 void sspm_build_header(struct sspm_header *header, char* line)
541 {
542 char *prop;
543 char *val;
544
545 val = sspm_strdup(sspm_value(line));
546 prop = sspm_strdup(sspm_property_name(line));
547
548 if(strcasecmp(prop,"Content-Type") == 0){
549
550 /* Create a new mime_header, fill in content-type
551 and possibly boundary */
552
553 char* boundary= sspm_get_parameter(line,"boundary");
554
555 header->def = 0;
556 header->major = sspm_find_major_content_type(val);
557 header->minor = sspm_find_minor_content_type(val);
558
559 if(header->minor == SSPM_UNKNOWN_MINOR_TYPE){
560 char *p = strchr(val,'/');
561
562 if (p != 0){
563 p++; /* Skip the '/' */
564
565 header->minor_text = sspm_strdup(p);
566 } else {
567 /* Error, malformed content type */
568 header->minor_text = sspm_strdup("unknown");
569 }
570 }
571 if (boundary != 0){
572 header->boundary = sspm_strdup(boundary);
573 }
574
575 } else if(strcasecmp(prop,"Content-Transfer-Encoding")==0){
576 char* encoding = sspm_value(line);
577 char* lencoding = sspm_lowercase(encoding);
578
579 if(strcasecmp(lencoding,"base64")==0){
580 header->encoding = SSPM_BASE64_ENCODING;
581 } else if(strcasecmp(lencoding,"quoted-printable")==0){
582 header->encoding = SSPM_QUOTED_PRINTABLE_ENCODING;
583 } else if(strcasecmp(lencoding,"binary")==0){
584 header->encoding = SSPM_BINARY_ENCODING;
585 } else if(strcasecmp(lencoding,"7bit")==0){
586 header->encoding = SSPM_7BIT_ENCODING;
587 } else if(strcasecmp(lencoding,"8bit")==0){
588 header->encoding = SSPM_8BIT_ENCODING;
589 } else {
590 header->encoding = SSPM_UNKNOWN_ENCODING;
591 }
592
593
594 free(lencoding);
595
596 header->def = 0;
597
598 } else if(strcasecmp(prop,"Content-Id")==0){
599 char* cid = sspm_value(line);
600 header->content_id = sspm_strdup(cid);
601 header->def = 0;
602
603 }
604 free(val);
605 free(prop);
606 }
607
sspm_get_next_line(struct mime_impl * impl)608 char* sspm_get_next_line(struct mime_impl *impl)
609 {
610 char* s;
611 s = impl->get_string(impl->temp,TMP_BUF_SIZE,impl->get_string_data);
612
613 if(s == 0){
614 impl->state = END_OF_INPUT;
615 }
616 return s;
617 }
618
619
sspm_store_part(struct mime_impl * impl,struct sspm_header header,int level,void * part,size_t size)620 void sspm_store_part(struct mime_impl *impl, struct sspm_header header,
621 int level, void *part, size_t size)
622 {
623
624 impl->parts[impl->part_no].header = header;
625 impl->parts[impl->part_no].level = level;
626 impl->parts[impl->part_no].data = part;
627 impl->parts[impl->part_no].data_size = size;
628 impl->part_no++;
629 }
630
sspm_set_error(struct sspm_header * header,enum sspm_error error,char * message)631 void sspm_set_error(struct sspm_header* header, enum sspm_error error,
632 char* message)
633 {
634 header->error = error;
635
636 if(header->error_text!=0){
637 free(header->error_text);
638 }
639
640 header->def = 0;
641
642 if(message != 0){
643 header->error_text = sspm_strdup(message);
644 } else {
645 header->error_text = 0;
646 }
647
648 }
649
sspm_make_part(struct mime_impl * impl,struct sspm_header * header,struct sspm_header * parent_header,void ** end_part,size_t * size)650 void* sspm_make_part(struct mime_impl *impl,
651 struct sspm_header *header,
652 struct sspm_header *parent_header,
653 void **end_part,
654 size_t *size)
655 {
656
657 /* For a single part type, read to the boundary, if there is a
658 boundary. Otherwise, read until the end of input. This routine
659 assumes that the caller has read the header and has left the input
660 at the first blank line */
661
662 char *line;
663 void *part;
664 int end = 0;
665
666 struct sspm_action_map action = get_action(
667 impl,
668 header->major,
669 header->minor);
670
671 *size = 0;
672 part =action.new_part();
673
674 impl->state = IN_BODY;
675
676 while(end == 0 && (line = sspm_get_next_line(impl)) != 0){
677
678 if(sspm_is_mime_boundary(line)){
679
680 /* If there is a boundary, then this must be a multipart
681 part, so there must be a parent_header. */
682 if(parent_header == 0){
683 char* boundary;
684 end = 1;
685 *end_part = 0;
686
687 sspm_set_error(header,SSPM_UNEXPECTED_BOUNDARY_ERROR,line);
688
689 /* Read until the paired terminating boundary */
690 if((boundary = (char*)malloc(strlen(line)+5)) == 0){
691 fprintf(stderr,"Out of memory");
692 abort();
693 }
694 strcpy(boundary,line);
695 strcat(boundary,"--");
696 while((line = sspm_get_next_line(impl)) != 0){
697 /*printf("Error: %s\n",line);*/
698 if(strcmp(boundary,line)==0){
699 break;
700 }
701 }
702 free(boundary);
703
704 break;
705 }
706
707 if(strcmp((line+2),parent_header->boundary) == 0) {
708 *end_part = action.end_part(part);
709
710 if(sspm_is_mime_boundary(line)){
711 impl->state = END_OF_PART;
712 } else if ( sspm_is_mime_terminating_boundary(line)){
713 impl->state = TERMINAL_END_OF_PART;
714 }
715 end = 1;
716 } else {
717 /* Error, this is not the correct terminating boundary*/
718
719 /* read and discard until we get the right boundary. */
720 char* boundary;
721 char msg[256];
722
723 snprintf(msg,256,
724 "Expected: %s--. Got: %s",
725 parent_header->boundary,line);
726
727 sspm_set_error(parent_header,
728 SSPM_WRONG_BOUNDARY_ERROR,msg);
729
730 /* Read until the paired terminating boundary */
731 if((boundary = (char*)malloc(strlen(line)+5)) == 0){
732 fprintf(stderr,"Out of memory");
733 abort();
734 }
735 strcpy(boundary,line);
736 strcat(boundary,"--");
737 while((line = sspm_get_next_line(impl)) != 0){
738 if(strcmp(boundary,line)==0){
739 break;
740 }
741 }
742 free(boundary);
743
744 }
745 } else {
746 char* data=0;
747 char* rtrn=0;
748 *size = strlen(line);
749
750 data = (char*)malloc(*size+2);
751 assert(data != 0);
752 if (header->encoding == SSPM_BASE64_ENCODING){
753 rtrn = decode_base64(data,line,size);
754 } else if(header->encoding == SSPM_QUOTED_PRINTABLE_ENCODING){
755 rtrn = decode_quoted_printable(data,line,size);
756 }
757
758 if(rtrn == 0){
759 strcpy(data,line);
760 }
761
762 /* add a end-of-string after the data, just in case binary
763 data from decode64 gets passed to a tring handling
764 routine in add_line */
765 data[*size+1]='\0';
766
767 action.add_line(part,header,data,*size);
768
769 free(data);
770 }
771 }
772
773 if (end == 0){
774 /* End the part if the input is exhausted */
775 *end_part = action.end_part(part);
776 }
777
778 return end_part;
779 }
780
781
sspm_make_multipart_subpart(struct mime_impl * impl,struct sspm_header * parent_header)782 void* sspm_make_multipart_subpart(struct mime_impl *impl,
783 struct sspm_header *parent_header)
784 {
785 struct sspm_header header;
786 char *line;
787 void* part;
788 size_t size;
789
790 if(parent_header->boundary == 0){
791 /* Error. Multipart headers must have a boundary*/
792
793 sspm_set_error(parent_header,SSPM_NO_BOUNDARY_ERROR,0);
794 /* read all of the reamining lines */
795 while((line = sspm_get_next_line(impl)) != 0){
796 }
797
798 return 0;
799 }
800
801
802 /* Step 1: Read the opening boundary */
803
804 if(get_line_type(impl->temp) != BOUNDARY){
805 while((line=sspm_get_next_line(impl)) != 0 ){
806 if(sspm_is_mime_boundary(line)){
807
808 assert(parent_header != 0);
809
810 /* Check if it is the right boundary */
811 if(!sspm_is_mime_terminating_boundary(line) &&
812 strcmp((line+2),parent_header->boundary)
813 == 0){
814 /* The +2 in strncmp skips over the leading "--" */
815
816 break;
817 } else {
818 /* Got the wrong boundary, so read and discard
819 until we get the right boundary. */
820 char* boundary;
821 char msg[256];
822
823 snprintf(msg,256,
824 "Expected: %s. Got: %s",
825 parent_header->boundary,line);
826
827 sspm_set_error(parent_header,
828 SSPM_WRONG_BOUNDARY_ERROR,msg);
829
830 /* Read until the paired terminating boundary */
831 if((boundary = (char*)malloc(strlen(line)+5)) == 0){
832 fprintf(stderr,"Out of memory");
833 abort();
834 }
835 strcpy(boundary,line);
836 strcat(boundary,"--");
837 while((line = sspm_get_next_line(impl)) != 0){
838 if(strcmp(boundary,line)==0){
839 break;
840 }
841 }
842 free(boundary);
843
844 return 0;
845 }
846 }
847 }
848 }
849
850 /* Step 2: Get the part header */
851 sspm_read_header(impl,&header);
852
853 /* If the header is still listed as default, there was probably an
854 error */
855 if(header.def == 1 && header.error != SSPM_NO_ERROR){
856 sspm_set_error(&header,SSPM_NO_HEADER_ERROR,0);
857 return 0;
858 }
859
860 if(header.error!= SSPM_NO_ERROR){
861 sspm_store_part(impl,header,impl->level,0,0);
862 return 0;
863 }
864
865 /* Step 3: read the body */
866
867 if(header.major == SSPM_MULTIPART_MAJOR_TYPE){
868 struct sspm_header *child_header;
869 child_header = &(impl->parts[impl->part_no].header);
870
871 /* Store the multipart part */
872 sspm_store_part(impl,header,impl->level,0,0);
873
874 /* now get all of the sub-parts */
875 part = sspm_make_multipart_part(impl,child_header);
876
877 if(get_line_type(impl->temp) != TERMINATING_BOUNDARY){
878
879 sspm_set_error(child_header,SSPM_NO_BOUNDARY_ERROR,impl->temp);
880 return 0;
881 }
882
883 sspm_get_next_line(impl); /* Step past the terminating boundary */
884
885 } else {
886 sspm_make_part(impl, &header,parent_header,&part,&size);
887
888 memset(&(impl->parts[impl->part_no]), 0, sizeof(struct sspm_part));
889
890 sspm_store_part(impl,header,impl->level,part,size);
891
892 }
893
894 return part;
895 }
896
sspm_make_multipart_part(struct mime_impl * impl,struct sspm_header * header)897 void* sspm_make_multipart_part(struct mime_impl *impl,struct sspm_header *header)
898 {
899 void *part=0;
900
901 /* Now descend a level into each of the children of this part */
902 impl->level++;
903
904 /* Now we are working on the CHILD */
905 memset(&(impl->parts[impl->part_no]), 0, sizeof(struct sspm_part));
906
907 do{
908 part = sspm_make_multipart_subpart(impl,header);
909
910 if (part==0){
911 /* Clean up the part in progress */
912 impl->parts[impl->part_no].header.major
913 = SSPM_NO_MAJOR_TYPE;
914 impl->parts[impl->part_no].header.minor
915 = SSPM_NO_MINOR_TYPE;
916
917 }
918
919
920 } while (get_line_type(impl->temp) != TERMINATING_BOUNDARY &&
921 impl->state != END_OF_INPUT);
922
923 impl->level--;
924
925 return 0;
926 }
927
928
sspm_read_header(struct mime_impl * impl,struct sspm_header * header)929 void sspm_read_header(struct mime_impl *impl,struct sspm_header *header)
930 {
931 #define BUF_SIZE 1024
932 #define MAX_HEADER_LINES 25
933
934 char *buf;
935 char header_lines[MAX_HEADER_LINES][BUF_SIZE]; /* HACK, hard limits TODO*/
936 int current_line = -1;
937 int end = 0;
938
939 memset(header_lines,0,sizeof(header_lines));
940 memset(header,0,sizeof(struct sspm_header));
941
942 /* Set up default header */
943 header->def = 1;
944 header->major = SSPM_TEXT_MAJOR_TYPE;
945 header->minor = SSPM_PLAIN_MINOR_TYPE;
946 header->error = SSPM_NO_ERROR;
947 header->error_text = 0;
948
949 /* Read all of the lines into memory */
950 while(current_line<(MAX_HEADER_LINES-2) &&
951 (end==0) &&
952 ((buf=sspm_get_next_line(impl)) != 0)){
953
954 enum line_type line_type = get_line_type(buf);
955
956 switch(line_type){
957 case BLANK: {
958 end = 1;
959 impl->state = END_OF_HEADER;
960 break;
961 }
962
963 case MAIL_HEADER:
964 case MIME_HEADER: {
965 impl->state = IN_HEADER;
966 current_line++;
967
968 assert(strlen(buf) < BUF_SIZE);
969
970 strncpy(header_lines[current_line],buf,BUF_SIZE);
971 header_lines[current_line][BUF_SIZE-1] = '\0';
972
973 break;
974 }
975
976 case HEADER_CONTINUATION: {
977 char* last_line, *end;
978 char *buf_start;
979
980 if(current_line < 0){
981 /* This is not really a continuation line, since
982 we have not see any header line yet */
983 sspm_set_error(header,SSPM_MALFORMED_HEADER_ERROR,buf);
984 return;
985 }
986
987 last_line = header_lines[current_line];
988 end = (char*) ( (size_t)strlen(last_line)+
989 (size_t)last_line);
990
991 impl->state = IN_HEADER;
992
993
994 /* skip over the spaces in buf start, and remove the new
995 line at the end of the lat line */
996 if (last_line[strlen(last_line)-1] == '\n'){
997 last_line[strlen(last_line)-1] = '\0';
998 }
999 buf_start = buf;
1000 while(*buf_start == ' ' ||*buf_start == '\t' ){
1001 buf_start++;
1002 }
1003
1004 assert( strlen(buf_start) + strlen(last_line) < BUF_SIZE);
1005
1006 strncat(last_line,buf_start, BUF_SIZE-strlen(last_line)-1);
1007
1008 break;
1009 }
1010
1011 default: {
1012 sspm_set_error(header,SSPM_MALFORMED_HEADER_ERROR,buf);
1013 return;
1014 }
1015 }
1016 }
1017
1018
1019 for(current_line = 0;
1020 current_line < MAX_HEADER_LINES && header_lines[current_line][0] != 0;
1021 current_line++){
1022
1023 sspm_build_header(header,header_lines[current_line]);
1024 }
1025
1026
1027 }
1028
1029 /* Root routine for parsing mime entries*/
sspm_parse_mime(struct sspm_part * parts,size_t max_parts,const struct sspm_action_map * actions,char * (* get_string)(char * s,size_t size,void * data),void * get_string_data,struct sspm_header * first_header)1030 int sspm_parse_mime(struct sspm_part *parts,
1031 size_t max_parts,
1032 const struct sspm_action_map *actions,
1033 char* (*get_string)(char *s, size_t size, void* data),
1034 void *get_string_data,
1035 struct sspm_header *first_header
1036 )
1037 {
1038 struct mime_impl impl;
1039 struct sspm_header header;
1040 void *part;
1041 int i;
1042 (void)first_header;
1043
1044 /* Initialize all of the data */
1045 memset(&impl,0,sizeof(struct mime_impl));
1046 memset(&header,0,sizeof(struct sspm_header));
1047
1048 for(i = 0; i<(int)max_parts; i++){
1049 parts[i].header.major = SSPM_NO_MAJOR_TYPE;
1050 parts[i].header.minor = SSPM_NO_MINOR_TYPE;
1051 }
1052
1053 impl.parts = parts;
1054 impl.max_parts = max_parts;
1055 impl.part_no = 0;
1056 impl.actions = actions;
1057 impl.get_string = get_string;
1058 impl.get_string_data = get_string_data;
1059
1060 /* Read the header of the message. This will be the email header,
1061 unless first_header is specified. But ( HACK) that var is not
1062 currently being used */
1063 sspm_read_header(&impl,&header);
1064
1065 if(header.major == SSPM_MULTIPART_MAJOR_TYPE){
1066 struct sspm_header *child_header;
1067 child_header = &(impl.parts[impl.part_no].header);
1068
1069 sspm_store_part(&impl,header,impl.level,0,0);
1070
1071 part = sspm_make_multipart_part(&impl,child_header);
1072
1073 } else {
1074 void *part;
1075 size_t size;
1076 sspm_make_part(&impl, &header, 0,&part,&size);
1077
1078 memset(&(impl.parts[impl.part_no]), 0, sizeof(struct sspm_part));
1079
1080 sspm_store_part(&impl,header,impl.level,part,size);
1081 }
1082
1083 return 0;
1084 }
1085
sspm_free_parts(struct sspm_part * parts,size_t max_parts)1086 void sspm_free_parts(struct sspm_part *parts, size_t max_parts)
1087 {
1088 int i;
1089
1090 for(i = 0; i<(int)max_parts && parts[i].header.major != SSPM_NO_MAJOR_TYPE;
1091 i++){
1092 sspm_free_header(&(parts[i].header));
1093 }
1094 }
1095
sspm_free_header(struct sspm_header * header)1096 void sspm_free_header(struct sspm_header *header)
1097 {
1098 if(header->boundary!=0){
1099 free(header->boundary);
1100 }
1101 if(header->minor_text!=0){
1102 free(header->minor_text);
1103 }
1104 if(header->charset!=0){
1105 free(header->charset);
1106 }
1107 if(header->filename!=0){
1108 free(header->filename);
1109 }
1110 if(header->content_id!=0){
1111 free(header->content_id);
1112 }
1113 if(header->error_text!=0){
1114 free(header->error_text);
1115 }
1116 }
1117
1118 /***********************************************************************
1119 The remaining code is beased on code from the mimelite distribution,
1120 which has the following notice:
1121
1122 | Authorship:
1123 | Copyright (c) 1994 Gisle Hannemyr.
1124 | Permission is granted to hack, make and distribute copies of this
1125 | program as long as this copyright notice is not removed.
1126 | Flames, bug reports, comments and improvements to:
1127 | snail: Gisle Hannemyr, Brageveien 3A, 0452 Oslo, Norway
1128 | email: Inet: gisle@oslonett.no
1129
1130 The code is heavily modified by Eric Busboom.
1131
1132 ***********************************************************************/
1133
decode_quoted_printable(char * dest,char * src,size_t * size)1134 char *decode_quoted_printable(char *dest,
1135 char *src,
1136 size_t *size)
1137 {
1138 int cc;
1139 size_t i=0;
1140
1141 while (*src != 0 && i < *size) {
1142 if (*src == '=') {
1143
1144 src++;
1145 if (!*src) {
1146 break;
1147 }
1148
1149 /* remove soft line breaks*/
1150 if ((*src == '\n') || (*src == '\r')){
1151 src++;
1152 if ((*src == '\n') || (*src == '\r')){
1153 src++;
1154 }
1155 continue;
1156 }
1157
1158 cc = isdigit(*src) ? (*src - '0') : (*src - 55);
1159 cc *= 0x10;
1160 src++;
1161 if (!*src) {
1162 break;
1163 }
1164 cc += isdigit(*src) ? (*src - '0') : (*src - 55);
1165
1166 *dest = cc;
1167
1168 } else {
1169 *dest = *src;
1170 }
1171
1172 dest++;
1173 src++;
1174 i++;
1175 }
1176
1177 *dest = '\0';
1178
1179 *size = i;
1180 return(dest);
1181 }
1182
decode_base64(char * dest,char * src,size_t * size)1183 char *decode_base64(char *dest,
1184 char *src,
1185 size_t *size)
1186 {
1187 int cc = 0;
1188 char buf[4] = {0,0,0,0};
1189 int p = 0;
1190 int valid_data = 0;
1191 size_t size_out=0;
1192
1193 while (*src && p<(int)*size && (cc!= -1)) {
1194
1195 /* convert a character into the Base64 alphabet */
1196 cc = *src++;
1197
1198 if ((cc >= 'A') && (cc <= 'Z')) cc = cc - 'A';
1199 else if ((cc >= 'a') && (cc <= 'z')) cc = cc - 'a' + 26;
1200 else if ((cc >= '0') && (cc <= '9')) cc = cc - '0' + 52;
1201 else if (cc == '/') cc = 63;
1202 else if (cc == '+') cc = 62;
1203 else cc = -1;
1204
1205 assert(cc<64);
1206
1207 /* If we've reached the end, fill the remaining slots in
1208 the bucket and do a final conversion */
1209 if(cc== -1){
1210 if(valid_data == 0){
1211 return 0;
1212 }
1213
1214 while(p%4!=3){
1215 p++;
1216 buf[p%4] = 0;
1217 }
1218 } else {
1219 buf[p%4] = cc;
1220 size_out++;
1221 valid_data = 1;
1222 }
1223
1224
1225 /* When we have 4 base64 letters, convert them into three
1226 bytes */
1227 if (p%4 == 3) {
1228 *dest++ =(buf[0]<< 2)|((buf[1] & 0x30) >> 4);
1229 *dest++ =((buf[1] & 0x0F) << 4)|((buf[2] & 0x3C) >> 2);
1230 *dest++ =((buf[2] & 0x03) << 6)|(buf[3] & 0x3F);
1231
1232 memset(buf,0,4);
1233 }
1234
1235 p++;
1236
1237 }
1238 /* Calculate the size of the converted data*/
1239 *size = ((int)(size_out/4))*3;
1240 if(size_out%4 == 2) *size+=1;
1241 if(size_out%4 == 3) *size+=2;
1242
1243 return(dest);
1244 }
1245
1246
1247 /***********************************************************************
1248
1249 Routines to output MIME
1250
1251 **********************************************************************/
1252
1253
1254 struct sspm_buffer {
1255 char* buffer;
1256 char* pos;
1257 size_t buf_size;
1258 int line_pos;
1259 };
1260
1261 void sspm_append_string(struct sspm_buffer* buf, const char* string);
1262 void sspm_write_part(struct sspm_buffer *buf,struct sspm_part *part, int *part_num);
1263
sspm_append_hex(struct sspm_buffer * buf,char ch)1264 void sspm_append_hex(struct sspm_buffer* buf, char ch)
1265 {
1266 char tmp[4];
1267
1268 snprintf(tmp,sizeof(tmp),"=%02X",ch);
1269
1270 sspm_append_string(buf,tmp);
1271 }
1272
1273 /* a copy of icalmemory_append_char */
sspm_append_char(struct sspm_buffer * buf,char ch)1274 void sspm_append_char(struct sspm_buffer* buf, char ch)
1275 {
1276 char *new_buf;
1277 char *new_pos;
1278
1279 size_t data_length, final_length;
1280
1281 data_length = (size_t)buf->pos - (size_t)buf->buffer;
1282
1283 final_length = data_length + 2;
1284
1285 if ( final_length > (size_t) buf->buf_size ) {
1286
1287 buf->buf_size = (buf->buf_size) * 2 + final_length +1;
1288
1289 new_buf = realloc(buf->buffer,buf->buf_size);
1290
1291 new_pos = (void*)((size_t)new_buf + data_length);
1292
1293 buf->pos = new_pos;
1294 buf->buffer = new_buf;
1295 }
1296
1297 *(buf->pos) = ch;
1298 buf->pos += 1;
1299 *(buf->pos) = 0;
1300 }
1301 /* A copy of icalmemory_append_string */
sspm_append_string(struct sspm_buffer * buf,const char * string)1302 void sspm_append_string(struct sspm_buffer* buf, const char* string)
1303 {
1304 char *new_buf;
1305 char *new_pos;
1306
1307 size_t data_length, final_length, string_length;
1308
1309 string_length = strlen(string);
1310 data_length = (size_t)buf->pos - (size_t)buf->buffer;
1311 final_length = data_length + string_length;
1312
1313 if ( final_length >= (size_t) buf->buf_size) {
1314
1315
1316 buf->buf_size = (buf->buf_size) * 2 + final_length;
1317
1318 new_buf = realloc(buf->buffer,buf->buf_size);
1319
1320 new_pos = (void*)((size_t)new_buf + data_length);
1321
1322 buf->pos = new_pos;
1323 buf->buffer = new_buf;
1324 }
1325
1326 strcpy(buf->pos, string);
1327
1328 buf->pos += string_length;
1329 }
1330
1331
1332
sspm_is_printable(char c)1333 static int sspm_is_printable(char c)
1334 {
1335 return (c >= 33) && (c <= 126) && (c != '=');
1336
1337 }
1338
1339
sspm_encode_quoted_printable(struct sspm_buffer * buf,char * data)1340 void sspm_encode_quoted_printable(struct sspm_buffer *buf, char* data)
1341 {
1342 char *p;
1343 int lpos = 0;
1344
1345 for(p = data; *p != 0; p++){
1346
1347 if(sspm_is_printable(*p)){
1348 /* plain characters can represent themselves */
1349 /* RFC2045 Rule #2 */
1350 sspm_append_char(buf,*p);
1351 lpos++;
1352 } else if ( *p == '\t' || *p == ' ' ) {
1353
1354 /* For tabs and spaces, only encode if they appear at the
1355 end of the line */
1356 /* RFC2045 Rule #3 */
1357
1358 char n = *(p+1);
1359
1360 if( n == '\n' || n == '\r'){
1361 sspm_append_hex(buf,*p);
1362 lpos += 3;
1363 } else {
1364 sspm_append_char(buf,*p);
1365 lpos++;
1366 }
1367
1368 } else if( *p == '\n' || *p == '\r'){
1369 sspm_append_char(buf,*p);
1370
1371 lpos=0;
1372
1373 } else {
1374 /* All others need to be encoded */
1375 sspm_append_hex(buf,*p);
1376 lpos+=3;
1377 }
1378
1379
1380 /* Add line breaks */
1381 if (lpos > 72){
1382 lpos = 0;
1383 sspm_append_string(buf,"=\n");
1384 }
1385 }
1386 }
1387
1388 static char BaseTable[64] = {
1389 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
1390 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
1391 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
1392 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
1393 };
1394
sspm_write_base64(struct sspm_buffer * buf,char * inbuf,int size)1395 void sspm_write_base64(struct sspm_buffer *buf, char* inbuf,int size )
1396 {
1397
1398 char outbuf[4];
1399 int i;
1400
1401 outbuf[0] = outbuf[1] = outbuf[2] = outbuf[3] = 65;
1402
1403 switch(size){
1404
1405 case 4:
1406 outbuf[3] = inbuf[2] & 0x3F;
1407
1408 case 3:
1409 outbuf[2] = ((inbuf[1] & 0x0F) << 2) | ((inbuf[2] & 0xC0) >> 6);
1410
1411 case 2:
1412 outbuf[0] = (inbuf[0] & 0xFC) >> 2;
1413 outbuf[1] = ((inbuf[0] & 0x03) << 4) | ((inbuf[1] & 0xF0) >> 4);
1414 break;
1415
1416 default:
1417 assert(0);
1418 }
1419
1420 for(i = 0; i < 4; i++){
1421
1422 if(outbuf[i] == 65){
1423 sspm_append_char(buf,'=');
1424 } else {
1425 sspm_append_char(buf,BaseTable[(int)outbuf[i]]);
1426 }
1427 }
1428 }
1429
sspm_encode_base64(struct sspm_buffer * buf,char * data,size_t size)1430 void sspm_encode_base64(struct sspm_buffer *buf, char* data, size_t size)
1431 {
1432 char *p;
1433 char inbuf[3];
1434 int i = 0;
1435 int first = 1;
1436 int lpos = 0;
1437 (void)size;
1438
1439 inbuf[0] = inbuf[1] = inbuf[2] = 0;
1440
1441 for (p = data; *p !=0; p++){
1442
1443 if (i%3 == 0 && first == 0){
1444
1445 sspm_write_base64(buf, inbuf, 4);
1446 lpos+=4;
1447
1448 inbuf[0] = inbuf[1] = inbuf[2] = 0;
1449 }
1450
1451 assert(lpos%4 == 0);
1452
1453 if (lpos == 72){
1454 sspm_append_string(buf,"\n");
1455 lpos = 0;
1456 }
1457
1458 inbuf[i%3] = *p;
1459
1460 i++;
1461 first = 0;
1462
1463 }
1464
1465
1466 /* If the inbuf was not exactly filled on the last byte, we need
1467 to spit out the odd bytes that did get in -- either one or
1468 two. This will result in an output of two bytes and '==' or
1469 three bytes and '=', respectively */
1470
1471 if (i%3 == 1 && first == 0){
1472 sspm_write_base64(buf, inbuf, 2);
1473 } else if (i%3 == 2 && first == 0){
1474 sspm_write_base64(buf, inbuf, 3);
1475 }
1476
1477 }
1478
sspm_write_header(struct sspm_buffer * buf,struct sspm_header * header)1479 void sspm_write_header(struct sspm_buffer *buf,struct sspm_header *header)
1480 {
1481
1482 int i;
1483 char temp[TMP_BUF_SIZE];
1484 const char* major;
1485 const char* minor;
1486
1487 /* Content-type */
1488
1489 major = sspm_major_type_string(header->major);
1490 minor = sspm_minor_type_string(header->minor);
1491
1492 if(header->minor == SSPM_UNKNOWN_MINOR_TYPE ){
1493 assert(header->minor_text !=0);
1494 minor = header->minor_text;
1495 }
1496
1497 snprintf(temp,sizeof(temp),"Content-Type: %s/%s",major,minor);
1498
1499 sspm_append_string(buf,temp);
1500
1501 if(header->boundary != 0){
1502 snprintf(temp,sizeof(temp),";boundary=\"%s\"",header->boundary);
1503 sspm_append_string(buf,temp);
1504 }
1505
1506 /* Append any content type parameters */
1507 if(header->content_type_params != 0){
1508 for(i=0; *(header->content_type_params[i])!= 0;i++){
1509 snprintf(temp, sizeof(temp),"%s", header->content_type_params[i]);
1510 sspm_append_char(buf, ';');
1511 sspm_append_string(buf, temp);
1512 }
1513 }
1514
1515 sspm_append_char(buf,'\n');
1516
1517 /*Content-Transfer-Encoding */
1518
1519 if(header->encoding != SSPM_UNKNOWN_ENCODING &&
1520 header->encoding != SSPM_NO_ENCODING){
1521 snprintf(temp,sizeof(temp),"Content-Transfer-Encoding: %s\n",
1522 sspm_encoding_string(header->encoding));
1523 }
1524
1525 sspm_append_char(buf,'\n');
1526
1527 }
1528
sspm_write_multipart_part(struct sspm_buffer * buf,struct sspm_part * parts,int * part_num)1529 void sspm_write_multipart_part(struct sspm_buffer *buf,
1530 struct sspm_part *parts,
1531 int* part_num)
1532 {
1533
1534 int parent_level, level;
1535 struct sspm_header *header = &(parts[*part_num].header);
1536 /* Write the header for the multipart part */
1537 sspm_write_header(buf,header);
1538
1539 parent_level = parts[*part_num].level;
1540
1541 (*part_num)++;
1542
1543 level = parts[*part_num].level;
1544
1545 while(parts[*part_num].header.major != SSPM_NO_MAJOR_TYPE &&
1546 level == parent_level+1){
1547
1548 assert(header->boundary);
1549 sspm_append_string(buf,header->boundary);
1550 sspm_append_char(buf,'\n');
1551
1552 if (parts[*part_num].header.major == SSPM_MULTIPART_MAJOR_TYPE){
1553 sspm_write_multipart_part(buf,parts,part_num);
1554 } else {
1555 sspm_write_part(buf, &(parts[*part_num]), part_num);
1556 }
1557
1558 (*part_num)++;
1559 level = parts[*part_num].level;
1560 }
1561
1562 sspm_append_string(buf,"\n\n--");
1563 sspm_append_string(buf,header->boundary);
1564 sspm_append_string(buf,"\n");
1565
1566 (*part_num)--; /* undo last, spurious, increment */
1567 }
1568
sspm_write_part(struct sspm_buffer * buf,struct sspm_part * part,int * part_num)1569 void sspm_write_part(struct sspm_buffer *buf,struct sspm_part *part,int *part_num)
1570 {
1571 (void)part_num;
1572
1573 /* Write header */
1574 sspm_write_header(buf,&(part->header));
1575
1576 /* Write part data */
1577
1578 if(part->data == 0){
1579 return;
1580 }
1581
1582 if(part->header.encoding == SSPM_BASE64_ENCODING) {
1583 assert(part->data_size != 0);
1584 sspm_encode_base64(buf,part->data,part->data_size);
1585 } else if(part->header.encoding == SSPM_QUOTED_PRINTABLE_ENCODING) {
1586 sspm_encode_quoted_printable(buf,part->data);
1587 } else {
1588 sspm_append_string(buf,part->data);
1589 }
1590
1591 sspm_append_string(buf,"\n\n");
1592 }
1593
sspm_write_mime(struct sspm_part * parts,size_t num_parts,char ** output_string,const char * header)1594 int sspm_write_mime(struct sspm_part *parts,size_t num_parts,
1595 char **output_string, const char* header)
1596 {
1597 struct sspm_buffer buf;
1598 int part_num =0;
1599 int slen;
1600 (void)num_parts;
1601
1602 buf.buffer = malloc(4096);
1603 buf.buffer[0] = '\0';
1604 buf.pos = buf.buffer;
1605 buf.buf_size = 10;
1606 buf.line_pos = 0;
1607
1608 /* write caller's header */
1609 if(header != 0){
1610 sspm_append_string(&buf,header);
1611 }
1612
1613 slen = strlen(buf.buffer);
1614 if(slen > 0 && buf.buffer[slen-1] != '\n'){
1615 sspm_append_char(&buf,'\n');
1616 }
1617
1618 /* write mime-version header */
1619 sspm_append_string(&buf,"Mime-Version: 1.0\n");
1620
1621 /* End of header */
1622
1623 /* Write body parts */
1624 while(parts[part_num].header.major != SSPM_NO_MAJOR_TYPE){
1625 if (parts[part_num].header.major == SSPM_MULTIPART_MAJOR_TYPE){
1626 sspm_write_multipart_part(&buf,parts,&part_num);
1627 } else {
1628 sspm_write_part(&buf, &(parts[part_num]), &part_num);
1629 }
1630
1631 part_num++;
1632 }
1633
1634
1635 *output_string = buf.buffer;
1636
1637 return 0;
1638 }
1639
1640