git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@1201 77e5149b-7576-45b1-b177-96237e5ba77b

Nigel Horne authored on 2004/12/19 22:50:08
Showing 2 changed files
... ...
@@ -17,6 +17,9 @@
17 17
  *
18 18
  * Change History:
19 19
  * $Log: mbox.c,v $
20
+ * Revision 1.203  2004/12/19 13:50:08  nigelhorne
21
+ * Tidy
22
+ *
20 23
  * Revision 1.202  2004/12/18 16:32:10  nigelhorne
21 24
  * Added parseEmailFile
22 25
  *
... ...
@@ -594,7 +597,7 @@
594 594
  * Compilable under SCO; removed duplicate code with message.c
595 595
  *
596 596
  */
597
-static	char	const	rcsid[] = "$Id: mbox.c,v 1.202 2004/12/18 16:32:10 nigelhorne Exp $";
597
+static	char	const	rcsid[] = "$Id: mbox.c,v 1.203 2004/12/19 13:50:08 nigelhorne Exp $";
598 598
 
599 599
 #if HAVE_CONFIG_H
600 600
 #include "clamav-config.h"
... ...
@@ -752,7 +755,7 @@ static	char	*rfc822comments(const char *in);
752 752
 static	int	rfc1341(message *m, const char *dir);
753 753
 #endif
754 754
 static	bool	usefulHeader(int commandNumber, const char *cmd);
755
-#ifdef	notdef
755
+#if	0
756 756
 static	const	char	*cli_pmemstr(const char *haystack, size_t hs, const char *needle, size_t ns);
757 757
 #endif
758 758
 
... ...
@@ -875,7 +878,7 @@ static	pthread_mutex_t	tables_mutex = PTHREAD_MUTEX_INITIALIZER;
875 875
 #define	O_BINARY	0
876 876
 #endif
877 877
 
878
-#ifdef	notdef
878
+#if	0
879 879
 
880 880
 #if HAVE_MMAP
881 881
 #if HAVE_SYS_MMAN_H
... ...
@@ -888,22 +891,28 @@ static	pthread_mutex_t	tables_mutex = PTHREAD_MUTEX_INITIALIZER;
888 888
 /*
889 889
  * This could be the future. Instead of parsing and decoding it just decodes.
890 890
  * Currently this code is about 50% *slower* than the full blown parser, but
891
- * that may improve with time.
891
+ * that may improve with time. To speed it up we only scan less than 10MB -
892
+ *	need access to the options structure to check StreamMaxLength
892 893
  * USE IT AT YOUR PERIL, a large number of viruses are not detected with this
893 894
  * method, possibly because the decoded files must be exact and not have
894 895
  * extra data at the start or end, which this code will produce.
896
+ *
897
+ * One big hole is that if there's two attachements of the same type it only
898
+ * extracts the first
895 899
  */
896 900
 int
897 901
 cli_mbox(const char *dir, int desc, unsigned int options)
898 902
 {
899
-	char *start, *ptr, *line, *buf, *p;
903
+	char *start, *ptr, *line, *p;
904
+	char *b64start, *quotedstart;
900 905
 	const char *last;
901
-	int decoder;
902
-	long bytesleft;
906
+	int decoder, length;
903 907
 	size_t size, headersize, bodysize;
908
+	long b64size, quotedsize;
904 909
 	struct stat statb;
905 910
 	message *m;
906 911
 	fileblob *fb;
912
+	int ret = 0;
907 913
 
908 914
 	if(fstat(desc, &statb) < 0)
909 915
 		return CL_EOPEN;
... ...
@@ -913,15 +922,12 @@ cli_mbox(const char *dir, int desc, unsigned int options)
913 913
 	if(size == 0)
914 914
 		return CL_CLEAN;
915 915
 
916
-	m = messageCreate();
917
-	if(m == NULL)
918
-		return CL_EMEM;
916
+	if(size > 10*1024*1024)
917
+		return CL_CLEAN;	/* should be StreamMaxLength, I guess */
919 918
 
920 919
 	start = ptr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, desc, 0);
