Browse code

More tidy

git-svn: trunk@2053

Nigel Horne authored on 2006/06/29 06:07:36
Showing 1 changed files
... ...
@@ -16,7 +16,7 @@
16 16
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 17
  *  MA 02110-1301, USA.
18 18
  */
19
-static	char	const	rcsid[] = "$Id: mbox.c,v 1.312 2006/06/28 16:06:07 njh Exp $";
19
+static	char	const	rcsid[] = "$Id: mbox.c,v 1.313 2006/06/28 21:07:36 njh Exp $";
20 20
 
21 21
 #if HAVE_CONFIG_H
22 22
 #include "clamav-config.h"
... ...
@@ -187,11 +187,18 @@ typedef enum	{ FALSE = 0, TRUE = 1 } bool;
187 187
 					 * of EICAR within bounces, which don't matter
188 188
 					 */
189 189
 
190
+typedef	struct	mbox_ctx {
191
+	const	char	*dir;
192
+	const	table_t	*rfc821Table;
193
+	const	table_t	*subtypeTable;
194
+	cli_ctx	*ctx;
195
+} mbox_ctx;
196
+
190 197
 static	int	cli_parse_mbox(const char *dir, int desc, cli_ctx *ctx);
191 198
 static	message	*parseEmailFile(FILE *fin, const table_t *rfc821Table, const char *firstLine, const char *dir);
192 199
 static	message	*parseEmailHeaders(const message *m, const table_t *rfc821Table);
193 200
 static	int	parseEmailHeader(message *m, const char *line, const table_t *rfc821Table);
194
-static	int	parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t *rfc821Table, const table_t *subtypeTable, cli_ctx *ctx);
201
+static	int	parseEmailBody(message *messageIn, text *textIn, mbox_ctx *mctx);
195 202
 static	int	boundaryStart(const char *line, const char *boundary);
196 203
 static	int	endOfMessage(const char *line, const char *boundary);
197 204
 static	int	initialiseTables(table_t **rfc821Table, table_t **subtypeTable);
... ...
@@ -209,6 +216,7 @@ static	bool	usefulHeader(int commandNumber, const char *cmd);
209 209
 static	char	*getline_from_mbox(char *buffer, size_t len, FILE *fin);
210 210
 static	bool	isBounceStart(const char *line);
211 211
 static	bool	binhexMessage(const char *dir, message *message);
212
+static	message	*do_multipart(message *mainMessage, message **messages, int i, int *rc, mbox_ctx *mctx, message *messageIn, text **tptr);
212 213
 
213 214
 static	void	checkURLs(message *m, const char *dir);
214 215
 #ifdef	WITH_CURL
... ...
@@ -1127,6 +1135,7 @@ cli_parse_mbox(const char *dir, int desc, cli_ctx *ctx)
1127 1127
 	message *body;
1128 1128
 	FILE *fd;
1129 1129
 	char buffer[RFC2821LENGTH + 1];
1130
+	mbox_ctx mctx;
1130 1131
 #ifdef HAVE_BACKTRACE
1131 1132
 	void (*segv)(int);
1132 1133
 #endif
... ...
@@ -1211,6 +1220,11 @@ cli_parse_mbox(const char *dir, int desc, cli_ctx *ctx)
1211 1211
 	retcode = CL_SUCCESS;
1212 1212
 	body = NULL;
1213 1213
 
1214
+	mctx.dir = dir;
1215
+	mctx.rfc821Table = rfc821;
1216
+	mctx.subtypeTable = subtype;
1217
+	mctx.ctx = ctx;
1218
+
1214 1219
 	/*
1215 1220
 	 * Is it a UNIX style mbox with more than one
1216 1221
 	 * mail message, or just a single mail message?
... ...
@@ -1276,7 +1290,7 @@ cli_parse_mbox(const char *dir, int desc, cli_ctx *ctx)
1276 1276
 				messageSetCTX(body, ctx);
1277 1277
 				messageDestroy(m);
1278 1278
 				if(messageGetBody(body)) {
1279
-					int rc = parseEmailBody(body, NULL, dir, rfc821, subtype, ctx);
1279
+					int rc = parseEmailBody(body, NULL, &mctx);
1280 1280
 					if(rc == 0) {
1281 1281
 						messageReset(body);
1282 1282
 						m = body;
... ...
@@ -1357,7 +1371,7 @@ cli_parse_mbox(const char *dir, int desc, cli_ctx *ctx)
1357 1357
 		 */
