1 /* $Cambridge: exim/src/src/demime.c,v 1.10 2010/06/05 11:13:29 pdp Exp $ */
3 /*************************************************
4 * Exim - an Internet mail transport agent *
5 *************************************************/
7 /* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
10 /* Code for unpacking MIME containers. Called from acl.c. */
13 #ifdef WITH_OLD_DEMIME
17 uschar demime_reason_buffer
[1024];
18 struct file_extension
*file_extensions
= NULL
;
20 int demime(uschar
**listptr
) {
22 uschar
*list
= *listptr
;
24 uschar option_buffer
[64];
25 unsigned long mbox_size
;
27 uschar defer_error_buffer
[1024];
30 /* reset found_extension variable */
31 found_extension
= NULL
;
33 /* try to find 1st option */
34 if ((option
= string_nextinlist(&list
, &sep
,
36 sizeof(option_buffer
))) != NULL
) {
38 /* parse 1st option */
39 if ( (Ustrcmp(option
,"false") == 0) || (Ustrcmp(option
,"0") == 0) ) {
40 /* explicitly no demimeing */
45 /* no options -> no demimeing */
49 /* make sure the eml mbox file is spooled up */
50 mbox_file
= spool_mbox(&mbox_size
, NULL
);
52 if (mbox_file
== NULL
) {
53 /* error while spooling */
54 log_write(0, LOG_MAIN
|LOG_PANIC
,
55 "demime acl condition: error while creating mbox spool file");
59 /* call demimer if not already done earlier */
61 demime_rc
= mime_demux(mbox_file
, defer_error_buffer
);
63 (void)fclose(mbox_file
);
65 if (demime_rc
== DEFER
) {
66 /* temporary failure (DEFER => DEFER) */
67 log_write(0, LOG_MAIN
,
68 "demime acl condition: %s", defer_error_buffer
);
72 /* set demime_ok to avoid unpacking again */
75 /* check for file extensions, if there */
76 while (option
!= NULL
) {
77 struct file_extension
*this_extension
= file_extensions
;
79 /* Look for the wildcard. If it is found, we always return true.
80 The user must then use a custom condition to evaluate demime_errorlevel */
81 if (Ustrcmp(option
,"*") == 0) {
82 found_extension
= NULL
;
86 /* loop thru extension list */
87 while (this_extension
!= NULL
) {
88 if (strcmpic(option
, this_extension
->file_extension_string
) == 0) {
90 found_extension
= this_extension
->file_extension_string
;
93 this_extension
= this_extension
->next
;
96 /* grab next extension from option list */
97 option
= string_nextinlist(&list
, &sep
,
99 sizeof(option_buffer
));
107 /*************************************************
108 * small hex_str -> integer conversion function *
109 *************************************************/
111 /* needed for quoted-printable
114 unsigned int mime_hstr_i(uschar
*cptr
) {
115 unsigned int i
, j
= 0;
117 while (cptr
&& *cptr
&& isxdigit(*cptr
)) {
128 /*************************************************
129 * decode quoted-printable chars *
130 *************************************************/
132 /* gets called when we hit a =
133 returns: new pointer position
136 -1 - soft line break, no char
137 0-255 - char to write
140 uschar
*mime_decode_qp(uschar
*qp_p
,int *c
) {
141 uschar hex
[] = {0,0,0};
143 uschar
*initial_pos
= qp_p
;
145 /* advance one char */
149 if ( (*qp_p
== '\t') || (*qp_p
== ' ') || (*qp_p
== '\r') ) {
150 /* tab or whitespace may follow
151 just ignore it, but remember
152 that this is not a valid hex
158 else if ( (('0' <= *qp_p
) && (*qp_p
<= '9')) || (('A' <= *qp_p
) && (*qp_p
<= 'F')) || (('a' <= *qp_p
) && (*qp_p
<= 'f')) ) {
159 /* this is a valid hex char, if nan is unset */
161 /* this is illegal */
170 else if (*qp_p
== '\n') {
171 /* hit soft line break already, continue */
176 /* illegal char here */
181 if ( (('0' <= *qp_p
) && (*qp_p
<= '9')) || (('A' <= *qp_p
) && (*qp_p
<= 'F')) || (('a' <= *qp_p
) && (*qp_p
<= 'f')) ) {
184 /* do hex conversion */
185 *c
= mime_hstr_i(hex
);
204 /*************************************************
205 * open new dump file *
206 *************************************************/
208 /* open new dump file
209 returns: -2 soft error
210 or file #, FILE * in f
213 int mime_get_dump_file(uschar
*extension
, FILE **f
, uschar
*info
) {
214 uschar file_name
[1024];
216 unsigned int file_nr
;
217 uschar default_extension
[] = ".com";
220 if (extension
== NULL
)
221 extension
= default_extension
;
223 /* scan the proposed extension.
224 if it is longer than 4 chars, or
225 contains exotic chars, use the default extension */
227 /* if (Ustrlen(extension) > 4) {
228 extension = default_extension;
235 *p
= (uschar
)tolower((uschar
)*p
);
236 if ( (*p
< 97) || (*p
> 122) ) {
237 extension
= default_extension
;
243 /* find a new file to write to */
248 (void)string_format(file_name
,1024,"%s/scan/%s/%s-%05u%s",spool_directory
,message_id
,message_id
,file_nr
,extension
);
250 if (file_nr
>= MIME_SANITY_MAX_DUMP_FILES
) {
251 /* max parts reached */
252 mime_trigger_error(MIME_ERRORLEVEL_TOO_MANY_PARTS
);
255 result
= stat(CS file_name
,&mystat
);
259 *f
= modefopen(file_name
,"wb+",SPOOL_MODE
);
261 /* cannot open new dump file, disk full ? -> soft error */
262 (void)string_format(info
, 1024,"unable to open dump file");
270 /*************************************************
271 * Find a string in a mime header *
272 *************************************************/
274 /* Find a string in a mime header, and optionally fill in
275 the value associated with it into *value
277 returns: 0 - nothing found
279 2 - found param + value
282 int mime_header_find(uschar
*header
, uschar
*param
, uschar
**value
) {
285 needle
= strstric(header
,param
,FALSE
);
286 if (needle
!= NULL
) {
288 needle
+= Ustrlen(param
);
289 if (*needle
== '=') {
293 value_start
= needle
+ 1;
294 value_end
= strstric(value_start
,US
";",FALSE
);
295 if (value_end
!= NULL
) {
296 /* allocate mem for value */
297 *value
= (uschar
*)malloc((value_end
- value_start
)+1);
301 Ustrncpy(*value
,value_start
,(value_end
- value_start
));
302 (*value
)[(value_end
- value_start
)] = '\0';
313 /*************************************************
314 * Read a line of MIME input *
315 *************************************************/
316 /* returns status code, one of
319 MIME_READ_LINE_OVERFLOW 2
321 In header mode, the line will be "cooked".
324 int mime_read_line(FILE *f
, int mime_demux_mode
, uschar
*buffer
, long *num_copied
) {
327 int header_value_mode
= 0;
328 int header_open_brackets
= 0;
337 /* --------- header mode -------------- */
338 if (mime_demux_mode
== MIME_DEMUX_MODE_MIME_HEADERS
) {
340 /* always skip CRs */
341 if (c
== '\r') continue;
344 if ((*num_copied
) > 0) {
345 /* look if next char is '\t' or ' ' */
348 if ( (c
== '\t') || (c
== ' ') ) continue;
351 /* end of the header, terminate with ';' */
356 /* skip control characters */
357 if (c
< 32) continue;
359 /* skip whitespace + tabs */
360 if ( (c
== ' ') || (c
== '\t') )
363 if (header_value_mode
) {
364 /* --------- value mode ----------- */
366 if (c
== '"') continue;
368 /* leave value mode on ';' */
370 header_value_mode
= 0;
372 /* -------------------------------- */
375 /* -------- non-value mode -------- */
377 /* quote next char. can be used
378 to escape brackets. */
383 header_open_brackets
++;
386 else if ((c
== ')') && header_open_brackets
) {
387 header_open_brackets
--;
390 else if ( (c
== '=') && !header_open_brackets
) {
391 /* enter value mode */
392 header_value_mode
= 1;
395 /* skip chars while we are in a comment */
396 if (header_open_brackets
> 0)
398 /* -------------------------------- */
401 /* ------------------------------------ */
403 /* ----------- non-header mode -------- */
407 /* ------------------------------------ */
410 /* copy the char to the buffer */
411 buffer
[*num_copied
] = (uschar
)c
;
415 /* break if buffer is full */
416 if (*num_copied
> MIME_SANITY_MAX_LINE_LENGTH
-1) {
422 buffer
[*num_copied
] = '\0';
424 if (*num_copied
> MIME_SANITY_MAX_LINE_LENGTH
-1)
425 return MIME_READ_LINE_OVERFLOW
;
428 return MIME_READ_LINE_EOF
;
430 return MIME_READ_LINE_OK
;
434 /*************************************************
435 * Check for a MIME boundary *
436 *************************************************/
438 /* returns: 0 - no boundary found
439 1 - start boundary found
440 2 - end boundary found
443 int mime_check_boundary(uschar
*line
, struct boundary
*boundaries
) {
444 struct boundary
*thisboundary
= boundaries
;
445 uschar workbuf
[MIME_SANITY_MAX_LINE_LENGTH
+1];
448 /* check for '--' first */
449 if (Ustrncmp(line
,"--",2) == 0) {
451 /* strip tab and space */
452 for (i
= 2; i
< Ustrlen(line
); i
++) {
453 if ((line
[i
] != ' ') && (line
[i
] != '\t')) {
454 workbuf
[j
] = line
[i
];
460 while(thisboundary
!= NULL
) {
461 if (Ustrncmp(workbuf
,thisboundary
->boundary_string
,Ustrlen(thisboundary
->boundary_string
)) == 0) {
462 if (Ustrncmp(&workbuf
[Ustrlen(thisboundary
->boundary_string
)],"--",2) == 0) {
463 /* final boundary found */
468 thisboundary
= thisboundary
->next
;
476 /*************************************************
477 * Check for start of a UUENCODE block *
478 *************************************************/
480 /* returns 0 for no hit,
484 int mime_check_uu_start(uschar
*line
, uschar
*uu_file_extension
, int *has_tnef
) {
486 if ( (strncmpic(line
,US
"begin ",6) == 0)) {
487 uschar
*uu_filename
= &line
[6];
489 /* skip perms, if present */
490 Ustrtoul(&line
[6],&uu_filename
,10);
492 /* advance one char */
495 /* This should be the filename.
496 Check if winmail.dat is present,
497 which indicates TNEF. */
498 if (strncmpic(uu_filename
,US
"winmail.dat",11) == 0) {
502 /* reverse to dot if present,
503 copy up to 4 chars for the extension */
504 if (Ustrrchr(uu_filename
,'.') != NULL
)
505 uu_filename
= Ustrrchr(uu_filename
,'.');
507 return sscanf(CS uu_filename
, "%4[.0-9A-Za-z]",CS uu_file_extension
);
516 /*************************************************
518 *************************************************/
520 /* returns number of decoded bytes
524 int warned_about_uudec_line_sanity_1
= 0;
525 int warned_about_uudec_line_sanity_2
= 0;
526 long uu_decode_line(uschar
*line
, uschar
**data
, long line_len
, uschar
*info
) {
528 long num_decoded
= 0;
531 int uu_decoded_line_len
, uu_encoded_line_len
;
533 /* allocate memory for data and work buffer */
534 *data
= (uschar
*)malloc(line_len
);
536 (void)string_format(info
, 1024,"unable to allocate %lu bytes",line_len
);
540 work
= (uschar
*)malloc(line_len
);
542 (void)string_format(info
, 1024,"unable to allocate %lu bytes",line_len
);
546 memcpy(work
,line
,line_len
);
548 /* First char is line length
549 This is microsofts way of getting it. Scary. */
551 /* ignore this line */
555 uu_decoded_line_len
= uudec
[work
[0]];
565 uu_encoded_line_len
= (p
- &work
[1]);
568 /* check that resulting line length is a multiple of 4 */
569 if ( ( uu_encoded_line_len
% 4 ) != 0) {
570 if (!warned_about_uudec_line_sanity_1
) {
571 mime_trigger_error(MIME_ERRORLEVEL_UU_MISALIGNED
);
572 warned_about_uudec_line_sanity_1
= 1;
577 /* check that the line length matches */
578 if ( ( (((uu_encoded_line_len
/4)*3)-2) > uu_decoded_line_len
) || (((uu_encoded_line_len
/4)*3) < uu_decoded_line_len
) ) {
579 if (!warned_about_uudec_line_sanity_2
) {
580 mime_trigger_error(MIME_ERRORLEVEL_UU_LINE_LENGTH
);
581 warned_about_uudec_line_sanity_2
= 1;
586 while ( ((p
- &work
[1]) < uu_encoded_line_len
) && (num_decoded
< uu_decoded_line_len
)) {
588 /* byte 0 ---------------------- */
589 if ((p
- &work
[1] + 1) >= uu_encoded_line_len
) {
593 (*data
)[num_decoded
] = *p
;
594 (*data
)[num_decoded
] <<= 2;
598 (*data
)[num_decoded
] |= tmp_c
;
603 /* byte 1 ---------------------- */
604 if ((p
- &work
[1] + 1) >= uu_encoded_line_len
) {
608 (*data
)[num_decoded
] = *p
;
609 (*data
)[num_decoded
] <<= 4;
613 (*data
)[num_decoded
] |= tmp_c
;
618 /* byte 2 ---------------------- */
619 if ((p
- &work
[1] + 1) >= uu_encoded_line_len
) {
623 (*data
)[num_decoded
] = *p
;
624 (*data
)[num_decoded
] <<= 6;
626 (*data
)[num_decoded
] |= *(p
+1);
633 return uu_decoded_line_len
;
637 /*************************************************
638 * Decode a b64 or qp line *
639 *************************************************/
641 /* returns number of decoded bytes
646 int warned_about_b64_line_length
= 0;
647 int warned_about_b64_line_sanity
= 0;
648 int warned_about_b64_illegal_char
= 0;
649 int warned_about_qp_line_sanity
= 0;
650 long mime_decode_line(int mime_demux_mode
,uschar
*line
, uschar
**data
, long max_data_len
, uschar
*info
) {
652 long num_decoded
= 0;
656 /* allocate memory for data */
657 *data
= (uschar
*)malloc(max_data_len
);
659 (void)string_format(info
, 1024,"unable to allocate %lu bytes",max_data_len
);
663 if (mime_demux_mode
== MIME_DEMUX_MODE_BASE64
) {
664 /* ---------------------------------------------- */
666 /* NULL out trailing '\r' and '\n' chars */
667 while (Ustrrchr(line
,'\r') != NULL
) {
668 *(Ustrrchr(line
,'\r')) = '\0';
670 while (Ustrrchr(line
,'\n') != NULL
) {
671 *(Ustrrchr(line
,'\n')) = '\0';
674 /* check maximum base 64 line length */
675 if (Ustrlen(line
) > MIME_SANITY_MAX_B64_LINE_LENGTH
) {
676 if (!warned_about_b64_line_length
) {
677 mime_trigger_error(MIME_ERRORLEVEL_B64_LINE_LENGTH
);
678 warned_about_b64_line_length
= 1;
684 while (*(p
+offset
) != '\0') {
685 /* hit illegal char ? */
686 if (b64
[*(p
+offset
)] == 128) {
687 if (!warned_about_b64_illegal_char
) {
688 mime_trigger_error(MIME_ERRORLEVEL_B64_ILLEGAL_CHAR
);
689 warned_about_b64_illegal_char
= 1;
694 *p
= b64
[*(p
+offset
)];
700 /* check that resulting line length is a multiple of 4 */
701 if ( ( (p
- &line
[0]) % 4 ) != 0) {
702 if (!warned_about_b64_line_sanity
) {
703 mime_trigger_error(MIME_ERRORLEVEL_B64_MISALIGNED
);
704 warned_about_b64_line_sanity
= 1;
708 /* line is translated, start bit shifting */
714 /* byte 0 ---------------------- */
719 (*data
)[num_decoded
] = *p
;
720 (*data
)[num_decoded
] <<= 2;
724 (*data
)[num_decoded
] |= tmp_c
;
729 /* byte 1 ---------------------- */
734 (*data
)[num_decoded
] = *p
;
735 (*data
)[num_decoded
] <<= 4;
739 (*data
)[num_decoded
] |= tmp_c
;
744 /* byte 2 ---------------------- */
749 (*data
)[num_decoded
] = *p
;
750 (*data
)[num_decoded
] <<= 6;
752 (*data
)[num_decoded
] |= *(p
+1);
759 /* ---------------------------------------------- */
761 else if (mime_demux_mode
== MIME_DEMUX_MODE_QP
) {
762 /* ---------------------------------------------- */
767 int decode_qp_result
;
769 p
= mime_decode_qp(p
,&decode_qp_result
);
771 if (decode_qp_result
== -2) {
772 /* Error from decoder. p is unchanged. */
773 if (!warned_about_qp_line_sanity
) {
774 mime_trigger_error(MIME_ERRORLEVEL_QP_ILLEGAL_CHAR
);
775 warned_about_qp_line_sanity
= 1;
777 (*data
)[num_decoded
] = '=';
781 else if (decode_qp_result
== -1) {
782 /* End of the line with soft line break.
786 else if (decode_qp_result
>= 0) {
787 (*data
)[num_decoded
] = decode_qp_result
;
792 (*data
)[num_decoded
] = *p
;
799 /* ---------------------------------------------- */
807 /*************************************************
808 * Log demime errors and set mime error level *
809 *************************************************/
811 /* This sets the global demime_reason expansion
812 variable and the demime_errorlevel gauge. */
814 void mime_trigger_error(int level
, uschar
*format
, ...) {
818 if( (f
= malloc(16384+23)) != NULL
) {
819 /* first log the incident */
820 sprintf(f
,"demime acl condition: ");
822 va_start(ap
, format
);
823 (void)string_vformat(US f
, 16383,(char *)format
, ap
);
826 log_write(0, LOG_MAIN
, f
);
827 /* then copy to demime_reason_buffer if new
828 level is greater than old level */
829 if (level
> demime_errorlevel
) {
830 demime_errorlevel
= level
;
831 Ustrcpy(demime_reason_buffer
, US f
);
832 demime_reason
= demime_reason_buffer
;
838 /*************************************************
839 * Demultiplex MIME stream. *
840 *************************************************/
842 /* We can handle BASE64, QUOTED-PRINTABLE, and UUENCODE.
843 UUENCODE does not need to have a proper
844 transfer-encoding header, we detect it with "begin"
846 This function will report human parsable errors in
849 returns DEFER -> soft error (see *info)
850 OK -> EOF hit, all ok
853 int mime_demux(FILE *f
, uschar
*info
) {
854 int mime_demux_mode
= MIME_DEMUX_MODE_MIME_HEADERS
;
855 int uu_mode
= MIME_UU_MODE_OFF
;
856 FILE *mime_dump_file
= NULL
;
857 FILE *uu_dump_file
= NULL
;
859 int mime_read_line_status
= MIME_READ_LINE_OK
;
861 struct boundary
*boundaries
= NULL
;
862 struct mime_part mime_part_p
;
866 /* allocate room for our linebuffer */
867 line
= (uschar
*)malloc(MIME_SANITY_MAX_LINE_LENGTH
);
869 (void)string_format(info
, 1024,"unable to allocate %u bytes",MIME_SANITY_MAX_LINE_LENGTH
);
873 /* clear MIME header structure */
874 memset(&mime_part_p
,0,sizeof(mime_part
));
876 /* ----------------------- start demux loop --------------------- */
877 while (mime_read_line_status
== MIME_READ_LINE_OK
) {
879 /* read a line of input. Depending on the mode we are in,
880 the returned format will differ. */
881 mime_read_line_status
= mime_read_line(f
,mime_demux_mode
,line
,&line_len
);
883 if (mime_read_line_status
== MIME_READ_LINE_OVERFLOW
) {
884 mime_trigger_error(MIME_ERRORLEVEL_LONG_LINE
);
885 /* despite the error, continue .. */
886 mime_read_line_status
= MIME_READ_LINE_OK
;
889 else if (mime_read_line_status
== MIME_READ_LINE_EOF
) {
893 if (mime_demux_mode
== MIME_DEMUX_MODE_MIME_HEADERS
) {
894 /* -------------- header mode --------------------- */
896 /* Check for an empty line, which is the end of the headers.
897 In HEADER mode, the line is returned "cooked", with the
898 final '\n' replaced by a ';' */
902 /* We have reached the end of the headers. Start decoding
903 with the collected settings. */
904 if (mime_part_p
.seen_content_transfer_encoding
> 1) {
905 mime_demux_mode
= mime_part_p
.seen_content_transfer_encoding
;
908 /* default to plain mode if no specific encoding type found */
909 mime_demux_mode
= MIME_DEMUX_MODE_PLAIN
;
912 /* open new dump file */
913 tmp
= mime_get_dump_file(mime_part_p
.extension
, &mime_dump_file
, info
);
918 /* clear out mime_part */
919 memset(&mime_part_p
,0,sizeof(mime_part
));
922 /* Another header to check for file extensions,
923 encoding type and boundaries */
924 if (strncmpic(US
"content-type:",line
,Ustrlen("content-type:")) == 0) {
925 /* ---------------------------- Content-Type header ------------------------------- */
926 uschar
*value
= line
;
928 /* check for message/partial MIME type and reject it */
929 if (mime_header_find(line
,US
"message/partial",NULL
) > 0)
930 mime_trigger_error(MIME_ERRORLEVEL_MESSAGE_PARTIAL
);
932 /* check for TNEF content type, remember to unpack TNEF later. */
933 if (mime_header_find(line
,US
"application/ms-tnef",NULL
) > 0)
936 /* check for message/rfcxxx attachments */
937 if (mime_header_find(line
,US
"message/rfc822",NULL
) > 0)
940 /* find the file extension, but do not fill it in
941 it is already set, since content-disposition has
943 if (mime_part_p
.extension
== NULL
) {
944 if (mime_header_find(line
,US
"name",&value
) == 2) {
945 if (Ustrlen(value
) > MIME_SANITY_MAX_FILENAME
)
946 mime_trigger_error(MIME_ERRORLEVEL_FILENAME_LENGTH
);
947 mime_part_p
.extension
= value
;
948 mime_part_p
.extension
= Ustrrchr(value
,'.');
949 if (mime_part_p
.extension
== NULL
) {
950 /* file without extension, setting
951 NULL will use the default extension later */
952 mime_part_p
.extension
= NULL
;
955 struct file_extension
*this_extension
=
956 (struct file_extension
*)malloc(sizeof(file_extension
));
958 this_extension
->file_extension_string
=
959 (uschar
*)malloc(Ustrlen(mime_part_p
.extension
)+1);
960 Ustrcpy(this_extension
->file_extension_string
,
961 mime_part_p
.extension
+1);
962 this_extension
->next
= file_extensions
;
963 file_extensions
= this_extension
;
968 /* find a boundary and add it to the list, if present */
970 if (mime_header_find(line
,US
"boundary",&value
) == 2) {
971 struct boundary
*thisboundary
;
973 if (Ustrlen(value
) > MIME_SANITY_MAX_BOUNDARY_LENGTH
) {
974 mime_trigger_error(MIME_ERRORLEVEL_BOUNDARY_LENGTH
);
977 thisboundary
= (struct boundary
*)malloc(sizeof(boundary
));
978 thisboundary
->next
= boundaries
;
979 thisboundary
->boundary_string
= value
;
980 boundaries
= thisboundary
;
984 if (mime_part_p
.seen_content_type
== 0) {
985 mime_part_p
.seen_content_type
= 1;
988 mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS
);
990 /* ---------------------------------------------------------------------------- */
992 else if (strncmpic(US
"content-transfer-encoding:",line
,Ustrlen("content-transfer-encoding:")) == 0) {
993 /* ---------------------------- Content-Transfer-Encoding header -------------- */
995 if (mime_part_p
.seen_content_transfer_encoding
== 0) {
996 if (mime_header_find(line
,US
"base64",NULL
) > 0) {
997 mime_part_p
.seen_content_transfer_encoding
= MIME_DEMUX_MODE_BASE64
;
999 else if (mime_header_find(line
,US
"quoted-printable",NULL
) > 0) {
1000 mime_part_p
.seen_content_transfer_encoding
= MIME_DEMUX_MODE_QP
;
1003 mime_part_p
.seen_content_transfer_encoding
= MIME_DEMUX_MODE_PLAIN
;
1007 mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS
);
1009 /* ---------------------------------------------------------------------------- */
1011 else if (strncmpic(US
"content-disposition:",line
,Ustrlen("content-disposition:")) == 0) {
1012 /* ---------------------------- Content-Disposition header -------------------- */
1013 uschar
*value
= line
;
1015 if (mime_part_p
.seen_content_disposition
== 0) {
1016 mime_part_p
.seen_content_disposition
= 1;
1018 if (mime_header_find(line
,US
"filename",&value
) == 2) {
1019 if (Ustrlen(value
) > MIME_SANITY_MAX_FILENAME
)
1020 mime_trigger_error(MIME_ERRORLEVEL_FILENAME_LENGTH
);
1021 mime_part_p
.extension
= value
;
1022 mime_part_p
.extension
= Ustrrchr(value
,'.');
1023 if (mime_part_p
.extension
== NULL
) {
1024 /* file without extension, setting
1025 NULL will use the default extension later */
1026 mime_part_p
.extension
= NULL
;
1029 struct file_extension
*this_extension
=
1030 (struct file_extension
*)malloc(sizeof(file_extension
));
1032 this_extension
->file_extension_string
=
1033 (uschar
*)malloc(Ustrlen(mime_part_p
.extension
)+1);
1034 Ustrcpy(this_extension
->file_extension_string
,
1035 mime_part_p
.extension
+1);
1036 this_extension
->next
= file_extensions
;
1037 file_extensions
= this_extension
;
1042 mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS
);
1044 /* ---------------------------------------------------------------------------- */
1046 }; /* End of header checks */
1047 /* ------------------------------------------------ */
1050 /* -------------- non-header mode ----------------- */
1053 if (uu_mode
== MIME_UU_MODE_OFF
) {
1054 uschar uu_file_extension
[5];
1055 /* We are not currently decoding UUENCODE
1056 Check for possible UUENCODE start tag. */
1057 if (mime_check_uu_start(line
,uu_file_extension
,&has_tnef
)) {
1058 /* possible UUENCODING start detected.
1059 Set unconfirmed mode first. */
1060 uu_mode
= MIME_UU_MODE_UNCONFIRMED
;
1061 /* open new uu dump file */
1062 tmp
= mime_get_dump_file(uu_file_extension
, &uu_dump_file
, info
);
1073 if (uu_mode
== MIME_UU_MODE_UNCONFIRMED
) {
1074 /* We are in unconfirmed UUENCODE mode. */
1076 data_len
= uu_decode_line(line
,&data
,line_len
,info
);
1078 if (data_len
== -2) {
1079 /* temp error, turn off uudecode mode */
1080 if (uu_dump_file
!= NULL
) {
1081 (void)fclose(uu_dump_file
); uu_dump_file
= NULL
;
1083 uu_mode
= MIME_UU_MODE_OFF
;
1086 else if (data_len
== -1) {
1087 if (uu_dump_file
!= NULL
) {
1088 (void)fclose(uu_dump_file
); uu_dump_file
= NULL
;
1090 uu_mode
= MIME_UU_MODE_OFF
;
1093 else if (data_len
> 0) {
1094 /* we have at least decoded a valid byte
1095 turn on confirmed mode */
1096 uu_mode
= MIME_UU_MODE_CONFIRMED
;
1099 else if (uu_mode
== MIME_UU_MODE_CONFIRMED
) {
1100 /* If we are in confirmed UU mode,
1101 check for single "end" tag on line */
1102 if ((strncmpic(line
,US
"end",3) == 0) && (line
[3] < 32)) {
1103 if (uu_dump_file
!= NULL
) {
1104 (void)fclose(uu_dump_file
); uu_dump_file
= NULL
;
1106 uu_mode
= MIME_UU_MODE_OFF
;
1109 data_len
= uu_decode_line(line
,&data
,line_len
,info
);
1110 if (data_len
== -2) {
1111 /* temp error, turn off uudecode mode */
1112 if (uu_dump_file
!= NULL
) {
1113 (void)fclose(uu_dump_file
); uu_dump_file
= NULL
;
1115 uu_mode
= MIME_UU_MODE_OFF
;
1118 else if (data_len
== -1) {
1119 /* skip this line */
1125 /* write data to dump file, if available */
1127 if (fwrite(data
,1,data_len
,uu_dump_file
) < data_len
) {
1129 (void)string_format(info
, 1024,"short write on uudecode dump file");
1136 if (mime_demux_mode
!= MIME_DEMUX_MODE_SCANNING
) {
1137 /* Non-scanning and Non-header mode. That means
1138 we are currently decoding data to the dump
1141 /* Check for a known boundary. */
1142 tmp
= mime_check_boundary(line
,boundaries
);
1144 /* We have hit a known start boundary.
1145 That will put us back in header mode. */
1146 mime_demux_mode
= MIME_DEMUX_MODE_MIME_HEADERS
;
1147 if (mime_dump_file
!= NULL
) {
1148 /* if the attachment was a RFC822 message, recurse into it */
1151 rewind(mime_dump_file
);
1152 mime_demux(mime_dump_file
,info
);
1155 (void)fclose(mime_dump_file
); mime_dump_file
= NULL
;
1158 else if (tmp
== 2) {
1159 /* We have hit a known end boundary.
1160 That puts us into scanning mode, which will end when we hit another known start boundary */
1161 mime_demux_mode
= MIME_DEMUX_MODE_SCANNING
;
1162 if (mime_dump_file
!= NULL
) {
1163 /* if the attachment was a RFC822 message, recurse into it */
1166 rewind(mime_dump_file
);
1167 mime_demux(mime_dump_file
,info
);
1170 (void)fclose(mime_dump_file
); mime_dump_file
= NULL
;
1177 /* decode the line with the appropriate method */
1178 if (mime_demux_mode
== MIME_DEMUX_MODE_PLAIN
) {
1179 /* in plain mode, just dump the line */
1181 data_len
= line_len
;
1183 else if ( (mime_demux_mode
== MIME_DEMUX_MODE_QP
) || (mime_demux_mode
== MIME_DEMUX_MODE_BASE64
) ) {
1184 data_len
= mime_decode_line(mime_demux_mode
,line
,&data
,line_len
,info
);
1186 /* Error reported from the line decoder. */
1191 /* write data to dump file */
1193 if (fwrite(data
,1,data_len
,mime_dump_file
) < data_len
) {
1195 (void)string_format(info
, 1024,"short write on dump file");
1204 /* Scanning mode. We end up here after a end boundary.
1205 This will usually be at the end of a message or at
1206 the end of a MIME container.
1207 We need to look for another start boundary to get
1208 back into header mode. */
1209 if (mime_check_boundary(line
,boundaries
) == 1) {
1210 mime_demux_mode
= MIME_DEMUX_MODE_MIME_HEADERS
;
1214 /* ------------------------------------------------ */
1217 /* ----------------------- end demux loop ----------------------- */
1219 /* close files, they could still be open */
1220 if (mime_dump_file
!= NULL
)
1221 (void)fclose(mime_dump_file
);
1222 if (uu_dump_file
!= NULL
)
1223 (void)fclose(uu_dump_file
);
1225 /* release line buffer */
1228 /* FIXME: release boundary buffers.
1229 Not too much of a problem since
1230 this instance of exim is not resident. */
1233 uschar file_name
[1024];
1234 /* at least one file could be TNEF encoded.
1235 attempt to send all decoded files thru the TNEF decoder */
1237 (void)string_format(file_name
,1024,"%s/scan/%s",spool_directory
,message_id
);
1238 /* Removed FTTB. We need to decide on TNEF inclusion */
1239 /* mime_unpack_tnef(file_name); */