921
-	if(ptr == MAP_FAILED) {
922
-		messageDestroy(m);
920
+	if(ptr == MAP_FAILED)
923 921
 		return CL_EMEM;
924
-	}
925 922
 
926 923
 	cli_dbgmsg("mmap'ed mbox\n");
927 924
 
... ...
@@ -944,7 +950,6 @@ cli_mbox(const char *dir, int desc, unsigned int options)
944 944
 	}
945 945
 	if(ptr >= last) {
946 946
 		cli_dbgmsg("cli_mbox: can't determine the end of the headers\n");
947
-		messageDestroy(m);
948 947
 		munmap(start, size);
949 948
 		return cli_parse_mbox(dir, desc, options);
950 949
 	}
... ...
@@ -954,122 +959,214 @@ cli_mbox(const char *dir, int desc, unsigned int options)
954 954
 
955 955
 	cli_dbgmsg("cli_mbox: size=%u, headersize=%u, bodysize=%u\n", size, headersize, bodysize);
956 956
 
957
-	bytesleft = bodysize;
958
-	buf = ptr;
957
+	b64start = quotedstart = NULL;
958
+	b64size = quotedsize = 0;
959 959
 	decoder = 0;
960 960
 
961
-	/* Would be nice to have a case insensitive cli_memstr() */
962
-	if(cli_pmemstr(start, headersize, "base64", 6)) {
961
+	/*
962
+	 * Would be nice to have a case insensitive cli_memstr()
963
+	 *
964
+	 * This is v. slow especially on large files
965
+	 */
966
+	if((p = (char *)cli_pmemstr(ptr, bodysize, "base64", 6)) != NULL) {
963 967
 		cli_dbgmsg("Header base64\n");
964 968
 		decoder |= 1;
969
+		b64start = &p[6];
970
+		b64size = (size_t)(last - b64start) + 1;
965 971
 	}
966
-	if(cli_pmemstr(start, headersize, "quoted-printable", 16)) {
972
+	if((p = (char *)cli_pmemstr(ptr, bodysize, "quoted-printable", 16)) != NULL) {
967 973
 		cli_dbgmsg("Header quoted-printable\n");
968 974
 		decoder |= 2;
975
+		quotedstart = p;
976
+		quotedsize = (size_t)(last - quotedstart) + 1;
969 977
 	}
970 978
 	if(!(decoder&1))
971 979
 		if((p = (char *)cli_pmemstr(ptr, bodysize, "base64", 6)) != NULL) {
972 980
 			cli_dbgmsg("Body base64\n");
973 981
 			decoder |= 1;
974
-			buf = &p[6];
975
-			bytesleft = (unsigned long)(last - buf) + 1;
976
-			messageSetEncoding(m, "base64");
982
+			b64start = &p[6];
983
+			b64size = (unsigned long)(last - b64start) + 1;
977 984
 		}
978 985
 	if(!(decoder&2))
979 986
 		if((p = (char *)cli_pmemstr(ptr, bodysize, "quoted-printable", 16)) != NULL) {
980 987
 			cli_dbgmsg("Body quoted-printable\n");
981 988
 			decoder |= 2;
982
-			if((p < buf) || (buf == ptr)) {
983
-				buf = &p[16];
984
-				bytesleft = (unsigned long)(last - buf) + 1;
985
-			}
986
-			messageSetEncoding(m, "quoted-printable");
989
+			quotedstart = &p[16];
990
+			quotedsize = (unsigned long)(last - quotedstart) + 1;
987 991
 		}
988 992
 
989 993
 	if(decoder == 0) {
990
-		messageDestroy(m);
991 994
 		munmap(start, size);
992 995
 		cli_dbgmsg("cli_mbox: unknown encoder\n");
993 996
 		return cli_parse_mbox(dir, desc, options);
994 997
 	}
995 998
 
996
-	line = NULL;
999
+	if(b64start) {
1000
+		while(*b64start != '\n') {
1001
+			b64start++;
1002
+			b64size--;
1003
+		}
1004
+		/*
1005
+		 * Look for the end of the headers
1006
+		 */
1007
+		while(b64start < last) {
1008
+			if(*b64start == ';') {
1009
+				b64start++;
1010
+				b64size--;
1011
+			} else if(*b64start == '\n') {
1012
+				b64start++;
1013
+				b64size--;
1014
+				if((*b64start == '\n') || (*b64start == '\r')) {
1015
+					b64start++;
1016
+					b64size--;
1017
+					break;
1018
+				}
1019
+			}
1020
+			b64start++;
1021
+			b64size--;
1022
+		}
997 1023
 
998
-	while(*buf != '\n') {
999
-		buf++;
1000
-		bytesleft--;
1001
-	}
1002
-	/*
1003
-	 * Look for the end of the headers
1004
-	 */
1005
-	while(buf < last) {
1006
-		if(*buf == ';') {
1007
-			buf++;
1008
-			bytesleft--;
1009
-		} else if(*buf == '\n') {
1010
-			buf++;
1011
-			bytesleft--;
1012
-			if((*buf == '\n') || (*buf == '\r')) {
1013
-				buf++;
1014
-				bytesleft--;
1015
-				break;
1024
+		while(!isalnum(*b64start)) {
1025
+			b64start++;
1026
+			b64size--;
1027
+		}
1028
+
1029
+		if(b64size > 0L) {
1030
+			cli_dbgmsg("cli_mbox: decoding %ld base64 bytes\n", b64size);
1031
+
1032
+			line = NULL;
1033
+			length = 0;
1034
+
1035
+			m = messageCreate();
1036
+			if(m == NULL)
1037
+				return CL_EMEM;
1038
+			messageSetEncoding(m, "base64");
1039
+
1040
+			while(b64size > 0L) {
1041
+				length = 0;
1042
+
1043
+				/*printf("%ld: ", bytesleft); fflush(stdout);*/
1044
+
1045
+				for(ptr = b64start; b64size && (*ptr != '\n') && (*ptr != '\r'); ptr++) {
1046
+					length++;
1047
+					--b64size;
1048
+				}
1049
+
1050
+				/*printf("%d: ", length); fflush(stdout);*/
1051
+
1052
+				line = cli_realloc(line, length + 1);
1053
+
1054
+				memcpy(line, b64start, length);
1055
+				line[length] = '\0';
1056
+
1057
+				/*puts(line);*/
1058
+
1059
+				if(messageAddStr(m, line) < 0)
1060
+					break;
1061
+
1062
+				if((b64size > 0) && (*ptr == '\r')) {
1063
+					ptr++;
1064
+					--b64size;
1065
+				}
1066
+				b64start = ++ptr;
1067
+				--b64size;
1068
+				if(strchr(line, '='))
1069
+					break;
1016 1070
 			}
1071
+			fb = messageToFileblob(m, dir);
1072
+			messageDestroy(m);
1073
+
1074
+			if(fb)
1075
+				fileblobDestroy(fb);
1076
+			else
1077
+				ret = -1;
1017 1078
 		}
1018
-		buf++;
1019
-		bytesleft--;
1020 1079
 	}
1080
+	if(quotedstart) {
1081
+		while(*quotedstart != '\n') {
1082
+			quotedstart++;
1083
+			quotedsize--;
1084
+		}
1085
+		/*
1086
+		 * Look for the end of the headers
1087
+		 */
1088
+		while(quotedstart < last) {
1089
+			if(*quotedstart == ';') {
1090
+				quotedstart++;
1091
+				quotedsize--;
1092
+			} else if(*quotedstart == '\n') {
1093
+				quotedstart++;
1094
+				quotedsize--;
1095
+				if((*quotedstart == '\n') || (*quotedstart == '\r')) {
1096
+					quotedstart++;
1097
+					quotedsize--;
1098
+					break;
1099
+				}
1100
+			}
1101
+			quotedstart++;
1102
+			quotedsize--;
1103
+		}
1021 1104
 
1022
-	while(!isalnum(*buf)) {
1023
-		buf++;
1024
-		bytesleft--;
1025
-	}
1105
+		while(!isalnum(*quotedstart)) {
1106
+			quotedstart++;
1107
+			quotedsize--;
1108
+		}
1026 1109
 
1027
-	if(bytesleft > 1024*1024)
1028
-		bytesleft = 1024*1024;	/* should be MaxStreamSize, I guess */
1110
+		if(quotedsize > 0L) {
1111
+			cli_dbgmsg("cli_mbox: decoding %ld quoted-printable bytes\n", quotedsize);
1029 1112
 
1030
-	cli_dbgmsg("cli_mbox: decoding %ld bytes\n", bytesleft);
1113
+			m = messageCreate();
1114
+			if(m == NULL)
1115
+				return CL_EMEM;
1116
+			messageSetEncoding(m, "quoted-printable");
1031 1117
 
1032
-	while(bytesleft > 0) {
1033
-		int length = 0;
1118
+			line = NULL;
1119
+			length = 0;
1034 1120
 
1035
-		/*printf("%ld: ", bytesleft); fflush(stdout);*/
1121
+			while(quotedsize > 0L) {
1122
+				length = 0;
1036 1123
 
1037
-		for(ptr = buf; bytesleft && (*ptr != '\n') && (*ptr != '\r'); ptr++) {
1038
-			length++;
1039
-			--bytesleft;
1040
-		}
1124
+				/*printf("%ld: ", bytesleft); fflush(stdout);*/
1041 1125
 
1042
-		/*printf("%d: ", length); fflush(stdout);*/
1126
+				for(ptr = quotedstart; quotedsize && (*ptr != '\n') && (*ptr != '\r'); ptr++) {
1127
+					length++;
1128
+					--quotedsize;
1129
+				}
1043 1130
 
1044
-		line = cli_realloc(line, length + 1);
1131
+				/*printf("%d: ", length); fflush(stdout);*/
1045 1132
 
1046
-		memcpy(line, buf, length);
1047
-		line[length] = '\0';
1133
+				line = cli_realloc(line, length + 1);
1048 1134
 
1049
-		/*puts(line);*/
1135
+				memcpy(line, quotedstart, length);
1136
+				line[length] = '\0';
1050 1137
 
1051
-		if(messageAddStr(m, line) < 0)
1052
-			break;
1138
+				/*puts(line);*/
1053 1139
 
1054
-		if((bytesleft > 0) && (*ptr == '\r')) {
1055
-			ptr++;
1056
-			bytesleft--;
1140
+				if(messageAddStr(m, line) < 0)
1141
+					break;
1142
+
1143
+				if((quotedsize > 0) && (*ptr == '\r')) {
1144
+					ptr++;
1145
+					--quotedsize;
1146
+				}
1147
+				quotedstart = ++ptr;
1148
+				--quotedsize;
1149
+			}
1150
+			fb = messageToFileblob(m, dir);
1151
+			messageDestroy(m);
1152
+
1153
+			if(fb)
1154
+				fileblobDestroy(fb);
1155
+			else
1156
+				ret = -1;
1057 1157
 		}
1058
-		buf = ++ptr;
1059
-		bytesleft--;
1060 1158
 	}
1061
-	if(line)
1062
-		free(line);
1063 1159
 
1064 1160
 	munmap(start, size);
1065 1161
 
1066
-	fb = messageToFileblob(m, dir);
1067
-	messageDestroy(m);
1068
-
1069
-	if(fb) {
1070
-		fileblobDestroy(fb);
1162
+	if(ret == 0)
1071 1163
 		return CL_CLEAN;	/* a lie - but it gets things going */
1072
-	}
1164
+
1073 1165
 	return cli_parse_mbox(dir, desc, options);
1074 1166
 }
1075 1167
 #else
... ...
@@ -1151,6 +1248,20 @@ cli_parse_mbox(const char *dir, int desc, unsigned int options)
1151 1151
 		/*
1152 1152
 		 * Have been asked to check a UNIX style mbox file, which
1153 1153
 		 * may contain more than one e-mail message to decode
1154
+		 *
1155
+		 * It would be far better for scanners.c to do this splitting
1156
+		 * and do this
1157
+		 *	FOR EACH mail in the mailbox
1158
+		 *	DO
1159
+		 *		pass this mail to cli_mbox --
1160
+		 *		scan this file
1161
+		 *		IF this file has a virus quit
1162
+		 *		THEN
1163
+		 *			return CL_VIRUS
1164
+		 *		FI
1165
+		 *	END
1166
+		 * This would remove a problem with this code that it can
1167
+		 * fill up the tmp directory before it starts scanning
1154 1168
 		 */
1155 1169
 		bool lastLineWasEmpty;
1156 1170
 		int messagenumber;
... ...
@@ -3386,6 +3497,10 @@ rfc1341(message *m, const char *dir)
3386 3386
 	const char *tmpdir;
3387 3387
 	char pdir[NAME_MAX + 1];
3388 3388
 
3389
+	id = (char *)messageFindArgument(m, "id");
3390
+	if(id == NULL)
3391
+		return -1;
3392
+
3389 3393
 #ifdef  CYGWIN
3390 3394
 	if((tmpdir = getenv("TEMP")) == (char *)NULL)
3391 3395
 		if((tmpdir = getenv("TMP")) == (char *)NULL)
... ...
@@ -3419,9 +3534,6 @@ rfc1341(message *m, const char *dir)
3419 3419
 				pdir, statb.st_mode & 0777);
3420 3420
 	}
3421 3421
 
3422
-	id = (char *)messageFindArgument(m, "id");
3423
-	if(id == NULL)
3424
-		return -1;
3425 3422
 	number = (char *)messageFindArgument(m, "number");
3426 3423
 	if(number == NULL) {
3427 3424
 		free(id);
... ...
@@ -3457,6 +3569,7 @@ rfc1341(message *m, const char *dir)
3457 3457
 		int t = atoi(total);
3458 3458
 		DIR *dd = NULL;
3459 3459
 
3460
+		free(total);
3460 3461
 		/*
3461 3462
 		 * If it's the last one - reassemble it
3462 3463
 		 * FIXME: this assumes that we receive the parts in order
... ...
@@ -3473,7 +3586,6 @@ rfc1341(message *m, const char *dir)
3473 3473
 			if(fout == NULL) {
3474 3474
 				cli_errmsg("Can't open '%s' for writing", outname);
3475 3475
 				free(id);
3476
-				free(total);
3477 3476
 				free(number);
3478 3477
 				closedir(dd);
3479 3478
 				return -1;
... ...
@@ -3498,7 +3610,6 @@ rfc1341(message *m, const char *dir)
3498 3498
 #else	/*!HAVE_READDIR_R*/
3499 3499
 				while((dent = readdir(dd))) {
3500 3500
 #endif
3501
-					char fullname[NAME_MAX + 1];
3502 3501
 					FILE *fin;
3503 3502
 					char buffer[BUFSIZ];
3504 3503
 					int nblanks;
... ...
@@ -3510,14 +3621,13 @@ rfc1341(message *m, const char *dir)
3510 3510
 					if(strncmp(filename, dent->d_name, strlen(filename)) != 0)
3511 3511
 						continue;
3512 3512
 
3513
-					sprintf(fullname, "%s/%s", pdir, dent->d_name);
3514
-					fin = fopen(fullname, "rb");
3513
+					sprintf(filename, "%s/%s", pdir, dent->d_name);
3514
+					fin = fopen(filename, "rb");
3515 3515
 					if(fin == NULL) {
3516
-						cli_errmsg("Can't open '%s' for reading", fullname);
3516
+						cli_errmsg("Can't open '%s' for reading", filename);
3517 3517
 						fclose(fout);
3518 3518
 						unlink(outname);
3519 3519
 						free(id);
3520
-						free(total);
3521 3520
 						free(number);
3522 3521
 						closedir(dd);
3523 3522
 						return -1;
... ...
@@ -3528,9 +3638,9 @@ rfc1341(message *m, const char *dir)
3528 3528
 						 * Ensure that trailing newlines
3529 3529
 						 * aren't copied
3530 3530
 						 */
3531
-						if(buffer[0] == '\n') {
3531
+						if(buffer[0] == '\n')
3532 3532
 							nblanks++;
3533
-						} else {
3533
+						else {
3534 3534
 							if(nblanks)
3535 3535
 								do
3536 3536
 									putc('\n', fout);
... ...
@@ -3541,7 +3651,7 @@ rfc1341(message *m, const char *dir)
3541 3541
 
3542 3542
 					/* don't unlink if leave temps */
3543 3543
 					if(!cli_leavetemps_flag)
3544
-						unlink(fullname);
3544
+						unlink(filename);
3545 3545
 					break;
3546 3546
 				}
3547 3547
 				rewinddir(dd);
... ...
@@ -3549,10 +3659,9 @@ rfc1341(message *m, const char *dir)
3549 3549
 			closedir(dd);
3550 3550
 			fclose(fout);
3551 3551
 		}
3552
-		free(number);
3553 3552
 	}
3553
+	free(number);
3554 3554
 	free(id);
3555
-	free(total);
3556 3555
 
3557 3556
 	return 0;
3558 3557
 }
... ...
@@ -3899,7 +4008,7 @@ usefulHeader(int commandNumber, const char *cmd)
3899 3899
 	return FALSE;
3900 3900
 }
3901 3901
 
3902
-#ifdef	notdef
3902
+#if	0
3903 3903
 /*
3904 3904
  * like cli_memstr - but returns the location of the match
3905 3905
  */
... ...
@@ -17,6 +17,9 @@
17 17
  *
18 18
  * Change History:
19 19
  * $Log: message.c,v $
20
+ * Revision 1.133  2004/12/19 13:50:08  nigelhorne
21
+ * Tidy
22
+ *
20 23
  * Revision 1.132  2004/12/16 15:29:51  nigelhorne
21 24
  * Tidy
22 25
  *
... ...
@@ -393,7 +396,7 @@
393 393
  * uuencodebegin() no longer static
394 394
  *
395 395
  */
396
-static	char	const	rcsid[] = "$Id: message.c,v 1.132 2004/12/16 15:29:51 nigelhorne Exp $";
396
+static	char	const	rcsid[] = "$Id: message.c,v 1.133 2004/12/19 13:50:08 nigelhorne Exp $";
397 397
 
398 398
 #if HAVE_CONFIG_H
399 399
 #include "clamav-config.h"
... ...
@@ -441,6 +444,8 @@ static	char	const	rcsid[] = "$Id: message.c,v 1.132 2004/12/16 15:29:51 nigelhor
441 441
 #undef FALSE
442 442
 #endif
443 443
 
444
+#define	RFC2045LENGTH	76	/* maximum number of characters on a line */
445
+
444 446
 typedef enum { FALSE = 0, TRUE = 1 } bool;
445 447
 
446 448
 static	void	messageIsEncoding(message *m);
... ...
@@ -837,9 +842,7 @@ messageAddArguments(message *m, const char *s)
837 837
 			return;
838 838
 		}
839 839
 
840
-		string = data;
841
-
842
-		string++;
840
+		string = &data[1];
843 841
 
844 842
 		/*
845 843
 		 * Handle white space to the right of the equals sign
... ...
@@ -875,9 +878,7 @@ messageAddArguments(message *m, const char *s)
875 875
 				ptr = strchr(key, ':');
876 876
 			*ptr = '\0';
877 877
 
878
-			cptr++;
879
-
880
-			string = strchr(cptr, '"');
878
+			string = strchr(++cptr, '"');
881 879
 
882 880
 			if(string == NULL) {
883 881
 				cli_dbgmsg("Unbalanced quote character in \"%s\"\n", s);
... ...
@@ -1002,7 +1003,6 @@ messageFindArgument(const message *m, const char *variable)
1002 1002
 				if(ret == NULL)
1003 1003
 					return NULL;
1004 1004
 
1005
-				ret[strlen(ret) - 1] = '\0';
1006 1005
 				/*
1007 1006
 				 * Thomas Lamy <Thomas.Lamy@in-online.net>:
1008 1007
 				 * fix un-quoting of boundary strings from
... ...
@@ -1013,8 +1013,10 @@ messageFindArgument(const message *m, const char *variable)
1013 1013
 				 * quoted argument
1014 1014
 				 * end string at next quote
1015 1015
 				 */
1016
-				if((p = strchr(ret, '"')) != NULL)
1016
+				if((p = strchr(ret, '"')) != NULL) {
1017
+					ret[strlen(ret) - 1] = '\0';
1017 1018
 					*p = '\0';
1019
+				}
1018 1020
 				return ret;
1019 1021
 			}
1020 1022
 			return strdup(ptr);
... ...
@@ -1052,16 +1054,37 @@ messageSetEncoding(message *m, const char *enctype)
1052 1052
 		int highestSimil = 0;
1053 1053
 		const char *closest = NULL;
1054 1054
 
1055
-		for(e = encoding_map; e->string; e++)
1056
-			if(strcasecmp(type, e->string) == 0) {
1055
+		for(e = encoding_map; e->string; e++) {
1056
+			int sim;
1057
+			const char lowertype = tolower(type[0]);
1058
+			
1059
+			if((lowertype != tolower(e->string[0])) && (lowertype != 'x'))
1060
+				/*
1061
+				 * simil is expensive, I'm yet to encounter only
1062
+				 * one example of a missent encoding when the
1063
+				 * first character was wrong, so lets assume no
1064
+				 * match to save the call.
1065
+				 *
1066
+				 * That example was quoted-printable sent as
1067
+				 * X-quoted-printable.
1068
+				 */
1069
+				continue;
1070
+
1071
+			sim = simil(type, e->string);
1072
+
1073
+			if(sim == 100) {
1057 1074
 				int j;
1058 1075
 				encoding_type *et;
1059 1076
 
1060 1077
 				for(j = 0; j < m->numberOfEncTypes; j++)
1061
-					if(m->encodingTypes[j] == e->type) {
1062
-						cli_dbgmsg("Ignoring duplicate encoding mechanism\n");
1078
+					if(m->encodingTypes[j] == e->type)
1063 1079
 						break;
1064
-					}
1080
+
1081
+				if(j < m->numberOfEncTypes) {
1082
+					cli_dbgmsg("Ignoring duplicate encoding mechanism '%s'\n",
1083
+						type);
1084
+					break;
1085
+				}
1065 1086
 
1066 1087
 				et = (encoding_type *)cli_realloc(m->encodingTypes, (m->numberOfEncTypes + 1) * sizeof(encoding_type));
1067 1088
 				if(et == NULL)
... ...
@@ -1072,15 +1095,11 @@ messageSetEncoding(message *m, const char *enctype)
1072 1072
 
1073 1073
 				cli_dbgmsg("Encoding type %d is \"%s\"\n", m->numberOfEncTypes, type);
1074 1074
 				break;
1075
-
1076
-			} else {
1077
-				const int sim = simil(type, e->string);
1078
-
1079
-				if(sim > highestSimil) {
1080
-					closest = e->string;
1081
-					highestSimil = sim;
1082
-				}
1075
+			} else if(sim > highestSimil) {
1076
+				closest = e->string;
1077
+				highestSimil = sim;
1083 1078
 			}
1079
+		}
1084 1080
 
1085 1081
 		if(e->string == NULL) {
1086 1082
 			/*
... ...
@@ -2196,6 +2215,7 @@ decodeLine(message *m, encoding_type et, const char *line, unsigned char *buf, s
2196 2196
 	bool softbreak;
2197 2197
 	char *p2;
2198 2198
 	char *copy;
2199
+	char base64buf[RFC2045LENGTH + 1];
2199 2200
 
2200 2201
 	/*printf("decodeLine(et = %d buflen = %u)\n", (int)et, buflen);*/
2201 2202
 
... ...
@@ -2222,70 +2242,6 @@ decodeLine(message *m, encoding_type et, const char *line, unsigned char *buf, s
2222 2222
 				break;
2223 2223
 			}
2224 2224
 
2225
-#if	0
2226
-			/*
2227
-			 * Section 5.1 of RFC2045 states that any number of white
2228
-			 * space characters may appear on the end of the line
2229
-			 * before the final '=' which indicates a soft break.
2230
-			 *
2231
-			 * Section 6.7.(3) of RFC2045 is no clearer.
2232
-			 *
2233
-			 * This means that we have to do a look ahead here.
2234
-			 *
2235
-			 * This is a real pain because not everyone is
2236
-			 * aware of the implication of the above sentence,
2237
-			 * namely that you must encode any white space before
2238
-			 * the final '=' to ensure it is correctly transfered
2239
-			 * otherwise it is dropped.
2240
-			 * This code adheres to the RFC, but I don't think most
2241
-			 * other software does so I may have to change it
2242
-			 */
2243
-			p2 = strchr(line, '\0');
2244
-			if(p2 == line) {	/* empty line */
2245
-				*buf++ = '\n';
2246
-				break;
2247
-			}
2248
-			if(*--p2 == '=') {
2249
-				softbreak = TRUE;
2250
-				do
2251
-					--p2;
2252
-				while(isspace(*p2) && (p2 > line));
2253
-			} else
2254
-				softbreak = FALSE;
2255
-
2256
-			/*
2257
-			 * p2 now points to the last significant character on the line
2258
-			 */
2259
-			while(line <= p2) {
2260
-				if(*line == '=') {
2261
-					unsigned char byte;
2262
-
2263
-					if((*++line == '\0') || (*line == '\n')) {
2264
-						/* soft line break detected */
2265
-						if(!softbreak)
2266
-							cli_warnmsg("Unexpected soft line break\n");
2267
-						break;
2268
-					}
2269
-
2270
-					byte = hex(*line);
2271
-
2272
-					if((*++line == '\0') || (*line == '\n')) {
2273
-						/*
2274
-						 * broken e-mail, not
2275
-						 * adhering to RFC2045
2276
-						 */
2277
-						*buf++ = byte;
2278
-						break;
2279
-					}
2280
-
2281
-					byte <<= 4;
2282
-					byte += hex(*line);
2283
-					*buf++ = byte;
2284
-				} else
2285
-					*buf++ = *line;
2286
-				line++;
2287
-			}
2288
-#else
2289 2225
 			softbreak = FALSE;
2290 2226
 			while((line < (char *)&buf[buflen]) && *line) {
2291 2227
 				if(*line == '=') {
... ...
@@ -2315,7 +2271,6 @@ decodeLine(message *m, encoding_type et, const char *line, unsigned char *buf, s
2315 2315
 					*buf++ = *line;
2316 2316
 				line++;
2317 2317
 			}
2318
-#endif
2319 2318
 			if(!softbreak)
2320 2319
 				/* Put the new line back in */
2321 2320
 				*buf++ = '\n';
... ...
@@ -2328,9 +2283,14 @@ decodeLine(message *m, encoding_type et, const char *line, unsigned char *buf, s
2328 2328
 			 * RFC2045 sets the maximum length to 76 bytes
2329 2329
 			 * but many e-mail clients ignore that
2330 2330
 			 */
2331
-			copy = strdup(line);
2332
-			if(copy == NULL)
2333
-				break;
2331
+			if(strlen(line) < sizeof(base64buf)) {
2332
+				strcpy(base64buf, line);
2333
+				copy = base64buf;
2334
+			} else {
2335
+				copy = strdup(line);
2336
+				if(copy == NULL)
2337
+					break;
2338
+			}
2334 2339
 
2335 2340
 			p2 = strchr(copy, '=');
2336 2341
 			if(p2)
... ...
@@ -2343,7 +2303,8 @@ decodeLine(message *m, encoding_type et, const char *line, unsigned char *buf, s
2343 2343
 			 */
2344 2344
 			buf = decode(m, copy, buf, base64, (p2 == NULL) && ((strlen(copy) & 3) == 0));
2345 2345
 
2346
-			free(copy);
2346
+			if(copy != base64buf)
2347
+				free(copy);
2347 2348
 			break;
2348 2349
 
2349 2350
 		case UUENCODE: