Lines 1-1191
Link Here
|
1 |
X-Git-Url: http://git.exim.org/exim.git/blobdiff_plain/1bd0d12bcbf4f51bd78c60d5bae01f1ff38c5a84..4fd5d2bf25195969b9c6a6c23a59c495400ece8d:/src/src/mime.c |
|
|
2 |
|
3 |
diff --git a/src/src/mime.c b/src/src/mime.c |
4 |
index 2233dac..95d3da4 100644 |
5 |
--- src/mime.c |
6 |
+++ src/mime.c |
7 |
@@ -6,7 +6,7 @@ |
8 |
/* License: GPL */ |
9 |
|
10 |
#include "exim.h" |
11 |
-#ifdef WITH_CONTENT_SCAN |
12 |
+#ifdef WITH_CONTENT_SCAN /* entire file */ |
13 |
#include "mime.h" |
14 |
#include <sys/stat.h> |
15 |
|
16 |
@@ -21,7 +21,9 @@ uschar *mime_current_boundary = NULL; |
17 |
give info on detected "problems" in MIME |
18 |
encodings. Those are defined in mime.h. */ |
19 |
|
20 |
-void mime_set_anomaly(int level, const char *text) { |
21 |
+void |
22 |
+mime_set_anomaly(int level, const char *text) |
23 |
+{ |
24 |
mime_anomaly_level = level; |
25 |
mime_anomaly_text = CUS text; |
26 |
} |
27 |
@@ -39,36 +41,37 @@ void mime_set_anomaly(int level, const char *text) { |
28 |
0-255 - char to write |
29 |
*/ |
30 |
|
31 |
-uschar *mime_decode_qp_char(uschar *qp_p, int *c) { |
32 |
- uschar *initial_pos = qp_p; |
33 |
+uschar * |
34 |
+mime_decode_qp_char(uschar *qp_p, int *c) |
35 |
+{ |
36 |
+uschar *initial_pos = qp_p; |
37 |
+ |
38 |
+/* advance one char */ |
39 |
+qp_p++; |
40 |
+ |
41 |
+/* Check for two hex digits and decode them */ |
42 |
+if (isxdigit(*qp_p) && isxdigit(qp_p[1])) |
43 |
+ { |
44 |
+ /* Do hex conversion */ |
45 |
+ *c = (isdigit(*qp_p) ? *qp_p - '0' : toupper(*qp_p) - 'A' + 10) <<4; |
46 |
+ qp_p++; |
47 |
+ *c |= isdigit(*qp_p) ? *qp_p - '0' : toupper(*qp_p) - 'A' + 10; |
48 |
+ return qp_p + 1; |
49 |
+ } |
50 |
|
51 |
- /* advance one char */ |
52 |
+/* tab or whitespace may follow just ignore it if it precedes \n */ |
53 |
+while (*qp_p == '\t' || *qp_p == ' ' || *qp_p == '\r') |
54 |
qp_p++; |
55 |
|
56 |
- /* Check for two hex digits and decode them */ |
57 |
- if (isxdigit(*qp_p) && isxdigit(qp_p[1])) { |
58 |
- /* Do hex conversion */ |
59 |
- if (isdigit(*qp_p)) {*c = *qp_p - '0';} |
60 |
- else {*c = toupper(*qp_p) - 'A' + 10;}; |
61 |
- *c <<= 4; |
62 |
- if (isdigit(qp_p[1])) {*c |= qp_p[1] - '0';} |
63 |
- else {*c |= toupper(qp_p[1]) - 'A' + 10;}; |
64 |
- return qp_p + 2; |
65 |
- }; |
66 |
- |
67 |
- /* tab or whitespace may follow just ignore it if it precedes \n */ |
68 |
- while (*qp_p == '\t' || *qp_p == ' ' || *qp_p == '\r') |
69 |
- qp_p++; |
70 |
- |
71 |
- if (*qp_p == '\n') { |
72 |
- /* hit soft line break */ |
73 |
- *c = -1; |
74 |
- return qp_p; |
75 |
- }; |
76 |
- |
77 |
- /* illegal char here */ |
78 |
- *c = -2; |
79 |
- return initial_pos; |
80 |
+if (*qp_p == '\n') /* hit soft line break */ |
81 |
+ { |
82 |
+ *c = -1; |
83 |
+ return qp_p; |
84 |
+ } |
85 |
+ |
86 |
+/* illegal char here */ |
87 |
+*c = -2; |
88 |
+return initial_pos; |
89 |
} |
90 |
|
91 |
|
92 |
@@ -79,18 +82,19 @@ mime_decode_asis(FILE* in, FILE* out, uschar* boundary) |
93 |
ssize_t len, size = 0; |
94 |
uschar buffer[MIME_MAX_LINE_LENGTH]; |
95 |
|
96 |
- while(fgets(CS buffer, MIME_MAX_LINE_LENGTH, mime_stream) != NULL) { |
97 |
+ while(fgets(CS buffer, MIME_MAX_LINE_LENGTH, mime_stream) != NULL) |
98 |
+ { |
99 |
if (boundary != NULL |
100 |
- && Ustrncmp(buffer, "--", 2) == 0 |
101 |
- && Ustrncmp((buffer+2), boundary, Ustrlen(boundary)) == 0 |
102 |
- ) |
103 |
+ && Ustrncmp(buffer, "--", 2) == 0 |
104 |
+ && Ustrncmp((buffer+2), boundary, Ustrlen(boundary)) == 0 |
105 |
+ ) |
106 |
break; |
107 |
|
108 |
len = Ustrlen(buffer); |
109 |
if (fwrite(buffer, 1, (size_t)len, out) < len) |
110 |
return -1; |
111 |
size += len; |
112 |
- } /* while */ |
113 |
+ } /* while */ |
114 |
return size; |
115 |
} |
116 |
|
117 |
@@ -107,26 +111,29 @@ mime_decode_base64(FILE* in, FILE* out, uschar* boundary) |
118 |
opos = obuf; |
119 |
|
120 |
while (Ufgets(ibuf, MIME_MAX_LINE_LENGTH, in) != NULL) |
121 |
- { |
122 |
+ { |
123 |
if (boundary != NULL |
124 |
- && Ustrncmp(ibuf, "--", 2) == 0 |
125 |
- && Ustrncmp((ibuf+2), boundary, Ustrlen(boundary)) == 0 |
126 |
- ) |
127 |
+ && Ustrncmp(ibuf, "--", 2) == 0 |
128 |
+ && Ustrncmp((ibuf+2), boundary, Ustrlen(boundary)) == 0 |
129 |
+ ) |
130 |
break; |
131 |
|
132 |
- for (ipos = ibuf ; *ipos != '\r' && *ipos != '\n' && *ipos != 0; ++ipos) { |
133 |
- /* skip padding */ |
134 |
- if (*ipos == '=') { |
135 |
+ for (ipos = ibuf ; *ipos != '\r' && *ipos != '\n' && *ipos != 0; ++ipos) |
136 |
+ { |
137 |
+ if (*ipos == '=') /* skip padding */ |
138 |
+ { |
139 |
++bytestate; |
140 |
continue; |
141 |
- } |
142 |
- /* skip bad characters */ |
143 |
- if (mime_b64[*ipos] == 128) { |
144 |
+ } |
145 |
+ if (mime_b64[*ipos] == 128) /* skip bad characters */ |
146 |
+ { |
147 |
mime_set_anomaly(MIME_ANOMALY_BROKEN_BASE64); |
148 |
continue; |
149 |
- } |
150 |
+ } |
151 |
+ |
152 |
/* simple state-machine */ |
153 |
- switch((bytestate++) & 3) { |
154 |
+ switch((bytestate++) & 3) |
155 |
+ { |
156 |
case 0: |
157 |
*opos = mime_b64[*ipos] << 2; |
158 |
break; |
159 |
@@ -144,27 +151,28 @@ mime_decode_base64(FILE* in, FILE* out, uschar* boundary) |
160 |
*opos |= mime_b64[*ipos]; |
161 |
++opos; |
162 |
break; |
163 |
- } /* switch */ |
164 |
- } /* for */ |
165 |
+ } /* switch */ |
166 |
+ } /* for */ |
167 |
+ |
168 |
/* something to write? */ |
169 |
len = opos - obuf; |
170 |
- if (len > 0) { |
171 |
- if (fwrite(obuf, 1, len, out) != len) |
172 |
- return -1; /* error */ |
173 |
+ if (len > 0) |
174 |
+ { |
175 |
+ if (fwrite(obuf, 1, len, out) != len) return -1; /* error */ |
176 |
size += len; |
177 |
/* copy incomplete last byte to start of obuf, where we continue */ |
178 |
if ((bytestate & 3) != 0) |
179 |
*obuf = *opos; |
180 |
opos = obuf; |
181 |
- } |
182 |
- } /* while */ |
183 |
+ } |
184 |
+ } /* while */ |
185 |
|
186 |
/* write out last byte if it was incomplete */ |
187 |
- if (bytestate & 3) { |
188 |
- if (fwrite(obuf, 1, 1, out) != 1) |
189 |
- return -1; |
190 |
- ++size; |
191 |
- } |
192 |
+ if (bytestate & 3) |
193 |
+ { |
194 |
+ if (fwrite(obuf, 1, 1, out) != 1) return -1; |
195 |
+ ++size; |
196 |
+ } |
197 |
|
198 |
return size; |
199 |
} |
200 |
@@ -174,219 +182,232 @@ mime_decode_base64(FILE* in, FILE* out, uschar* boundary) |
201 |
static ssize_t |
202 |
mime_decode_qp(FILE* in, FILE* out, uschar* boundary) |
203 |
{ |
204 |
- uschar ibuf[MIME_MAX_LINE_LENGTH], obuf[MIME_MAX_LINE_LENGTH]; |
205 |
- uschar *ipos, *opos; |
206 |
- ssize_t len, size = 0; |
207 |
+uschar ibuf[MIME_MAX_LINE_LENGTH], obuf[MIME_MAX_LINE_LENGTH]; |
208 |
+uschar *ipos, *opos; |
209 |
+ssize_t len, size = 0; |
210 |
|
211 |
- while (fgets(CS ibuf, MIME_MAX_LINE_LENGTH, in) != NULL) |
212 |
+while (fgets(CS ibuf, MIME_MAX_LINE_LENGTH, in) != NULL) |
213 |
{ |
214 |
- if (boundary != NULL |
215 |
- && Ustrncmp(ibuf, "--", 2) == 0 |
216 |
- && Ustrncmp((ibuf+2), boundary, Ustrlen(boundary)) == 0 |
217 |
- ) |
218 |
- break; /* todo: check for missing boundary */ |
219 |
+ if (boundary != NULL |
220 |
+ && Ustrncmp(ibuf, "--", 2) == 0 |
221 |
+ && Ustrncmp((ibuf+2), boundary, Ustrlen(boundary)) == 0 |
222 |
+ ) |
223 |
+ break; /* todo: check for missing boundary */ |
224 |
|
225 |
- ipos = ibuf; |
226 |
- opos = obuf; |
227 |
- |
228 |
- while (*ipos != 0) { |
229 |
- if (*ipos == '=') { |
230 |
- int decode_qp_result; |
231 |
- |
232 |
- ipos = mime_decode_qp_char(ipos, &decode_qp_result); |
233 |
+ ipos = ibuf; |
234 |
+ opos = obuf; |
235 |
|
236 |
- if (decode_qp_result == -2) { |
237 |
- /* Error from decoder. ipos is unchanged. */ |
238 |
- mime_set_anomaly(MIME_ANOMALY_BROKEN_QP); |
239 |
- *opos = '='; |
240 |
- ++opos; |
241 |
- ++ipos; |
242 |
- } |
243 |
- else if (decode_qp_result == -1) { |
244 |
- break; |
245 |
- } |
246 |
- else if (decode_qp_result >= 0) { |
247 |
- *opos = decode_qp_result; |
248 |
- ++opos; |
249 |
- } |
250 |
+ while (*ipos != 0) |
251 |
+ { |
252 |
+ if (*ipos == '=') |
253 |
+ { |
254 |
+ int decode_qp_result; |
255 |
+ |
256 |
+ ipos = mime_decode_qp_char(ipos, &decode_qp_result); |
257 |
+ |
258 |
+ if (decode_qp_result == -2) |
259 |
+ { |
260 |
+ /* Error from decoder. ipos is unchanged. */ |
261 |
+ mime_set_anomaly(MIME_ANOMALY_BROKEN_QP); |
262 |
+ *opos = '='; |
263 |
+ ++opos; |
264 |
+ ++ipos; |
265 |
+ } |
266 |
+ else if (decode_qp_result == -1) |
267 |
+ break; |
268 |
+ else if (decode_qp_result >= 0) |
269 |
+ { |
270 |
+ *opos = decode_qp_result; |
271 |
+ ++opos; |
272 |
+ } |
273 |
} |
274 |
- else { |
275 |
- *opos = *ipos; |
276 |
- ++opos; |
277 |
- ++ipos; |
278 |
+ else |
279 |
+ { |
280 |
+ *opos = *ipos; |
281 |
+ ++opos; |
282 |
+ ++ipos; |
283 |
} |
284 |
} |
285 |
- /* something to write? */ |
286 |
- len = opos - obuf; |
287 |
- if (len > 0) { |
288 |
- if (fwrite(obuf, 1, len, out) != len) |
289 |
- return -1; /* error */ |
290 |
- size += len; |
291 |
+ /* something to write? */ |
292 |
+ len = opos - obuf; |
293 |
+ if (len > 0) |
294 |
+ { |
295 |
+ if (fwrite(obuf, 1, len, out) != len) return -1; /* error */ |
296 |
+ size += len; |
297 |
} |
298 |
} |
299 |
- return size; |
300 |
+return size; |
301 |
} |
302 |
|
303 |
|
304 |
-FILE *mime_get_decode_file(uschar *pname, uschar *fname) { |
305 |
- FILE *f = NULL; |
306 |
- uschar *filename; |
307 |
+FILE * |
308 |
+mime_get_decode_file(uschar *pname, uschar *fname) |
309 |
+{ |
310 |
+FILE *f = NULL; |
311 |
+uschar *filename; |
312 |
|
313 |
- filename = (uschar *)malloc(2048); |
314 |
+filename = (uschar *)malloc(2048); |
315 |
|
316 |
- if ((pname != NULL) && (fname != NULL)) { |
317 |
- (void)string_format(filename, 2048, "%s/%s", pname, fname); |
318 |
- f = modefopen(filename,"wb+",SPOOL_MODE); |
319 |
- } |
320 |
- else if (pname == NULL) { |
321 |
- f = modefopen(fname,"wb+",SPOOL_MODE); |
322 |
+if (pname && fname) |
323 |
+ { |
324 |
+ (void)string_format(filename, 2048, "%s/%s", pname, fname); |
325 |
+ f = modefopen(filename,"wb+",SPOOL_MODE); |
326 |
} |
327 |
- else if (fname == NULL) { |
328 |
- int file_nr = 0; |
329 |
- int result = 0; |
330 |
+else if (!pname) |
331 |
+ f = modefopen(fname,"wb+",SPOOL_MODE); |
332 |
+else if (!fname) |
333 |
+ { |
334 |
+ int file_nr = 0; |
335 |
+ int result = 0; |
336 |
+ |
337 |
+ /* must find first free sequential filename */ |
338 |
+ do |
339 |
+ { |
340 |
+ struct stat mystat; |
341 |
+ (void)string_format(filename, 2048, |
342 |
+ "%s/%s-%05u", pname, message_id, file_nr++); |
343 |
+ /* security break */ |
344 |
+ if (file_nr >= 1024) |
345 |
+ break; |
346 |
+ result = stat(CS filename, &mystat); |
347 |
+ } while(result != -1); |
348 |
|
349 |
- /* must find first free sequential filename */ |
350 |
- do { |
351 |
- struct stat mystat; |
352 |
- (void)string_format(filename,2048,"%s/%s-%05u", pname, message_id, file_nr); |
353 |
- file_nr++; |
354 |
- /* security break */ |
355 |
- if (file_nr >= 1024) |
356 |
- break; |
357 |
- result = stat(CS filename,&mystat); |
358 |
- } |
359 |
- while(result != -1); |
360 |
- f = modefopen(filename,"wb+",SPOOL_MODE); |
361 |
- }; |
362 |
+ f = modefopen(filename, "wb+", SPOOL_MODE); |
363 |
+ } |
364 |
|
365 |
- /* set expansion variable */ |
366 |
- mime_decoded_filename = filename; |
367 |
+/* set expansion variable */ |
368 |
+mime_decoded_filename = filename; |
369 |
|
370 |
- return f; |
371 |
+return f; |
372 |
} |
373 |
|
374 |
|
375 |
-int mime_decode(uschar **listptr) { |
376 |
- int sep = 0; |
377 |
- uschar *list = *listptr; |
378 |
- uschar *option; |
379 |
- uschar option_buffer[1024]; |
380 |
- uschar decode_path[1024]; |
381 |
- FILE *decode_file = NULL; |
382 |
- long f_pos = 0; |
383 |
- ssize_t size_counter = 0; |
384 |
- ssize_t (*decode_function)(FILE*, FILE*, uschar*); |
385 |
- |
386 |
- if (mime_stream == NULL) |
387 |
+int |
388 |
+mime_decode(uschar **listptr) |
389 |
+{ |
390 |
+int sep = 0; |
391 |
+uschar *list = *listptr; |
392 |
+uschar *option; |
393 |
+uschar option_buffer[1024]; |
394 |
+uschar decode_path[1024]; |
395 |
+FILE *decode_file = NULL; |
396 |
+long f_pos = 0; |
397 |
+ssize_t size_counter = 0; |
398 |
+ssize_t (*decode_function)(FILE*, FILE*, uschar*); |
399 |
+ |
400 |
+if (mime_stream == NULL) |
401 |
+ return FAIL; |
402 |
+ |
403 |
+f_pos = ftell(mime_stream); |
404 |
+ |
405 |
+/* build default decode path (will exist since MBOX must be spooled up) */ |
406 |
+(void)string_format(decode_path,1024,"%s/scan/%s",spool_directory,message_id); |
407 |
+ |
408 |
+/* try to find 1st option */ |
409 |
+if ((option = string_nextinlist(&list, &sep, |
410 |
+ option_buffer, |
411 |
+ sizeof(option_buffer))) != NULL) |
412 |
+ { |
413 |
+ /* parse 1st option */ |
414 |
+ if ( (Ustrcmp(option,"false") == 0) || (Ustrcmp(option,"0") == 0) ) |
415 |
+ /* explicitly no decoding */ |
416 |
return FAIL; |
417 |
|
418 |
- f_pos = ftell(mime_stream); |
419 |
- |
420 |
- /* build default decode path (will exist since MBOX must be spooled up) */ |
421 |
- (void)string_format(decode_path,1024,"%s/scan/%s",spool_directory,message_id); |
422 |
- |
423 |
- /* try to find 1st option */ |
424 |
- if ((option = string_nextinlist(&list, &sep, |
425 |
- option_buffer, |
426 |
- sizeof(option_buffer))) != NULL) { |
427 |
+ if (Ustrcmp(option,"default") == 0) |
428 |
+ /* explicit default path + file names */ |
429 |
+ goto DEFAULT_PATH; |
430 |
|
431 |
- /* parse 1st option */ |
432 |
- if ( (Ustrcmp(option,"false") == 0) || (Ustrcmp(option,"0") == 0) ) { |
433 |
- /* explicitly no decoding */ |
434 |
- return FAIL; |
435 |
- }; |
436 |
+ if (option[0] == '/') |
437 |
+ { |
438 |
+ struct stat statbuf; |
439 |
|
440 |
- if (Ustrcmp(option,"default") == 0) { |
441 |
- /* explicit default path + file names */ |
442 |
- goto DEFAULT_PATH; |
443 |
- }; |
444 |
+ memset(&statbuf,0,sizeof(statbuf)); |
445 |
|
446 |
- if (option[0] == '/') { |
447 |
- struct stat statbuf; |
448 |
- |
449 |
- memset(&statbuf,0,sizeof(statbuf)); |
450 |
- |
451 |
- /* assume either path or path+file name */ |
452 |
- if ( (stat(CS option, &statbuf) == 0) && S_ISDIR(statbuf.st_mode) ) |
453 |
- /* is directory, use it as decode_path */ |
454 |
- decode_file = mime_get_decode_file(option, NULL); |
455 |
- else |
456 |
- /* does not exist or is a file, use as full file name */ |
457 |
- decode_file = mime_get_decode_file(NULL, option); |
458 |
- } |
459 |
+ /* assume either path or path+file name */ |
460 |
+ if ( (stat(CS option, &statbuf) == 0) && S_ISDIR(statbuf.st_mode) ) |
461 |
+ /* is directory, use it as decode_path */ |
462 |
+ decode_file = mime_get_decode_file(option, NULL); |
463 |
else |
464 |
- /* assume file name only, use default path */ |
465 |
- decode_file = mime_get_decode_file(decode_path, option); |
466 |
- } |
467 |
- else |
468 |
- /* no option? patch default path */ |
469 |
- DEFAULT_PATH: decode_file = mime_get_decode_file(decode_path, NULL); |
470 |
- |
471 |
- if (decode_file == NULL) |
472 |
- return DEFER; |
473 |
- |
474 |
- /* decode according to mime type */ |
475 |
- if (mime_content_transfer_encoding == NULL) |
476 |
- /* no encoding, dump as-is */ |
477 |
- decode_function = mime_decode_asis; |
478 |
- else if (Ustrcmp(mime_content_transfer_encoding, "base64") == 0) |
479 |
- decode_function = mime_decode_base64; |
480 |
- else if (Ustrcmp(mime_content_transfer_encoding, "quoted-printable") == 0) |
481 |
- decode_function = mime_decode_qp; |
482 |
+ /* does not exist or is a file, use as full file name */ |
483 |
+ decode_file = mime_get_decode_file(NULL, option); |
484 |
+ } |
485 |
else |
486 |
- /* unknown encoding type, just dump as-is */ |
487 |
- decode_function = mime_decode_asis; |
488 |
+ /* assume file name only, use default path */ |
489 |
+ decode_file = mime_get_decode_file(decode_path, option); |
490 |
+ } |
491 |
+else |
492 |
+ { |
493 |
+ /* no option? patch default path */ |
494 |
+DEFAULT_PATH: |
495 |
+ decode_file = mime_get_decode_file(decode_path, NULL); |
496 |
+ } |
497 |
|
498 |
- size_counter = decode_function(mime_stream, decode_file, mime_current_boundary); |
499 |
+if (!decode_file) |
500 |
+ return DEFER; |
501 |
|
502 |
- clearerr(mime_stream); |
503 |
- fseek(mime_stream, f_pos, SEEK_SET); |
504 |
+/* decode according to mime type */ |
505 |
+decode_function = |
506 |
+ !mime_content_transfer_encoding |
507 |
+ ? mime_decode_asis /* no encoding, dump as-is */ |
508 |
+ : Ustrcmp(mime_content_transfer_encoding, "base64") == 0 |
509 |
+ ? mime_decode_base64 |
510 |
+ : Ustrcmp(mime_content_transfer_encoding, "quoted-printable") == 0 |
511 |
+ ? mime_decode_qp |
512 |
+ : mime_decode_asis; /* unknown encoding type, just dump as-is */ |
513 |
|
514 |
- if (fclose(decode_file) != 0 || size_counter < 0) |
515 |
- return DEFER; |
516 |
+size_counter = decode_function(mime_stream, decode_file, mime_current_boundary); |
517 |
|
518 |
- /* round up to the next KiB */ |
519 |
- mime_content_size = (size_counter + 1023) / 1024; |
520 |
+clearerr(mime_stream); |
521 |
+fseek(mime_stream, f_pos, SEEK_SET); |
522 |
|
523 |
- return OK; |
524 |
-} |
525 |
+if (fclose(decode_file) != 0 || size_counter < 0) |
526 |
+ return DEFER; |
527 |
|
528 |
-int mime_get_header(FILE *f, uschar *header) { |
529 |
- int c = EOF; |
530 |
- int done = 0; |
531 |
- int header_value_mode = 0; |
532 |
- int header_open_brackets = 0; |
533 |
- int num_copied = 0; |
534 |
+/* round up to the next KiB */ |
535 |
+mime_content_size = (size_counter + 1023) / 1024; |
536 |
|
537 |
- while(!done) { |
538 |
+return OK; |
539 |
+} |
540 |
|
541 |
- c = fgetc(f); |
542 |
- if (c == EOF) break; |
543 |
+int |
544 |
+mime_get_header(FILE *f, uschar *header) |
545 |
+{ |
546 |
+int c = EOF; |
547 |
+int done = 0; |
548 |
+int header_value_mode = 0; |
549 |
+int header_open_brackets = 0; |
550 |
+int num_copied = 0; |
551 |
|
552 |
- /* always skip CRs */ |
553 |
- if (c == '\r') continue; |
554 |
+while(!done) |
555 |
+ { |
556 |
+ if ((c = fgetc(f)) == EOF) break; |
557 |
+ |
558 |
+ /* always skip CRs */ |
559 |
+ if (c == '\r') continue; |
560 |
+ |
561 |
+ if (c == '\n') |
562 |
+ { |
563 |
+ if (num_copied > 0) |
564 |
+ { |
565 |
+ /* look if next char is '\t' or ' ' */ |
566 |
+ if ((c = fgetc(f)) == EOF) break; |
567 |
+ if ( (c == '\t') || (c == ' ') ) continue; |
568 |
+ (void)ungetc(c,f); |
569 |
+ } |
570 |
+ /* end of the header, terminate with ';' */ |
571 |
+ c = ';'; |
572 |
+ done = 1; |
573 |
+ } |
574 |
|
575 |
- if (c == '\n') { |
576 |
- if (num_copied > 0) { |
577 |
- /* look if next char is '\t' or ' ' */ |
578 |
- c = fgetc(f); |
579 |
- if (c == EOF) break; |
580 |
- if ( (c == '\t') || (c == ' ') ) continue; |
581 |
- (void)ungetc(c,f); |
582 |
- }; |
583 |
- /* end of the header, terminate with ';' */ |
584 |
- c = ';'; |
585 |
- done = 1; |
586 |
- }; |
587 |
- |
588 |
- /* skip control characters */ |
589 |
- if (c < 32) continue; |
590 |
- |
591 |
- if (header_value_mode) { |
592 |
- /* --------- value mode ----------- */ |
593 |
- /* skip leading whitespace */ |
594 |
- if ( ((c == '\t') || (c == ' ')) && (header_value_mode == 1) ) |
595 |
- continue; |
596 |
+ /* skip control characters */ |
597 |
+ if (c < 32) continue; |
598 |
+ |
599 |
+ if (header_value_mode) |
600 |
+ { |
601 |
+ /* --------- value mode ----------- */ |
602 |
+ /* skip leading whitespace */ |
603 |
+ if ( ((c == '\t') || (c == ' ')) && (header_value_mode == 1) ) |
604 |
+ continue; |
605 |
|
606 |
/* we have hit a non-whitespace char, start copying value data */ |
607 |
header_value_mode = 2; |
608 |
@@ -400,295 +421,320 @@ int mime_get_header(FILE *f, uschar *header) { |
609 |
}; |
610 |
/* -------------------------------- */ |
611 |
} |
612 |
- else { |
613 |
- /* -------- non-value mode -------- */ |
614 |
- /* skip whitespace + tabs */ |
615 |
- if ( (c == ' ') || (c == '\t') ) |
616 |
- continue; |
617 |
- if (c == '\\') { |
618 |
- /* quote next char. can be used |
619 |
- to escape brackets. */ |
620 |
- c = fgetc(f); |
621 |
- if (c == EOF) break; |
622 |
+ else |
623 |
+ { |
624 |
+ /* -------- non-value mode -------- */ |
625 |
+ /* skip whitespace + tabs */ |
626 |
+ if ( (c == ' ') || (c == '\t') ) |
627 |
+ continue; |
628 |
+ if (c == '\\') |
629 |
+ { |
630 |
+ /* quote next char. can be used |
631 |
+ to escape brackets. */ |
632 |
+ if ((c = fgetc(f)) == EOF) break; |
633 |
} |
634 |
- else if (c == '(') { |
635 |
- header_open_brackets++; |
636 |
- continue; |
637 |
+ else if (c == '(') |
638 |
+ { |
639 |
+ header_open_brackets++; |
640 |
+ continue; |
641 |
} |
642 |
- else if ((c == ')') && header_open_brackets) { |
643 |
- header_open_brackets--; |
644 |
- continue; |
645 |
+ else if ((c == ')') && header_open_brackets) |
646 |
+ { |
647 |
+ header_open_brackets--; |
648 |
+ continue; |
649 |
} |
650 |
- else if ( (c == '=') && !header_open_brackets ) { |
651 |
- /* enter value mode */ |
652 |
- header_value_mode = 1; |
653 |
- }; |
654 |
+ else if ( (c == '=') && !header_open_brackets ) /* enter value mode */ |
655 |
+ header_value_mode = 1; |
656 |
|
657 |
- /* skip chars while we are in a comment */ |
658 |
- if (header_open_brackets > 0) |
659 |
- continue; |
660 |
- /* -------------------------------- */ |
661 |
- }; |
662 |
+ /* skip chars while we are in a comment */ |
663 |
+ if (header_open_brackets > 0) |
664 |
+ continue; |
665 |
+ /* -------------------------------- */ |
666 |
+ } |
667 |
|
668 |
- /* copy the char to the buffer */ |
669 |
- header[num_copied] = (uschar)c; |
670 |
- /* raise counter */ |
671 |
- num_copied++; |
672 |
+ /* copy the char to the buffer */ |
673 |
+ header[num_copied++] = (uschar)c; |
674 |
|
675 |
- /* break if header buffer is full */ |
676 |
- if (num_copied > MIME_MAX_HEADER_SIZE-1) { |
677 |
- done = 1; |
678 |
- }; |
679 |
- }; |
680 |
+ /* break if header buffer is full */ |
681 |
+ if (num_copied > MIME_MAX_HEADER_SIZE-1) |
682 |
+ done = 1; |
683 |
+ } |
684 |
|
685 |
- if ((num_copied > 0) && (header[num_copied-1] != ';')) { |
686 |
- header[num_copied-1] = ';'; |
687 |
- }; |
688 |
+if ((num_copied > 0) && (header[num_copied-1] != ';')) |
689 |
+ header[num_copied-1] = ';'; |
690 |
|
691 |
- /* 0-terminate */ |
692 |
- header[num_copied] = '\0'; |
693 |
+/* 0-terminate */ |
694 |
+header[num_copied] = '\0'; |
695 |
|
696 |
- /* return 0 for EOF or empty line */ |
697 |
- if ((c == EOF) || (num_copied == 1)) |
698 |
- return 0; |
699 |
- else |
700 |
- return 1; |
701 |
+/* return 0 for EOF or empty line */ |
702 |
+if ((c == EOF) || (num_copied == 1)) |
703 |
+ return 0; |
704 |
+else |
705 |
+ return 1; |
706 |
} |
707 |
|
708 |
|
709 |
-int mime_acl_check(uschar *acl, FILE *f, struct mime_boundary_context *context, |
710 |
- uschar **user_msgptr, uschar **log_msgptr) { |
711 |
- int rc = OK; |
712 |
- uschar *header = NULL; |
713 |
- struct mime_boundary_context nested_context; |
714 |
- |
715 |
- /* reserve a line buffer to work in */ |
716 |
- header = (uschar *)malloc(MIME_MAX_HEADER_SIZE+1); |
717 |
- if (header == NULL) { |
718 |
- log_write(0, LOG_PANIC, |
719 |
- "MIME ACL: can't allocate %d bytes of memory.", MIME_MAX_HEADER_SIZE+1); |
720 |
- return DEFER; |
721 |
- }; |
722 |
- |
723 |
- /* Not actually used at the moment, but will be vital to fixing |
724 |
- * some RFC 2046 nonconformance later... */ |
725 |
- nested_context.parent = context; |
726 |
- |
727 |
- /* loop through parts */ |
728 |
- while(1) { |
729 |
- |
730 |
- /* reset all per-part mime variables */ |
731 |
- mime_anomaly_level = 0; |
732 |
- mime_anomaly_text = NULL; |
733 |
- mime_boundary = NULL; |
734 |
- mime_charset = NULL; |
735 |
- mime_decoded_filename = NULL; |
736 |
- mime_filename = NULL; |
737 |
- mime_content_description = NULL; |
738 |
- mime_content_disposition = NULL; |
739 |
- mime_content_id = NULL; |
740 |
- mime_content_transfer_encoding = NULL; |
741 |
- mime_content_type = NULL; |
742 |
- mime_is_multipart = 0; |
743 |
- mime_content_size = 0; |
744 |
- |
745 |
- /* |
746 |
- If boundary is null, we assume that *f is positioned on the start of headers (for example, |
747 |
- at the very beginning of a message. |
748 |
- If a boundary is given, we must first advance to it to reach the start of the next header |
749 |
- block. |
750 |
- */ |
751 |
- |
752 |
- /* NOTE -- there's an error here -- RFC2046 specifically says to |
753 |
- * check for outer boundaries. This code doesn't do that, and |
754 |
- * I haven't fixed this. |
755 |
- * |
756 |
- * (I have moved partway towards adding support, however, by adding |
757 |
- * a "parent" field to my new boundary-context structure.) |
758 |
- */ |
759 |
- if (context != NULL) { |
760 |
- while(fgets(CS header, MIME_MAX_HEADER_SIZE, f) != NULL) { |
761 |
- /* boundary line must start with 2 dashes */ |
762 |
- if (Ustrncmp(header,"--",2) == 0) { |
763 |
- if (Ustrncmp((header+2),context->boundary,Ustrlen(context->boundary)) == 0) { |
764 |
- /* found boundary */ |
765 |
- if (Ustrncmp((header+2+Ustrlen(context->boundary)),"--",2) == 0) { |
766 |
- /* END boundary found */ |
767 |
- debug_printf("End boundary found %s\n", context->boundary); |
768 |
- return rc; |
769 |
- } |
770 |
- else { |
771 |
- debug_printf("Next part with boundary %s\n", context->boundary); |
772 |
- }; |
773 |
- /* can't use break here */ |
774 |
- goto DECODE_HEADERS; |
775 |
- } |
776 |
- }; |
777 |
+int |
778 |
+mime_acl_check(uschar *acl, FILE *f, struct mime_boundary_context *context, |
779 |
+ uschar **user_msgptr, uschar **log_msgptr) |
780 |
+{ |
781 |
+int rc = OK; |
782 |
+uschar *header = NULL; |
783 |
+struct mime_boundary_context nested_context; |
784 |
+ |
785 |
+/* reserve a line buffer to work in */ |
786 |
+if (!(header = (uschar *)malloc(MIME_MAX_HEADER_SIZE+1))) |
787 |
+ { |
788 |
+ log_write(0, LOG_PANIC, |
789 |
+ "MIME ACL: can't allocate %d bytes of memory.", MIME_MAX_HEADER_SIZE+1); |
790 |
+ return DEFER; |
791 |
+ } |
792 |
+ |
793 |
+/* Not actually used at the moment, but will be vital to fixing |
794 |
+ * some RFC 2046 nonconformance later... */ |
795 |
+nested_context.parent = context; |
796 |
+ |
797 |
+/* loop through parts */ |
798 |
+while(1) |
799 |
+ { |
800 |
+ /* reset all per-part mime variables */ |
801 |
+ mime_anomaly_level = 0; |
802 |
+ mime_anomaly_text = NULL; |
803 |
+ mime_boundary = NULL; |
804 |
+ mime_charset = NULL; |
805 |
+ mime_decoded_filename = NULL; |
806 |
+ mime_filename = NULL; |
807 |
+ mime_content_description = NULL; |
808 |
+ mime_content_disposition = NULL; |
809 |
+ mime_content_id = NULL; |
810 |
+ mime_content_transfer_encoding = NULL; |
811 |
+ mime_content_type = NULL; |
812 |
+ mime_is_multipart = 0; |
813 |
+ mime_content_size = 0; |
814 |
+ |
815 |
+ /* |
816 |
+ If boundary is null, we assume that *f is positioned on the start of headers (for example, |
817 |
+ at the very beginning of a message. |
818 |
+ If a boundary is given, we must first advance to it to reach the start of the next header |
819 |
+ block. |
820 |
+ */ |
821 |
+ |
822 |
+ /* NOTE -- there's an error here -- RFC2046 specifically says to |
823 |
+ * check for outer boundaries. This code doesn't do that, and |
824 |
+ * I haven't fixed this. |
825 |
+ * |
826 |
+ * (I have moved partway towards adding support, however, by adding |
827 |
+ * a "parent" field to my new boundary-context structure.) |
828 |
+ */ |
829 |
+ if (context != NULL) |
830 |
+ { |
831 |
+ while(fgets(CS header, MIME_MAX_HEADER_SIZE, f) != NULL) |
832 |
+ { |
833 |
+ /* boundary line must start with 2 dashes */ |
834 |
+ if (Ustrncmp(header,"--",2) == 0) |
835 |
+ { |
836 |
+ if (Ustrncmp((header+2),context->boundary,Ustrlen(context->boundary)) == 0) |
837 |
+ { |
838 |
+ /* found boundary */ |
839 |
+ if (Ustrncmp((header+2+Ustrlen(context->boundary)),"--",2) == 0) |
840 |
+ { |
841 |
+ /* END boundary found */ |
842 |
+ debug_printf("End boundary found %s\n", context->boundary); |
843 |
+ return rc; |
844 |
+ } |
845 |
+ else |
846 |
+ debug_printf("Next part with boundary %s\n", context->boundary); |
847 |
+ |
848 |
+ /* can't use break here */ |
849 |
+ goto DECODE_HEADERS; |
850 |
+ } |
851 |
+ } |
852 |
} |
853 |
- /* Hit EOF or read error. Ugh. */ |
854 |
- debug_printf("Hit EOF ...\n"); |
855 |
- return rc; |
856 |
- }; |
857 |
- |
858 |
- DECODE_HEADERS: |
859 |
- /* parse headers, set up expansion variables */ |
860 |
- while(mime_get_header(f,header)) { |
861 |
- int i; |
862 |
- /* loop through header list */ |
863 |
- for (i = 0; i < mime_header_list_size; i++) { |
864 |
- uschar *header_value = NULL; |
865 |
- int header_value_len = 0; |
866 |
- |
867 |
- /* found an interesting header? */ |
868 |
- if (strncmpic(mime_header_list[i].name,header,mime_header_list[i].namelen) == 0) { |
869 |
- uschar *p = header + mime_header_list[i].namelen; |
870 |
- /* yes, grab the value (normalize to lower case) |
871 |
- and copy to its corresponding expansion variable */ |
872 |
- while(*p != ';') { |
873 |
- *p = tolower(*p); |
874 |
- p++; |
875 |
- }; |
876 |
- header_value_len = (p - (header + mime_header_list[i].namelen)); |
877 |
- header_value = (uschar *)malloc(header_value_len+1); |
878 |
- memset(header_value,0,header_value_len+1); |
879 |
- p = header + mime_header_list[i].namelen; |
880 |
- Ustrncpy(header_value, p, header_value_len); |
881 |
- debug_printf("Found %s MIME header, value is '%s'\n", mime_header_list[i].name, header_value); |
882 |
- *((uschar **)(mime_header_list[i].value)) = header_value; |
883 |
- |
884 |
- /* make p point to the next character after the closing ';' */ |
885 |
- p += (header_value_len+1); |
886 |
- |
887 |
- /* grab all param=value tags on the remaining line, check if they are interesting */ |
888 |
- NEXT_PARAM_SEARCH: while (*p != 0) { |
889 |
- int j; |
890 |
- for (j = 0; j < mime_parameter_list_size; j++) { |
891 |
- uschar *param_value = NULL; |
892 |
- int param_value_len = 0; |
893 |
- |
894 |
- /* found an interesting parameter? */ |
895 |
- if (strncmpic(mime_parameter_list[j].name,p,mime_parameter_list[j].namelen) == 0) { |
896 |
- uschar *q = p + mime_parameter_list[j].namelen; |
897 |
- /* yes, grab the value and copy to its corresponding expansion variable */ |
898 |
- while (*q && *q != ';') |
899 |
- { |
900 |
- if (*q == '"') do q++; while (*q != '"'); |
901 |
- q++; |
902 |
- } |
903 |
- |
904 |
- param_value_len = (q - (p + mime_parameter_list[j].namelen)); |
905 |
- param_value = (uschar *)malloc(param_value_len+1); |
906 |
- memset(param_value,0,param_value_len+1); |
907 |
- q = p + mime_parameter_list[j].namelen; |
908 |
- Ustrncpy(param_value, q, param_value_len); |
909 |
- param_value = rfc2047_decode(param_value, check_rfc2047_length, NULL, 32, ¶m_value_len, &q); |
910 |
- debug_printf("Found %s MIME parameter in %s header, value is '%s'\n", mime_parameter_list[j].name, mime_header_list[i].name, param_value); |
911 |
- *((uschar **)(mime_parameter_list[j].value)) = param_value; |
912 |
- p += (mime_parameter_list[j].namelen + param_value_len + 1); |
913 |
- goto NEXT_PARAM_SEARCH; |
914 |
- }; |
915 |
- } |
916 |
- /* There is something, but not one of our interesting parameters. |
917 |
- Advance to the next semicolon */ |
918 |
- while(*p != ';') p++; |
919 |
- p++; |
920 |
- }; |
921 |
- }; |
922 |
- }; |
923 |
- }; |
924 |
+ /* Hit EOF or read error. Ugh. */ |
925 |
+ debug_printf("Hit EOF ...\n"); |
926 |
+ return rc; |
927 |
+ } |
928 |
|
929 |
- /* set additional flag variables (easier access) */ |
930 |
- if ( (mime_content_type != NULL) && |
931 |
- (Ustrncmp(mime_content_type,"multipart",9) == 0) ) |
932 |
- mime_is_multipart = 1; |
933 |
+DECODE_HEADERS: |
934 |
+ /* parse headers, set up expansion variables */ |
935 |
+ while (mime_get_header(f,header)) |
936 |
+ { |
937 |
+ int i; |
938 |
+ /* loop through header list */ |
939 |
+ for (i = 0; i < mime_header_list_size; i++) |
940 |
+ { |
941 |
+ uschar *header_value = NULL; |
942 |
+ int header_value_len = 0; |
943 |
+ |
944 |
+ /* found an interesting header? */ |
945 |
+ if (strncmpic(mime_header_list[i].name,header,mime_header_list[i].namelen) == 0) |
946 |
+ { |
947 |
+ uschar *p = header + mime_header_list[i].namelen; |
948 |
+ /* yes, grab the value (normalize to lower case) |
949 |
+ and copy to its corresponding expansion variable */ |
950 |
+ while(*p != ';') |
951 |
+ { |
952 |
+ *p = tolower(*p); |
953 |
+ p++; |
954 |
+ } |
955 |
+ header_value_len = (p - (header + mime_header_list[i].namelen)); |
956 |
+ header_value = (uschar *)malloc(header_value_len+1); |
957 |
+ memset(header_value,0,header_value_len+1); |
958 |
+ p = header + mime_header_list[i].namelen; |
959 |
+ Ustrncpy(header_value, p, header_value_len); |
960 |
+ debug_printf("Found %s MIME header, value is '%s'\n", mime_header_list[i].name, header_value); |
961 |
+ *((uschar **)(mime_header_list[i].value)) = header_value; |
962 |
+ |
963 |
+ /* make p point to the next character after the closing ';' */ |
964 |
+ p += (header_value_len+1); |
965 |
+ |
966 |
+ /* grab all param=value tags on the remaining line, check if they are interesting */ |
967 |
+NEXT_PARAM_SEARCH: |
968 |
+ while (*p != 0) |
969 |
+ { |
970 |
+ mime_parameter * mp; |
971 |
+ for (mp = mime_parameter_list; |
972 |
+ mp < &mime_parameter_list[mime_parameter_list_size]; |
973 |
+ mp++) |
974 |
+ { |
975 |
+ uschar *param_value = NULL; |
976 |
+ int param_value_len = 0; |
977 |
+ |
978 |
+ /* found an interesting parameter? */ |
979 |
+ if (strncmpic(mp->name, p, mp->namelen) == 0) |
980 |
+ { |
981 |
+ uschar *q = p + mp->namelen; |
982 |
+ int size = 0; |
983 |
+ int ptr = 0; |
984 |
+ |
985 |
+ /* yes, grab the value and copy to its corresponding expansion variable */ |
986 |
+ while(*q && *q != ';') /* ; terminates */ |
987 |
+ { |
988 |
+ if (*q == '"') |
989 |
+ { |
990 |
+ q++; /* skip leading " */ |
991 |
+ while(*q && *q != '"') /* which protects ; */ |
992 |
+ param_value = string_cat(param_value, &size, &ptr, q++, 1); |
993 |
+ if (*q) q++; /* skip trailing " */ |
994 |
+ } |
995 |
+ else |
996 |
+ param_value = string_cat(param_value, &size, &ptr, q++, 1); |
997 |
+ } |
998 |
+ param_value[ptr++] = '\0'; |
999 |
+ param_value_len = ptr; |
1000 |
+ |
1001 |
+ param_value = rfc2047_decode(param_value, check_rfc2047_length, NULL, 32, ¶m_value_len, &q); |
1002 |
+ debug_printf("Found %s MIME parameter in %s header, value is '%s'\n", mp->name, mime_header_list[i].name, param_value); |
1003 |
+ *((uschar **)(mp->value)) = param_value; |
1004 |
+ p += (mp->namelen + param_value_len + 1); |
1005 |
+ goto NEXT_PARAM_SEARCH; |
1006 |
+ } |
1007 |
+ } |
1008 |
+ /* There is something, but not one of our interesting parameters. |
1009 |
+ Advance to the next semicolon */ |
1010 |
+ while(*p != ';') p++; |
1011 |
+ p++; |
1012 |
+ } |
1013 |
+ } |
1014 |
+ } |
1015 |
+ } |
1016 |
|
1017 |
- /* Make a copy of the boundary pointer. |
1018 |
- Required since mime_boundary is global |
1019 |
- and can be overwritten further down in recursion */ |
1020 |
- nested_context.boundary = mime_boundary; |
1021 |
+ /* set additional flag variables (easier access) */ |
1022 |
+ if ( (mime_content_type != NULL) && |
1023 |
+ (Ustrncmp(mime_content_type,"multipart",9) == 0) ) |
1024 |
+ mime_is_multipart = 1; |
1025 |
|
1026 |
- /* raise global counter */ |
1027 |
- mime_part_count++; |
1028 |
+ /* Make a copy of the boundary pointer. |
1029 |
+ Required since mime_boundary is global |
1030 |
+ and can be overwritten further down in recursion */ |
1031 |
+ nested_context.boundary = mime_boundary; |
1032 |
|
1033 |
- /* copy current file handle to global variable */ |
1034 |
- mime_stream = f; |
1035 |
- mime_current_boundary = context ? context->boundary : 0; |
1036 |
+ /* raise global counter */ |
1037 |
+ mime_part_count++; |
1038 |
|
1039 |
- /* Note the context */ |
1040 |
- mime_is_coverletter = !(context && context->context == MBC_ATTACHMENT); |
1041 |
+ /* copy current file handle to global variable */ |
1042 |
+ mime_stream = f; |
1043 |
+ mime_current_boundary = context ? context->boundary : 0; |
1044 |
|
1045 |
- /* call ACL handling function */ |
1046 |
- rc = acl_check(ACL_WHERE_MIME, NULL, acl, user_msgptr, log_msgptr); |
1047 |
+ /* Note the context */ |
1048 |
+ mime_is_coverletter = !(context && context->context == MBC_ATTACHMENT); |
1049 |
|
1050 |
- mime_stream = NULL; |
1051 |
- mime_current_boundary = NULL; |
1052 |
+ /* call ACL handling function */ |
1053 |
+ rc = acl_check(ACL_WHERE_MIME, NULL, acl, user_msgptr, log_msgptr); |
1054 |
|
1055 |
- if (rc != OK) break; |
1056 |
+ mime_stream = NULL; |
1057 |
+ mime_current_boundary = NULL; |
1058 |
+ |
1059 |
+ if (rc != OK) break; |
1060 |
|
1061 |
- /* If we have a multipart entity and a boundary, go recursive */ |
1062 |
- if ( (mime_content_type != NULL) && |
1063 |
- (nested_context.boundary != NULL) && |
1064 |
- (Ustrncmp(mime_content_type,"multipart",9) == 0) ) { |
1065 |
- debug_printf("Entering multipart recursion, boundary '%s'\n", nested_context.boundary); |
1066 |
- |
1067 |
- if (context && context->context == MBC_ATTACHMENT) |
1068 |
- nested_context.context = MBC_ATTACHMENT; |
1069 |
- else if (!Ustrcmp(mime_content_type,"multipart/alternative") |
1070 |
- || !Ustrcmp(mime_content_type,"multipart/related")) |
1071 |
- nested_context.context = MBC_COVERLETTER_ALL; |
1072 |
- else |
1073 |
- nested_context.context = MBC_COVERLETTER_ONESHOT; |
1074 |
- |
1075 |
- rc = mime_acl_check(acl, f, &nested_context, user_msgptr, log_msgptr); |
1076 |
- if (rc != OK) break; |
1077 |
+ /* If we have a multipart entity and a boundary, go recursive */ |
1078 |
+ if ( (mime_content_type != NULL) && |
1079 |
+ (nested_context.boundary != NULL) && |
1080 |
+ (Ustrncmp(mime_content_type,"multipart",9) == 0) ) |
1081 |
+ { |
1082 |
+ debug_printf("Entering multipart recursion, boundary '%s'\n", nested_context.boundary); |
1083 |
+ |
1084 |
+ nested_context.context = |
1085 |
+ context && context->context == MBC_ATTACHMENT |
1086 |
+ ? MBC_ATTACHMENT |
1087 |
+ : Ustrcmp(mime_content_type,"multipart/alternative") == 0 |
1088 |
+ || Ustrcmp(mime_content_type,"multipart/related") == 0 |
1089 |
+ ? MBC_COVERLETTER_ALL |
1090 |
+ : MBC_COVERLETTER_ONESHOT; |
1091 |
+ |
1092 |
+ rc = mime_acl_check(acl, f, &nested_context, user_msgptr, log_msgptr); |
1093 |
+ if (rc != OK) break; |
1094 |
} |
1095 |
- else if ( (mime_content_type != NULL) && |
1096 |
- (Ustrncmp(mime_content_type,"message/rfc822",14) == 0) ) { |
1097 |
- uschar *rfc822name = NULL; |
1098 |
- uschar filename[2048]; |
1099 |
- int file_nr = 0; |
1100 |
- int result = 0; |
1101 |
- |
1102 |
- /* must find first free sequential filename */ |
1103 |
- do { |
1104 |
- struct stat mystat; |
1105 |
- (void)string_format(filename,2048,"%s/scan/%s/__rfc822_%05u", spool_directory, message_id, file_nr); |
1106 |
- file_nr++; |
1107 |
- /* security break */ |
1108 |
- if (file_nr >= 128) |
1109 |
- goto NO_RFC822; |
1110 |
- result = stat(CS filename,&mystat); |
1111 |
- } |
1112 |
- while(result != -1); |
1113 |
- |
1114 |
- rfc822name = filename; |
1115 |
- |
1116 |
- /* decode RFC822 attachment */ |
1117 |
- mime_decoded_filename = NULL; |
1118 |
- mime_stream = f; |
1119 |
- mime_current_boundary = context ? context->boundary : NULL; |
1120 |
- mime_decode(&rfc822name); |
1121 |
- mime_stream = NULL; |
1122 |
- mime_current_boundary = NULL; |
1123 |
- if (mime_decoded_filename == NULL) { |
1124 |
- /* decoding failed */ |
1125 |
- log_write(0, LOG_MAIN, |
1126 |
- "mime_regex acl condition warning - could not decode RFC822 MIME part to file."); |
1127 |
- return DEFER; |
1128 |
- }; |
1129 |
- mime_decoded_filename = NULL; |
1130 |
- }; |
1131 |
+ else if ( (mime_content_type != NULL) && |
1132 |
+ (Ustrncmp(mime_content_type,"message/rfc822",14) == 0) ) |
1133 |
+ { |
1134 |
+ uschar *rfc822name = NULL; |
1135 |
+ uschar filename[2048]; |
1136 |
+ int file_nr = 0; |
1137 |
+ int result = 0; |
1138 |
|
1139 |
- NO_RFC822: |
1140 |
- /* If the boundary of this instance is NULL, we are finished here */ |
1141 |
- if (context == NULL) break; |
1142 |
+ /* must find first free sequential filename */ |
1143 |
+ do |
1144 |
+ { |
1145 |
+ struct stat mystat; |
1146 |
+ (void)string_format(filename, 2048, |
1147 |
+ "%s/scan/%s/__rfc822_%05u", spool_directory, message_id, file_nr++); |
1148 |
+ /* security break */ |
1149 |
+ if (file_nr >= 128) |
1150 |
+ goto NO_RFC822; |
1151 |
+ result = stat(CS filename,&mystat); |
1152 |
+ } while (result != -1); |
1153 |
+ |
1154 |
+ rfc822name = filename; |
1155 |
+ |
1156 |
+ /* decode RFC822 attachment */ |
1157 |
+ mime_decoded_filename = NULL; |
1158 |
+ mime_stream = f; |
1159 |
+ mime_current_boundary = context ? context->boundary : NULL; |
1160 |
+ mime_decode(&rfc822name); |
1161 |
+ mime_stream = NULL; |
1162 |
+ mime_current_boundary = NULL; |
1163 |
+ if (!mime_decoded_filename) /* decoding failed */ |
1164 |
+ { |
1165 |
+ log_write(0, LOG_MAIN, |
1166 |
+ "mime_regex acl condition warning - could not decode RFC822 MIME part to file."); |
1167 |
+ return DEFER; |
1168 |
+ } |
1169 |
+ mime_decoded_filename = NULL; |
1170 |
+ } |
1171 |
|
1172 |
- if (context->context == MBC_COVERLETTER_ONESHOT) |
1173 |
- context->context = MBC_ATTACHMENT; |
1174 |
+NO_RFC822: |
1175 |
+ /* If the boundary of this instance is NULL, we are finished here */ |
1176 |
+ if (context == NULL) break; |
1177 |
|
1178 |
- }; |
1179 |
+ if (context->context == MBC_COVERLETTER_ONESHOT) |
1180 |
+ context->context = MBC_ATTACHMENT; |
1181 |
+ } |
1182 |
|
1183 |
- return rc; |
1184 |
+return rc; |
1185 |
} |
1186 |
|
1187 |
-#endif |
1188 |
+#endif /*WITH_CONTENT_SCAN*/ |
1189 |
+ |
1190 |
+/* vi: sw ai sw=2 |
1191 |
+*/ |