1358 1358
 		if((retcode == CL_SUCCESS) && messageGetBody(body)) {
1359 1359
 			messageSetCTX(body, ctx);
1360
-			switch(parseEmailBody(body, NULL, dir, rfc821, subtype, ctx)) {
1360
+			switch(parseEmailBody(body, NULL, &mctx)) {
1361 1361
 				case 0:
1362 1362
 					retcode = CL_EFORMAT;
1363 1363
 					break;
... ...
@@ -1921,12 +1935,11 @@ parseEmailHeader(message *m, const char *line, const table_t *rfc821)
1921 1921
  *	3 for virus found
1922 1922
  */
1923 1923
 static int	/* success or fail */
1924
-parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t *rfc821Table, const table_t *subtypeTable, cli_ctx *ctx)
1924
+parseEmailBody(message *messageIn, text *textIn, mbox_ctx *mctx)
1925 1925
 {
1926 1926
 	message **messages;	/* parts of a multipart message */
1927 1927
 	int inMimeHead, i, rc = 1, htmltextPart, multiparts = 0;
1928 1928
 	text *aText;
1929
-	const char *cptr;
1930 1929
 	message *mainMessage;
1931 1930
 	fileblob *fb;
1932 1931
 	bool infected = FALSE;
... ...
@@ -1953,7 +1966,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
1953 1953
 		mimeSubtype = messageGetMimeSubtype(mainMessage);
1954 1954
 
1955 1955
 		/* pre-process */
1956
-		subtype = tableFind(subtypeTable, mimeSubtype);
1956
+		subtype = tableFind(mctx->subtypeTable, mimeSubtype);
1957 1957
 		if((mimeType == TEXT) && (subtype == PLAIN)) {
1958 1958
 			/*
1959 1959
 			 * This is effectively no encoding, notice that we
... ...
@@ -1983,8 +1996,8 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
1983 1983
 			break;
1984 1984
 		case TEXT:
1985 1985
 			/* text/plain has been preprocessed as no encoding */
1986
-			if((ctx->options&CL_SCAN_MAILURL) && (subtype == HTML))
1987
-				checkURLs(mainMessage, dir);
1986
+			if((mctx->ctx->options&CL_SCAN_MAILURL) && (subtype == HTML))
1987
+				checkURLs(mainMessage, mctx->dir);
1988 1988
 			break;
1989 1989
 		case MULTIPART:
1990 1990
 			cli_dbgmsg("Content-type 'multipart' handler\n");
... ...
@@ -2030,7 +2043,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
2030 2030
 					 * TODO: check yEnc
2031 2031
 					 */
2032 2032
 					if(binhexBegin(mainMessage) == t_line) {
2033
-						if(binhexMessage(dir, mainMessage)) {
2033
+						if(binhexMessage(mctx->dir, mainMessage)) {
2034 2034
 							/* virus found */
2035 2035
 							rc = 3;
2036 2036
 							break;
... ...
@@ -2096,7 +2109,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
2096 2096
 					multiparts--;
2097 2097
 					continue;
2098 2098
 				}
2099
-				messageSetCTX(aMessage, ctx);
2099
+				messageSetCTX(aMessage, mctx->ctx);
2100 2100
 
2101 2101
 				cli_dbgmsg("Now read in part %d\n", multiparts);
2102 2102
 
... ...
@@ -2153,7 +2166,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
2153 2153
 						 * Content-Type: application/octet-stream;
2154 2154
 						 * Content-Transfer-Encoding: base64
2155 2155
 						 */
2156
-						parseEmailHeader(aMessage, line, rfc821Table);
2156
+						parseEmailHeader(aMessage, line, mctx->rfc821Table);
2157 2157
 
2158 2158
 						while(isspace((int)*line))
2159 2159
 							line++;
... ...
@@ -2313,7 +2326,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
2313 2313
 						cli_dbgmsg("Multipart %d: About to parse folded header '%s'\n",
2314 2314
 							multiparts, fullline);
2315 2315
 
2316
-						parseEmailHeader(aMessage, fullline, rfc821Table);
2316
+						parseEmailHeader(aMessage, fullline, mctx->rfc821Table);
2317 2317
 						free(fullline);
2318 2318
 					} else if(endOfMessage(line, boundary)) {
2319 2319
 						/*
... ...
@@ -2348,7 +2361,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
2348 2348
 			 * Preprocess. Anything special to be done before
2349 2349
 			 * we handle the multiparts?
2350 2350
 			 */
2351
-			switch(tableFind(subtypeTable, mimeSubtype)) {
2351
+			switch(tableFind(mctx->subtypeTable, mimeSubtype)) {
2352 2352
 				case KNOWBOT:
2353 2353
 					/* TODO */
2354 2354
 					cli_dbgmsg("multipart/knowbot parsed as multipart/mixed for now\n");
... ...
@@ -2388,7 +2401,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
2388 2388
 			 *	message *messages[multiparts]
2389 2389
 			 * Let's decide what to do with them all
2390 2390
 			 */
2391
-			switch(tableFind(subtypeTable, mimeSubtype)) {
2391
+			switch(tableFind(mctx->subtypeTable, mimeSubtype)) {
2392 2392
 			case RELATED:
2393 2393
 				cli_dbgmsg("Multipart related handler\n");
2394 2394
 				/*
... ...
@@ -2418,7 +2431,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
2418 2418
 				if(htmltextPart == -1)
2419 2419
 					cli_dbgmsg("No HTML code found to be scanned\n");
2420 2420
 				else {
2421
-					rc = parseEmailBody(aMessage, aText, dir, rfc821Table, subtypeTable, ctx);
2421
+					rc = parseEmailBody(aMessage, aText, mctx);
2422 2422
 					if(rc == 1) {
2423 2423
 						assert(aMessage == messages[htmltextPart]);
2424 2424
 						messageDestroy(aMessage);
... ...
@@ -2497,230 +2510,16 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
2497 2497
 
2498 2498
 				cli_dbgmsg("Mixed message with %d parts\n", multiparts);
2499 2499
 				for(i = 0; i < multiparts; i++) {
2500
-					bool addToText = FALSE;
2501
-					const char *dtype;
2502
-#ifndef	SAVE_TO_DISC
2503
-					message *body;
2504
-#endif
2505
-
2506
-					aMessage = messages[i];
2507
-
2508
-					if(aMessage == NULL)
2509
-						continue;
2510
-
2511
-					cli_dbgmsg("Mixed message part %d is of type %d\n",
2512
-						i, messageGetMimeType(aMessage));
2513
-
2514
-					switch(messageGetMimeType(aMessage)) {
2515
-					case APPLICATION:
2516
-					case AUDIO:
2517
-					case IMAGE:
2518
-					case VIDEO:
2519
-						break;
2520
-					case NOMIME:
2521
-						cli_dbgmsg("No mime headers found in multipart part %d\n", i);
2522
-						if(mainMessage) {
2523
-							if(binhexBegin(aMessage)) {
2524
-								cli_dbgmsg("Found binhex message in multipart/mixed mainMessage\n");
2525
-
2526
-								if(binhexMessage(dir, mainMessage)) {
2527
-									infected = TRUE;
2528
-									rc = 3;
2529
-								}
2530
-							}
2531
-							if(mainMessage != messageIn)
2532
-								messageDestroy(mainMessage);
2533
-							mainMessage = NULL;
2534
-						} else if(aMessage) {
2535
-							if(binhexBegin(aMessage)) {
2536
-								cli_dbgmsg("Found binhex message in multipart/mixed non mime part\n");
2537
-								if(binhexMessage(dir, aMessage)) {
2538
-									infected = TRUE;
2539
-									rc = 3;
2540
-								}
2541
-								assert(aMessage == messages[i]);
2542
-								messageReset(messages[i]);
2543
-							}
2544
-						}
2545
-						addToText = TRUE;
2546
-						if(messageGetBody(aMessage) == NULL)
2547
-							/*
2548
-							 * No plain text version
2549
-							 */
2550
-							cli_dbgmsg("No plain text alternative\n");
2551
-						break;
2552
-					case TEXT:
2553
-						dtype = messageGetDispositionType(aMessage);
2554
-						cli_dbgmsg("Mixed message text part disposition \"%s\"\n",
2555
-							dtype);
2556
-						if(strcasecmp(dtype, "attachment") == 0)
2557
-							break;
2558
-						if((*dtype == '\0') || (strcasecmp(dtype, "inline") == 0)) {
2559
-							if(mainMessage && (mainMessage != messageIn))
2560
-								messageDestroy(mainMessage);
2561
-							mainMessage = NULL;
2562
-							cptr = messageGetMimeSubtype(aMessage);
2563
-							cli_dbgmsg("Mime subtype \"%s\"\n", cptr);
2564
-							if((tableFind(subtypeTable, cptr) == PLAIN) &&
2565
-								  (messageGetEncoding(aMessage) == NOENCODING)) {
2566
-								char *filename;
2567
-								/*
2568
-								 * Strictly speaking
2569
-								 * a text/plain part is
2570
-								 * not an attachment. We
2571
-								 * pretend it is so that
2572
-								 * we can decode and
2573
-								 * scan it
2574
-								 */
2575
-								filename = (char *)messageFindArgument(aMessage, "filename");
2576
-								if(filename == NULL)
2577
-									filename = (char *)messageFindArgument(aMessage, "name");
2578
-
2579
-								if(filename == NULL) {
2580
-									cli_dbgmsg("Adding part to main message\n");
2581
-									addToText = TRUE;
2582
-								} else {
2583
-									cli_dbgmsg("Treating %s as attachment\n",
2584
-										filename);
2585
-									free(filename);
2586
-								}
2587
-							} else {
2588
-								if(ctx->options&CL_SCAN_MAILURL)
2589
-									if(tableFind(subtypeTable, cptr) == HTML)
2590
-										checkURLs(aMessage, dir);
2591
-								messageAddArgument(aMessage, "filename=mixedtextportion");
2592
-							}
2593
-						} else {
2594
-							cli_dbgmsg("Text type %s is not supported\n", dtype);
2595
-							continue;
2596
-						}
2597
-						break;
2598
-					case MESSAGE:
2599
-						/* Content-Type: message/rfc822 */
2600
-						cli_dbgmsg("Found message inside multipart (encoding type %d)\n",
2601
-							messageGetEncoding(aMessage));
2602
-#ifndef	SCAN_UNENCODED_BOUNCES
2603
-						switch(messageGetEncoding(aMessage)) {
2604
-							case NOENCODING:
2605
-							case EIGHTBIT:
2606
-							case BINARY:
2607
-								if(encodingLine(aMessage) == NULL) {
2608
-									/*
2609
-									 * This means that the message has no attachments
2610
-									 * The test for messageGetEncoding is needed since
2611
-									 * encodingLine won't have been set if the message
2612
-									 * itself has been encoded
2613
-									 */
2614
-									cli_dbgmsg("Unencoded multipart/message will not be scanned\n");
2615
-									assert(aMessage == messages[i]);
2616
-									messageDestroy(messages[i]);
2617
-									messages[i] = NULL;
2618
-									continue;
2619
-								}
2620
-								/* FALLTHROUGH */
2621
-							default:
2622
-								cli_dbgmsg("Encoded multipart/message will be scanned\n");
2623
-						}
2624
-#endif
2625
-#if	0
2626
-						messageAddStrAtTop(aMessage,
2627
-							"Received: by clamd (message/rfc822)");
2628
-#endif
2629
-#ifdef	SAVE_TO_DISC
2630
-						/*
2631
-						 * Save this embedded message
2632
-						 * to a temporary file
2633
-						 */
2634
-						saveTextPart(aMessage, dir);
2635
-						assert(aMessage == messages[i]);
2636
-						messageDestroy(messages[i]);
2637
-						messages[i] = NULL;
2638
-#else
2639
-						/*
2640
-						 * Scan in memory, faster but
2641
-						 * is open to DoS attacks when
2642
-						 * many nested levels are
2643
-						 * involved.
2644
-						 */
2645
-						body = parseEmailHeaders(aMessage, rfc821Table, TRUE);
2646
-						/*
2647
-						 * We've fininished with the
2648
-						 * original copy of the message,
2649
-						 * so throw that away and
2650
-						 * deal with the encapsulated
2651
-						 * message as a message.
2652
-						 * This can save a lot of memory
2653
-						 */
2654
-						assert(aMessage == messages[i]);
2655
-						messageDestroy(messages[i]);
2656
-						messages[i] = NULL;
2657
-						if(body) {
2658
-							messageSetCTX(body, ctx);
2659
-							rc = parseEmailBody(body, NULL, dir, rfc821Table, subtypeTable, ctx);
2660
-							if(messageContainsVirus(body))
2661
-								infected = TRUE;
2662
-							messageDestroy(body);
2663
-						}
2664
-						if(infected) {
2665
-							rc = 3;
2666
-							break;
2667
-						}
2668
-#endif
2669
-						continue;
2670
-					case MULTIPART:
2671
-						/*
2672
-						 * It's a multi part within a multi part
2673
-						 * Run the message parser on this bit, it won't
2674
-						 * be an attachment
2675
-						 */
2676
-						cli_dbgmsg("Found multipart inside multipart\n");
2677
-						if(aMessage) {
2678
-							/*
2679
-							 * The headers were parsed when reading in the
2680
-							 * whole multipart section
2681
-							 */
2682
-							rc = parseEmailBody(aMessage, aText, dir, rfc821Table, subtypeTable, ctx);
2683
-							cli_dbgmsg("Finished recursion\n");
2684
-							assert(aMessage == messages[i]);
2685
-							messageDestroy(messages[i]);
2686
-							messages[i] = NULL;
2687
-						} else {
2688
-							rc = parseEmailBody(NULL, NULL, dir, rfc821Table, subtypeTable, ctx);
2689
-							if(mainMessage && (mainMessage != messageIn))
2690
-								messageDestroy(mainMessage);
2691
-							mainMessage = NULL;
2692
-						}
2693
-						continue;
2694
-					default:
2695
-						cli_warnmsg("Only text and application attachments are supported, type = %d\n",
2696
-							messageGetMimeType(aMessage));
2697
-						continue;
2698
-					}
2699
-
2700
-					if(addToText) {
2701
-						cli_dbgmsg("Adding to non mime-part\n");
2702
-						aText = textAdd(aText, messageGetBody(aMessage));
2703
-					} else {
2704
-						fb = messageToFileblob(aMessage, dir);
2705
-
2706
-						if(fb) {
2707
-							if(fileblobContainsVirus(fb))
2708
-								infected = TRUE;
2709
-							fileblobDestroy(fb);
2710
-						}
2711
-					}
2712
-					assert(aMessage == messages[i]);
2713
-					if(messageContainsVirus(aMessage))
2500
+					mainMessage = do_multipart(mainMessage,
2501
+						messages, i, &rc, mctx,
2502
+						messageIn, &aText);
2503
+					if(rc == 3) {
2714 2504
 						infected = TRUE;
2715
-					messageDestroy(aMessage);
2716
-					messages[i] = NULL;
2717
-					if(infected) {
2718
-						rc = 3;
2719 2505
 						break;
2720 2506
 					}
2721 2507
 				}
2722 2508
 
2723
-				/* rc = parseEmailBody(NULL, NULL, dir, rfc821Table, subtypeTable, ctx); */
2509
+				/* rc = parseEmailBody(NULL, NULL, mctx); */
2724 2510
 				break;
2725 2511
 			case SIGNED:
2726 2512
 			case PARALLEL:
... ...
@@ -2736,7 +2535,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
2736 2736
 				if(htmltextPart == -1)
2737 2737
 					htmltextPart = 0;
2738 2738
 
2739
-				rc = parseEmailBody(messages[htmltextPart], aText, dir, rfc821Table, subtypeTable, ctx);
2739
+				rc = parseEmailBody(messages[htmltextPart], aText, mctx);
2740 2740
 				break;
2741 2741
 			case ENCRYPTED:
2742 2742
 				rc = 0;
... ...
@@ -2763,9 +2562,9 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
2763 2763
 			if(aText && (textIn == NULL)) {
2764 2764
 				if((!infected) && (fb = fileblobCreate()) != NULL) {
2765 2765
 					cli_dbgmsg("Save non mime and/or text/plain part\n");
2766
-					fileblobSetFilename(fb, dir, "textpart");
2766
+					fileblobSetFilename(fb, mctx->dir, "textpart");
2767 2767
 					/*fileblobAddData(fb, "Received: by clamd (textpart)\n", 30);*/
2768
-					fileblobSetCTX(fb, ctx);
2768
+					fileblobSetCTX(fb, mctx->ctx);
2769 2769
 					(void)textToFileblob(aText, fb);
2770 2770
 
2771 2771
 					fileblobDestroy(fb);
... ...
@@ -2798,11 +2597,11 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
2798 2798
 			rc = 0;
2799 2799
 			if((strcasecmp(mimeSubtype, "rfc822") == 0) ||
2800 2800
 			   (strcasecmp(mimeSubtype, "delivery-status") == 0)) {
2801
-				message *m = parseEmailHeaders(mainMessage, rfc821Table);
2801
+				message *m = parseEmailHeaders(mainMessage, mctx->rfc821Table);
2802 2802
 				if(m) {
2803 2803
 					cli_dbgmsg("Decode rfc822\n");
2804 2804
 
2805
-					messageSetCTX(m, ctx);
2805
+					messageSetCTX(m, mctx->ctx);
2806 2806
 
2807 2807
 					if(mainMessage && (mainMessage != messageIn)) {
2808 2808
 						messageDestroy(mainMessage);
... ...
@@ -2810,7 +2609,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
2810 2810
 					} else
2811 2811
 						messageReset(mainMessage);
2812 2812
 					if(messageGetBody(m))
2813
-						rc = parseEmailBody(m, NULL, dir, rfc821Table, subtypeTable, ctx);
2813
+						rc = parseEmailBody(m, NULL, mctx);
2814 2814
 
2815 2815
 					messageDestroy(m);
2816 2816
 				}
... ...
@@ -2822,7 +2621,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
2822 2822
 			} else if(strcasecmp(mimeSubtype, "partial") == 0) {
2823 2823
 #ifdef	PARTIAL_DIR
2824 2824
 				/* RFC1341 message split over many emails */
2825
-				if(rfc1341(mainMessage, dir) >= 0)
2825
+				if(rfc1341(mainMessage, mctx->dir) >= 0)
2826 2826
 					rc = 1;
2827 2827
 #else
2828 2828
 				cli_warnmsg("Partial message received from MUA/MTA - message cannot be scanned\n");
... ...
@@ -2847,7 +2646,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
2847 2847
 			if((strcasecmp(cptr, "octet-stream") == 0) ||
2848 2848
 			   (strcasecmp(cptr, "x-msdownload") == 0)) {*/
2849 2849
 			{
2850
-				fb = messageToFileblob(mainMessage, dir);
2850
+				fb = messageToFileblob(mainMessage, mctx->dir);
2851 2851
 
2852 2852
 				if(fb) {
2853 2853
 					cli_dbgmsg("Saving main message as attachment\n");
... ...
@@ -2951,9 +2750,9 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
2951 2951
 			if((fb = fileblobCreate()) == NULL)
2952 2952
 				break;
2953 2953
 			cli_dbgmsg("Save non mime part bounce message\n");
2954
-			fileblobSetFilename(fb, dir, "bounce");
2954
+			fileblobSetFilename(fb, mctx->dir, "bounce");
2955 2955
 			fileblobAddData(fb, (unsigned char *)"Received: by clamd (bounce)\n", 28);
2956
-			fileblobSetCTX(fb, ctx);
2956
+			fileblobSetCTX(fb, mctx->ctx);
2957 2957
 
2958 2958
 			inheader = TRUE;
2959 2959
 			topofbounce = NULL;
... ...
@@ -3003,7 +2802,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
3003 3003
 	 */
3004 3004
 	cli_dbgmsg("%d multiparts found\n", multiparts);
3005 3005
 	for(i = 0; i < multiparts; i++) {
3006
-		fb = messageToFileblob(messages[i], dir);
3006
+		fb = messageToFileblob(messages[i], mctx->dir);
3007 3007
 
3008 3008
 		if(fb) {
3009 3009
 			cli_dbgmsg("Saving multipart %d\n", i);
... ...
@@ -3049,7 +2848,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
3049 3049
 				if(cli_strtokbuf(txt, 0, ":", cmd) == NULL)
3050 3050
 					continue;
3051 3051
 
3052
-				switch(tableFind(rfc821Table, cmd)) {
3052
+				switch(tableFind(mctx->rfc821Table, cmd)) {
3053 3053
 					case CONTENT_TRANSFER_ENCODING:
3054 3054
 						if((strstr(txt, "7bit") == NULL) &&
3055 3055
 						   (strstr(txt, "8bit") == NULL))
... ...
@@ -3072,7 +2871,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
3072 3072
 			}
3073 3073
 			if(t && ((fb = fileblobCreate()) != NULL)) {
3074 3074
 				cli_dbgmsg("Found a bounce message\n");
3075
-				fileblobSetFilename(fb, dir, "bounce");
3075
+				fileblobSetFilename(fb, mctx->dir, "bounce");
3076 3076
 				/*fileblobSetCTX(fb, ctx);*/
3077 3077
 				if(textToFileblob(start, fb) == NULL)
3078 3078
 					cli_dbgmsg("Nothing new to save in the bounce message\n");
... ...
@@ -3103,7 +2902,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
3103 3103
 				if((fb = fileblobCreate()) != NULL) {
3104 3104
 					cli_dbgmsg("Found a bounce message with no header at '%s'\n",
3105 3105
 						lineGetData(t_line->t_line));
3106
-					fileblobSetFilename(fb, dir, "bounce");
3106
+					fileblobSetFilename(fb, mctx->dir, "bounce");
3107 3107
 					fileblobAddData(fb,
3108 3108
 						(const unsigned char *)"Received: by clamd (bounce)\n",
3109 3109
 						28);
... ...
@@ -3129,7 +2928,7 @@ parseEmailBody(message *messageIn, text *textIn, const char *dir, const table_t
3129 3129
 				/*
3130 3130
 				 * TODO: May be better to save aText
3131 3131
 				 */
3132
-				saveTextPart(mainMessage, dir);
3132
+				saveTextPart(mainMessage, mctx->dir);
3133 3133
 				if(mainMessage != messageIn) {
3134 3134
 					messageDestroy(mainMessage);
3135 3135
 					mainMessage = NULL;
... ...
@@ -4509,3 +4308,228 @@ binhexMessage(const char *dir, message *m)
4509 4509
 
4510 4510
 	return infected;
4511 4511
 }
4512
+
4513
+/*
4514
+ * Handle the ith element of a number of multiparts, e.g. multipart/alternative
4515
+ */
4516
+static message *
4517
+do_multipart(message *mainMessage, message **messages, int i, int *rc, mbox_ctx *mctx, message *messageIn, text **tptr)
4518
+{
4519
+	bool addToText = FALSE;
4520
+	const char *dtype;
4521
+#ifndef	SAVE_TO_DISC
4522
+	message *body;
4523
+#endif
4524
+	message *aMessage = messages[i];
4525
+
4526
+	if(aMessage == NULL)
4527
+		return mainMessage;
4528
+
4529
+	cli_dbgmsg("Mixed message part %d is of type %d\n",
4530
+		i, messageGetMimeType(aMessage));
4531
+
4532
+	switch(messageGetMimeType(aMessage)) {
4533
+		case APPLICATION:
4534
+		case AUDIO:
4535
+		case IMAGE:
4536
+		case VIDEO:
4537
+			break;
4538
+		case NOMIME:
4539
+			cli_dbgmsg("No mime headers found in multipart part %d\n", i);
4540
+			if(mainMessage) {
4541
+				if(binhexBegin(aMessage)) {
4542
+					cli_dbgmsg("Found binhex message in multipart/mixed mainMessage\n");
4543
+
4544
+					if(binhexMessage(mctx->dir, mainMessage))
4545
+						*rc = 3;
4546
+				}
4547
+				if(mainMessage != messageIn)
4548
+					messageDestroy(mainMessage);
4549
+				mainMessage = NULL;
4550
+			} else if(aMessage) {
4551
+				if(binhexBegin(aMessage)) {
4552
+					cli_dbgmsg("Found binhex message in multipart/mixed non mime part\n");
4553
+					if(binhexMessage(mctx->dir, aMessage))
4554
+						*rc = 3;
4555
+					assert(aMessage == messages[i]);
4556
+					messageReset(messages[i]);
4557
+				}
4558
+			}
4559
+			addToText = TRUE;
4560
+			if(messageGetBody(aMessage) == NULL)
4561
+				/*
4562
+				 * No plain text version
4563
+				 */
4564
+				cli_dbgmsg("No plain text alternative\n");
4565
+			break;
4566
+		case TEXT:
4567
+			dtype = messageGetDispositionType(aMessage);
4568
+			cli_dbgmsg("Mixed message text part disposition \"%s\"\n",
4569
+				dtype);
4570
+			if(strcasecmp(dtype, "attachment") == 0)
4571
+				break;
4572
+			if((*dtype == '\0') || (strcasecmp(dtype, "inline") == 0)) {
4573
+				const char *cptr;
4574
+
4575
+				if(mainMessage && (mainMessage != messageIn))
4576
+					messageDestroy(mainMessage);
4577
+				mainMessage = NULL;
4578
+				cptr = messageGetMimeSubtype(aMessage);
4579
+				cli_dbgmsg("Mime subtype \"%s\"\n", cptr);
4580
+				if((tableFind(mctx->subtypeTable, cptr) == PLAIN) &&
4581
+					  (messageGetEncoding(aMessage) == NOENCODING)) {
4582
+					char *filename;
4583
+					/*
4584
+					 * Strictly speaking
4585
+					 * a text/plain part is
4586
+					 * not an attachment. We
4587
+					 * pretend it is so that
4588
+					 * we can decode and
4589
+					 * scan it
4590
+					 */
4591
+					filename = (char *)messageFindArgument(aMessage, "filename");
4592
+					if(filename == NULL)
4593
+						filename = (char *)messageFindArgument(aMessage, "name");
4594
+
4595
+					if(filename == NULL) {
4596
+						cli_dbgmsg("Adding part to main message\n");
4597
+						addToText = TRUE;
4598
+					} else {
4599
+						cli_dbgmsg("Treating %s as attachment\n",
4600
+							filename);
4601
+						free(filename);
4602
+					}
4603
+				} else {
4604
+					if(mctx->ctx->options&CL_SCAN_MAILURL)
4605
+						if(tableFind(mctx->subtypeTable, cptr) == HTML)
4606
+							checkURLs(aMessage,
4607
+								mctx->dir);
4608
+					messageAddArgument(aMessage,
4609
+						"filename=mixedtextportion");
4610
+				}
4611
+				break;
4612
+			}
4613
+			cli_dbgmsg("Text type %s is not supported\n", dtype);
4614
+			return mainMessage;
4615
+		case MESSAGE:
4616
+			/* Content-Type: message/rfc822 */
4617
+			cli_dbgmsg("Found message inside multipart (encoding type %d)\n",
4618
+				messageGetEncoding(aMessage));
4619
+#ifndef	SCAN_UNENCODED_BOUNCES
4620
+			switch(messageGetEncoding(aMessage)) {
4621
+				case NOENCODING:
4622
+				case EIGHTBIT:
4623
+				case BINARY:
4624
+					if(encodingLine(aMessage) == NULL) {
4625
+						/*
4626
+						 * This means that the message
4627
+						 * has no attachments
4628
+						 *
4629
+						 * The test for
4630
+						 * messageGetEncoding is needed
4631
+						 * since encodingLine won't have
4632
+						 * been set if the message
4633
+						 * itself has been encoded
4634
+						 */
4635
+						cli_dbgmsg("Unencoded multipart/message will not be scanned\n");
4636
+						assert(aMessage == messages[i]);
4637
+						messageDestroy(messages[i]);
4638
+						messages[i] = NULL;
4639
+						return mainMessage;
4640
+					}
4641
+					/* FALLTHROUGH */
4642
+				default:
4643
+					cli_dbgmsg("Encoded multipart/message will be scanned\n");
4644
+			}
4645
+#endif
4646
+#if	0
4647
+			messageAddStrAtTop(aMessage,
4648
+				"Received: by clamd (message/rfc822)");
4649
+#endif
4650
+#ifdef	SAVE_TO_DISC
4651
+			/*
4652
+			 * Save this embedded message
4653
+			 * to a temporary file
4654
+			 */
4655
+			saveTextPart(aMessage, mctx->dir);
4656
+			assert(aMessage == messages[i]);
4657
+			messageDestroy(messages[i]);
4658
+			messages[i] = NULL;
4659
+#else
4660
+			/*
4661
+			 * Scan in memory, faster but
4662
+			 * is open to DoS attacks when
4663
+			 * many nested levels are
4664
+			 * involved.
4665
+			 */
4666
+			body = parseEmailHeaders(aMessage, mctx->rfc821Table,
4667
+				TRUE);
4668
+			/*
4669
+			 * We've fininished with the
4670
+			 * original copy of the message,
4671
+			 * so throw that away and
4672
+			 * deal with the encapsulated
4673
+			 * message as a message.
4674
+			 * This can save a lot of memory
4675
+			 */
4676
+			assert(aMessage == messages[i]);
4677
+			messageDestroy(messages[i]);
4678
+			messages[i] = NULL;
4679
+			if(body) {
4680
+				messageSetCTX(body, ctx);
4681
+				rc = parseEmailBody(body, NULL, mctx);
4682
+				if(messageContainsVirus(body))
4683
+					*rc = 3;
4684
+				messageDestroy(body);
4685
+			}
4686
+#endif
4687
+			return mainMessage;
4688
+		case MULTIPART:
4689
+			/*
4690
+			 * It's a multi part within a multi part
4691
+			 * Run the message parser on this bit, it won't
4692
+			 * be an attachment
4693
+			 */
4694
+			cli_dbgmsg("Found multipart inside multipart\n");
4695
+			if(aMessage) {
4696
+				/*
4697
+				 * The headers were parsed when reading in the
4698
+				 * whole multipart section
4699
+				 */
4700
+				*rc = parseEmailBody(aMessage, *tptr, mctx);
4701
+				cli_dbgmsg("Finished recursion\n");
4702
+				assert(aMessage == messages[i]);
4703
+				messageDestroy(messages[i]);
4704
+				messages[i] = NULL;
4705
+			} else {
4706
+				*rc = parseEmailBody(NULL, NULL, mctx);
4707
+				if(mainMessage && (mainMessage != messageIn))
4708
+					messageDestroy(mainMessage);
4709
+				mainMessage = NULL;
4710
+			}
4711
+			return mainMessage;
4712
+		default:
4713
+			cli_warnmsg("Only text and application attachments are supported, type = %d\n",
4714
+				messageGetMimeType(aMessage));
4715
+			return mainMessage;
4716
+	}
4717
+
4718
+	if(addToText) {
4719
+		cli_dbgmsg("Adding to non mime-part\n");
4720
+		*tptr = textAdd(*tptr, messageGetBody(aMessage));
4721
+	} else {
4722
+		fileblob *fb = messageToFileblob(aMessage, mctx->dir);
4723
+
4724
+		if(fb) {
4725
+			if(fileblobContainsVirus(fb))
4726
+				*rc = 3;
4727
+			fileblobDestroy(fb);
4728
+		}
4729
+	}
4730
+	if(messageContainsVirus(aMessage))
4731
+		*rc = 3;
4732
+	messageDestroy(aMessage);
4733
+	messages[i] = NULL;
4734
+
4735
+	return mainMessage;
4736
+}