1
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5
6 #include <ctype.h>
7 #include <errno.h>
8
9 #include "main.h"
10 #include "struct.h"
11
12 #define MAXLINE 4096
13
14 typedef enum {
15 ENCODE_UNSET, /* not set, act NORMAL (ho ho ho) */
16 ENCODE_NORMAL,
17 ENCODE_QP, /* quoted printable */
18
19 ENCODE_MULTILINED, /* this is not a real type, but just a separator showing
20 that the types below are encoded in a way that makes
21 one line in the indata may become one or more lines
22 in the outdata */
23
24 ENCODE_BASE64, /* base64 */
25 ENCODE_UUENCODE, /* well, it seems there exist some kind of semi-standard
26 for uu-encoded attachments. */
27
28 ENCODE_UNKNOWN /* must be the last one */
29 } EncodeType;
30
31 typedef enum {
32 CONTENT_TEXT, /* normal mails are text based default */
33 CONTENT_BINARY, /* this kind we store separately and href to */
34 CONTENT_HTML, /* this is html formated text */
35 CONTENT_IGNORE, /* don't care about this content */
36
37 CONTENT_UNKNOWN /* must be the last one */
38 } ContentType;
39
40
preferedcontent(char * type)41 int preferedcontent(char *type)
42 {
43 if(!strcasecmp(type, "text/plain"))
44 return 1;
45 return 0;
46 }
47
48 /*
49 ** strcasestr() - case insensitive strstr()
50 */
51
52 /* FreeBSD defines this function a bit differently, so rename this version */
mail2sms_strcasestr(char * haystack,char * needle)53 char *mail2sms_strcasestr(char *haystack, char *needle)
54 {
55 int nlen = strlen(needle);
56 int hlen = strlen(haystack);
57
58 int i;
59 int max;
60
61 max = hlen-nlen;
62
63 for (i=0; i<=max; i++) {
64 if (!strncasecmp(haystack, needle, nlen))
65 return haystack;
66 haystack++;
67 }
68 return NULL;
69 }
70
71 /*
72 ** RFC 2047 defines MIME extensions for mail headers.
73 **
74 ** This function decodes that into binary/8bit data.
75 **
76 ** Example:
77 ** =?iso-8859-1?q?I'm_called_?= =?iso-8859-1?q?Daniel?=
78 **
79 ** Should result in "I'm called Daniel", but:
80 **
81 ** =?iso-8859-1?q?I'm_called?= Daniel
82 **
83 ** Should result in "I'm called Daniel" too.
84 **
85 ** Returns the newly allcated string, or the previous if nothing changed
86 */
87
mdecodeRFC2047(char * string,int length)88 static char *mdecodeRFC2047( char *string, int length )
89 {
90 char *iptr = string;
91 char *oldptr;
92 char *storage=malloc(length+1);
93
94 char *output = storage;
95
96 char charset[129];
97 char encoding[33];
98 char blurb[257];
99 char equal;
100 int value;
101
102 char didanything=FALSE;
103
104 while (*iptr) {
105 if (!strncmp(iptr, "=?", 2) &&
106 (3 == sscanf(iptr+2, "%128[^?]?%32[^?]?%256[^ ]",
107 charset, encoding, blurb)) ) {
108 /* This is a full, valid 'encoded-word'. Decode! */
109 char *ptr=blurb;
110
111 ptr = strstr(blurb, "?=");
112 if(ptr) {
113 *ptr=0;
114 }
115 else {
116 *output++ = *iptr++;
117 /* it wasn't a real encoded-word */
118 continue;
119 }
120 ptr = blurb;
121
122 didanything=TRUE; /* yes, we decode something */
123
124 /* we could've done this with a %n in the sscanf, but we know all
125 sscanfs don't grok that */
126
127 iptr += 2+ strlen(charset) + 1 + strlen(encoding) + 1 + strlen(blurb) + 2;
128
129 if (!strcasecmp("q", encoding)) {
130 /* quoted printable decoding */
131
132 for ( ; *ptr; ptr++ ) {
133 switch ( *ptr ) {
134 case '=':
135 sscanf( ptr+1, "%02X", &value );
136 *output++ = value;
137 ptr += 2;
138 break;
139 case '_':
140 *output++ = ' ';
141 break;
142 default:
143 *output++ = *ptr;
144 break;
145 }
146 }
147 }
148 else if (!strcasecmp("b", encoding)) {
149 /* base64 decoding */
150 int length;
151 base64Decode(ptr, output, &length);
152 output += length-1;
153 }
154 else {
155 /* unsupported encoding type */
156 strcpy(output, "<unknown>");
157 output += 9;
158 }
159
160 oldptr = iptr; /* save start position */
161
162 while (*iptr && isspace(*iptr))
163 iptr++; /* pass all whitespaces */
164
165 /* if this is an encoded word here, we should skip the passed
166 whitespaces. If it isn't an encoded-word, we should include the
167 whitespaces in the output. */
168
169 if (!strncmp(iptr, "=?", 2) &&
170 (4 == sscanf(iptr+2, "%128[^?]?%32[^?]?%128[^?]?%c",
171 charset, encoding, blurb, &equal)) &&
172 ('=' == equal)) {
173 continue; /* this IS an encoded-word, continue from here */
174 }
175 else
176 /* this IS NOT an encoded-word, move back to the first whitespace */
177 iptr = oldptr;
178 }
179 else
180 *output++ = *iptr++;
181 }
182 *output=0;
183
184 if (didanything) {
185 /* this check prevents unneccessary strsav() calls if not needed */
186 free(string); /* free old memory */
187
188 #if 0
189 /* debug display */
190 printf("NEW: %s\n", storage);
191
192 {
193 unsigned char *f;
194 puts("NEW:");
195 for (f=storage; f<output; f++) {
196 if (isgraph(*f))
197 printf("%c", *f);
198 else
199 printf("%02X", (unsigned char)*f);
200 }
201 puts("");
202 }
203 #endif
204 return storage; /* return new */
205 }
206 else {
207 free (storage);
208 return string;
209 }
210 }
211
212 /*
213 ** Decode this [virtual] Quoted-Printable line as defined by RFC2045.
214 ** Written by Daniel.Stenberg@haxx.nu
215 */
216
mdecodeQP(FILE * file,char * input,char ** result,int * length)217 static void mdecodeQP(FILE *file, char *input, char **result, int *length)
218 {
219 int outcount=0;
220 char *buffer=input;
221 unsigned char inchar;
222 char *output;
223
224 int len=strlen(input);
225 output=strdup(input);
226
227 while ((inchar = *input) != '\0') {
228
229 if (outcount>=len-1) {
230 /* we need to enlarge the destination area! */
231 /* double the size each time enlargement is needed */
232 char *newp = realloc(output, len*2);
233 if (newp) {
234 output = newp;
235 len *= 2;
236 }
237 else
238 break;
239 }
240
241 input++;
242 if ('=' == inchar) {
243 int value;
244 if (('\n'== *input) ||
245 (('\r' == input[0]) && ('\n' == input[1]))) {
246 if (!fgets(buffer, MAXLINE, file))
247 break;
248 input = buffer;
249 continue;
250 }
251 else if ('=' == *input) {
252 inchar='=';
253 input++; /* pass this */
254 }
255 else if (isxdigit(*input)) {
256 sscanf(input, "%02X", &value);
257 inchar = (unsigned char)value;
258 input+=2; /* pass the two letters */
259 }
260 else
261 inchar='=';
262 }
263 output[outcount++] = inchar;
264 }
265 output[outcount]=0; /* zero terminate */
266
267 *result = output;
268 *length = outcount;
269 }
270
271 /*
272 ** Parsing...
273 ** This loads in the mail from stdin or a file, adding the right
274 ** field variables to the right structures. If readone is set, it will
275 ** think anything it reads in is one article only.
276 */
277
process(char * mbox,int use_stdin,int readone)278 struct body * process(char *mbox, /* file name */
279 int use_stdin, /* read from stdin */
280 int readone) /* only one mail */
281 {
282 char line[MAXLINE];
283 char *cp, *dp;
284 FILE *fp;
285 int num, isinheader;
286
287 /* -- variables for the multipart/alternative parser -- */
288 struct body *origbp=NULL; /* store the original bp */
289 struct body *origlp=NULL; /* ... and the original lp */
290 char alternativeparser=FALSE; /* set when inside alternative parser mode */
291 /* -- end of alternative parser variables -- */
292
293 struct body *bp;
294 struct body *lp=NULL; /* the last pointer, points to the last node in the
295 body list. Initially set to NULL since we have
296 none at the moment. */
297
298 struct body *headp=NULL; /* stored pointer to the point where we last
299 scanned the headers of this mail. */
300
301 char Mime_B = FALSE;
302 char boundbuffer[128]="";
303
304 struct boundary *boundp=NULL; /* This variable is used to store a stack
305 of boundary separators in cases with mimed
306 mails inside mimed mails */
307
308 char multilinenoend=FALSE; /* This variable is set TRUE if we have read
309 a partial line off a multiline-encoded line,
310 and the next line we read is supposed to get
311 appended to the previous one */
312
313 int bodyflags=0; /* This variable is set to extra flags that the
314 addbody() calls should OR in the flag parameter */
315
316 char *binname=NULL; /* file name to store binary attachments in */
317 int binfile=-1;
318
319 char *boundary;
320 char type[129]; /* for Content-Type */
321
322
323 EncodeType decode=ENCODE_UNSET;
324 ContentType content=CONTENT_TEXT;
325
326 if (use_stdin || !mbox || !strcasecmp(mbox, "NONE"))
327 fp = stdin;
328 else if ((fp = fopen(mbox, "r")) == NULL) {
329 return -1; /* add error code */
330 }
331
332 isinheader = 1;
333
334 bp = NULL;
335
336 while (fgets(line, MAXLINE, fp) != NULL) {
337 #if 0
338 printf("IN: %s", line);
339 #endif
340 if (isinheader) {
341 /* check for MIME */
342 if (!strncasecmp( line, "MIME-Version:", 13))
343 Mime_B = TRUE;
344 else if (isspace(line[0]) && ('\n' != line[0]) && ('\r' != line[0])) {
345 /*
346 ** since this begins with a whitespace, it means the
347 ** previous line is continued on this line, leave only
348 ** one space character and go!
349 */
350 char *ptr=line;
351 while (isspace(*ptr))
352 ptr++;
353 ptr--; /* leave one space */
354 *ptr=' '; /* make it a true space, no tabs here! */
355 #if 0
356 decodeRFC2047(ptr+1, MAXLINE-(ptr+2-line));
357 #endif
358 bp = addbody(bp, &lp, ptr, BODY_CONTINUE|BODY_HEADER|bodyflags);
359 }
360
361 else if ((line[0] == '\n') || (line[0] == '\r')) {
362 struct body *head;
363
364 char savealternative;
365
366 /*
367 ** we mark this as a header-line, and we use it to
368 ** track end-of-header displays
369 */
370 bp = addbody(bp, &lp, line, BODY_HEADER|bodyflags);
371 isinheader--;
372
373 #if 0
374 printf("HEADER status: %d\n", isinheader);
375 #endif
376
377 /*
378 ** This signals us that we are no longer in the header,
379 ** let's fill in all those fields we are interested in.
380 ** Parse the headers up to now and copy to the target
381 ** variables
382 */
383
384 for (head = bp; head; head=head->next) {
385 if (head->header && !head->demimed) {
386 head->line = mdecodeRFC2047(head->line, strlen(head->line));
387 head->demimed=TRUE; /* don't do this again */
388 }
389 }
390
391 if (!headp)
392 headp=bp;
393
394 savealternative = FALSE;
395
396 for (head = headp; head; head=head->next) {
397 if(head->parsedheader || !head->header)
398 continue;
399
400 if (!strncasecmp( head->line, "Content-Type:", 13)) {
401 char *ptr=head->line+13;
402 #define DISP_HREF 1
403 #define DISP_IMG 2
404 #define DISP_IGNORE 3
405 /* default is href to the attachment: */
406 char disposition=DISP_HREF;
407
408 /* we must make sure this is not parsed more times
409 than this */
410 head->parsedheader= TRUE;
411
412 while (isspace(*ptr))
413 ptr++;
414
415 sscanf(ptr, "%128[^;]", type);
416 if ((cp = strchr(type, '\r')) != NULL)
417 *cp = '\0'; /* rm CR */
418 if ((cp = strchr(type, '\n')) != NULL)
419 *cp = '\0'; /* rm LF */
420
421 if(alternativeparser) {
422 /* We are parsing alternatives... */
423
424 if(preferedcontent(type) ) {
425 /* ... this is a prefered type, we want to store
426 this [instead of the earlier one]. */
427 #if 0
428 struct body *next;
429 printf("%s is more fun than the previous one\n",
430 type);
431 #endif
432 #if 0
433 /*
434 ** Not sure why this free section is here.
435 ** It is causing purify to barf with massive numbers of
436 ** "FMR: Free memory reads". When I commented it out it
437 ** cleared up the problem with no associated memory leaked
438 ** or difference in output. It's history for now.
439 */
440 while(bp) {
441 next=bp->next;
442 if (bp->line) free(bp->line);
443 if (bp) free(bp);
444 bp=next;
445 }
446 #endif
447 headp = NULL;
448 }
449 else {
450 /* ...and this type is not a prefered one. Thus, we
451 * shall ignore it completely! */
452 disposition = DISP_IGNORE;
453 #if 0
454 printf("%s is to be ignored\n", type);
455 #endif
456 }
457 }
458 if (!strcasecmp(type, "text/plain") ||
459 (!alternativeparser &&
460 !strcasecmp(type, "text/html")) ) {
461 /*
462 * text or inlined html follows
463 */
464 /* default is just plain 7/8 bit */
465 if(ENCODE_UNSET == decode)
466 decode = ENCODE_NORMAL;
467
468 if (!strcasecmp(type, "text/html"))
469 content = CONTENT_HTML;
470 else
471 content = CONTENT_TEXT;
472 continue;
473 }
474 else if (!strncasecmp(type, "message/rfc822", 14)) {
475 /*
476 ** Here comes an attached mail! This can be ugly,
477 ** since the attached mail may very well itself
478 ** contain attached binaries, or why not another
479 ** attached mail? :-)
480 **
481 ** We need to store the current boundary separator
482 ** in order to get it back when we're done parsing
483 ** this particular mail, since each attached mail
484 ** will have its own boundary separator that *might*
485 ** be used.
486 */
487 #if 0
488 /* removed 2001-02-07, this is old leftovers from when I
489 * picked this code out of hypermail */
490 bp = addbody(bp, &lp,
491 "<P><STRONG>attached mail follows:</STRONG><HR>",
492 BODY_HTMLIZED | bodyflags);
493 #endif
494 bodyflags |= BODY_ATTACHED;
495 isinheader = 2;
496 continue;
497 }
498 else if (strncasecmp(type, "multipart/", 10)) {
499 /*
500 ** This is not a multipart and not text
501 */
502 struct body *fnamep=NULL;
503 char acomment[256];
504 char attachname[129]; /* listed attachment name */
505 char checkpath[256]; /* uniqueness path */
506 char *fname = NULL; /* attachment filename */
507 char nameisuniq=FALSE; /* use the name included ?*/
508 char *file = NULL;
509
510 fname = strstr(ptr, "name=");
511 if (NULL == fname) {
512 /*
513 ** Name of file not specified in the
514 ** Content-Type header. See if the
515 ** Content-Disposition header exists and
516 ** contains the info.
517 */
518
519 for (fnamep = head;fnamep;fnamep=fnamep->next) {
520 if(!fnamep->header)
521 continue;
522 if (!strncasecmp(fnamep->line,"Content-Disposition:", 20)) {
523 if ((fname = strstr(fnamep->line, "filename=")) != NULL) {
524 sscanf(fname+10, "%128[^\"]",attachname);
525 fname = attachname;
526 }
527 }
528 }
529 }
530 else {
531 sscanf(fname+6, "%128[^\"]", attachname);
532 fname = attachname;
533 }
534 #if 0
535 sprintf(line, "** %s\n", fname?fname:"attachment");
536 bp = addbody(bp,&lp,line,BODY_HTMLIZED|bodyflags);
537 #endif
538 /* don't save this */
539 disposition = DISP_IGNORE;
540 content = CONTENT_IGNORE;
541
542 continue;
543 }
544 else {
545 /*
546 ** Find the first boundary separator
547 */
548
549 boundary=strcasestr(ptr, "boundary=");
550
551 if (boundary) {
552 boundary=strchr(boundary, '=');
553 if (boundary) {
554 boundary++;
555 while (isspace(*boundary))
556 boundary++;
557 if ('\"' == *boundary) {
558 sscanf(++boundary, "%[^\"]", boundbuffer);
559 }
560 else
561 sscanf(boundary, "%s", boundbuffer);
562 boundary = boundbuffer;
563 }
564
565 while (fgets(line, MAXLINE, fp)) {
566 if (!strncmp(line, "--", 2) &&
567 !strncmp(line+2, boundbuffer,
568 strlen(boundbuffer))) {
569 break;
570 }
571 }
572
573 /*
574 ** This stores the boundary string in a stack
575 ** of strings:
576 */
577 boundp = bound(boundp, boundbuffer);
578
579 /* printf("set new boundary: %s\n", boundp->line); */
580
581 /*
582 ** We set ourselves, "back in header" since there is
583 ** gonna come MIME headers now after the separator
584 */
585 isinheader = 1;
586
587 /* Daniel Stenberg started adding the
588 * "multipart/alternative" parser 13th of July
589 * 1998! We check if this is a 'multipart/
590 * alternative' header, in which case we need to
591 * treat it very special.
592 */
593
594 if(!strncasecmp(&ptr[10], "alternative", 11)) {
595 /* It *is* an alternative session! Alternative
596 ** means there will be X parts with the same text
597 ** using different content-types. We are supposed
598 ** to take the most prefered format of the ones
599 ** used and only output that one. MIME defines
600 ** the order of the texts to start with pure text
601 ** and then continue with more and more obscure
602 ** formats. (well, it doesn't use those terms but
603 ** that's what it means! ;-))
604 */
605
606 /* How "we" are gonna deal with them:
607 **
608 ** We create a "spare" linked list body for the
609 ** very first part. Since the first part is
610 ** defined to be the most readable, we save that
611 ** in case no content-type present is prefered!
612 **
613 ** We skip all parts that are not prefered. All
614 ** prefered parts found will replace the first
615 ** one that is saved. When we reach the end of
616 ** the alternatives, we will use the last saved
617 ** one as prefered.
618 */
619
620 savealternative = TRUE;
621 #if 0
622 printf("SAVEALTERNATIVE: yes\n");
623 #endif
624
625 }
626
627 }
628 else
629 boundary = NULL;
630 }
631 }
632 else if (!strncasecmp(head->line, "Content-Transfer-Encoding:", 26)) {
633 char *ptr=head->line+26;
634
635 head->parsedheader= TRUE;
636 while (isspace(*ptr))
637 ptr++;
638 if (!strncasecmp(ptr, "QUOTED-PRINTABLE", 16)) {
639 decode = ENCODE_QP;
640 }
641 else if (!strncasecmp(ptr, "BASE64", 6)) {
642 decode = ENCODE_BASE64;
643 }
644 else if (!strncasecmp(ptr, "8BIT", 4)) {
645 decode = ENCODE_NORMAL;
646 }
647 else if (!strncasecmp(ptr, "7BIT", 4)) {
648 decode = ENCODE_NORMAL;
649 }
650 else if (!strncasecmp(ptr, "x-uue", 5)) {
651 decode = ENCODE_UUENCODE;
652
653 if (uudecode(fp, line, line, NULL, TRUE))
654 /*
655 ** oh gee, we failed this is chaos */
656 break;
657 }
658 else {
659 /* this is an unknown format, we use default decoding */
660 char code[64];
661
662 sscanf(ptr, "%63s", code);
663 sprintf(line, " ('%s')\n", code);
664
665 bp = addbody(bp, &lp, line, BODY_HTMLIZED|bodyflags);
666 }
667 #if 0
668 printf("DECODE set to %d\n", decode);
669 #endif
670 }
671 }
672 if (savealternative) {
673 /* let's remember 'bp' and 'lp' */
674
675 origbp=bp;
676 origlp=lp;
677
678 alternativeparser = TRUE;
679
680 /* restart on a new list: */
681 lp=bp=NULL;
682 }
683 headp = lp; /* start at this point next time */
684 }
685 else {
686 #if 0
687 decodeRFC2047(line, MAXLINE);
688 #endif
689 bp = addbody(bp, &lp, line, BODY_HEADER|bodyflags);
690 }
691 }
692 else {
693 /* decode MIME complient gibberish */
694 char newbuffer[MAXLINE];
695 char *data;
696 int datalen=-1; /* -1 means use strlen to get length */
697
698 if (Mime_B) {
699 if (boundp &&
700 !strncmp(line, "--", 2) &&
701 !strncmp(line+2, boundp->line, strlen(boundp->line))) {
702 /* right at this point, we have another part coming up */
703 isinheader = 1; /* back on a kind-of-header */
704
705 #if 0
706 printf("hit %s\n", line);
707 #endif
708 if (!strncmp(line+2+strlen(boundp->line), "--", 2)) {
709 bp = addbody(bp,&lp,"\n",BODY_HTMLIZED|bodyflags);
710
711
712 isinheader = 0; /* no header, the ending boundary
713 can't have any describing
714 headers */
715
716 #if 0
717 printf("End boundary %s\n", line);
718 #endif
719 boundp = bound(boundp, NULL);
720 if (!boundp) {
721 bodyflags &= ~BODY_ATTACHED;
722 }
723 if(alternativeparser) {
724 struct body *next;
725 /* we no longer have alternatives */
726 alternativeparser = FALSE;
727 #if 0
728 printf("We DUMP an old alternative\n");
729 #endif
730 while(bp) {
731 origbp = addbody(origbp, &origlp,
732 bp->line,
733 (bp->header?BODY_HEADER:0)|
734 (bp->html?BODY_HTMLIZED:0)|
735 (bp->attached?BODY_ATTACHED:0)
736 );
737 next= bp->next;
738 free(bp->line);
739 free(bp);
740 bp=next;
741 }
742 bp = origbp;
743 lp = origlp;
744
745 headp= NULL;
746 }
747 #if 0
748 if (boundp)
749 printf("back %s\n", boundp->line);
750 else
751 printf("back to NONE\n");
752 #endif
753 }
754
755 if (-1 != binfile) {
756 close(binfile);
757 binfile=-1;
758 }
759 continue;
760 }
761 }
762
763 switch ( decode ) {
764 case ENCODE_QP:
765 mdecodeQP(fp, line, &data, &datalen);
766 break;
767 case ENCODE_BASE64:
768 base64Decode(line, newbuffer, &datalen);
769 data = newbuffer;
770 break;
771 case ENCODE_UUENCODE:
772 uudecode(NULL, line, newbuffer, &datalen, FALSE);
773 data = newbuffer;
774 break;
775 case ENCODE_NORMAL:
776 case ENCODE_UNSET:
777 data = line;
778 break;
779 default:
780 /* we have no clue! */
781 data = NULL;
782 break;
783 }
784 #if 0
785 printf("LINE %s\n", data);
786 #endif
787 if (data) {
788 if ((content == CONTENT_TEXT) || (content==CONTENT_HTML)) {
789 if (decode > ENCODE_MULTILINED) {
790 /*
791 ** This can be more than one resulting line,
792 ** as the decoded the string may look like:
793 "#!/bin/sh\r\n\r\nhelp() {\r\n echo 'Usage: difftree"
794 */
795 char *p=data;
796 char *n;
797 char store;
798
799 #if 0
800 printf("decode type %d\n", decode);
801 #endif
802
803 while ((n = strchr(p, '\n'))) {
804 store = n[1];
805 n[1]=0;
806 #if 0
807 printf("UNFOLDED %s", p);
808 #endif
809 bp = addbody(bp, &lp, p,
810 (content==CONTENT_HTML?
811 BODY_HTMLIZED:0)|
812 (multilinenoend?BODY_CONTINUE:0)|
813 bodyflags);
814 multilinenoend = FALSE; /* full line pushed */ n[1]=store;
815 p = n+1;
816 }
817 if (strlen(p)) {
818 /*
819 ** This line doesn't really end here,
820 ** we will get another line soon that
821 ** should get appended!
822 */
823 #if 0
824 printf("CONTINUE %s\n", p);
825 #endif
826 bp = addbody(bp, &lp, p,
827 (content==CONTENT_HTML?
828 BODY_HTMLIZED:0)|
829 (multilinenoend?BODY_CONTINUE:0)|
830 bodyflags);
831
832 /*
833 ** We want the next line to get appended to this!
834 */
835 multilinenoend = TRUE;
836 }
837 }
838 else {
839 bp = addbody(bp, &lp, data,
840 (content==CONTENT_HTML?
841 BODY_HTMLIZED:0) | bodyflags );
842 }
843 #if 0
844 printf("ALIVE?\n");
845 #endif
846 }
847 else if (content == CONTENT_BINARY) {
848 if (-1 != binfile) {
849 if (datalen < 0)
850 datalen = strlen(data);
851
852 /*fwrite(data, datalen, 1, binfile); */
853 write(binfile, data, datalen);
854 /*bp = addbody(bp, "file contents");*/
855 }
856 }
857
858 if (ENCODE_QP == decode)
859 free(data); /* this was allocatd by mdecodeQP() */
860 }
861 }
862 }
863
864 if (!isinheader || readone) {
865 while (rmlastlines(bp));
866 num++;
867 }
868
869 fclose(fp);
870
871 /* can we clean up a bit please... */
872
873 if (boundp != NULL) {
874 if (boundp->line)
875 free(boundp->line);
876 free(boundp);
877 }
878
879
880 return bp;
881 }
882
883