diff -urNw clamav-devel/clamav-milter/Makefile.am clamav-devel.jm-pl3/clamav-milter/Makefile.am
--- clamav-devel/clamav-milter/Makefile.am	Tue Apr  6 18:43:43 2004
+++ clamav-devel.jm-pl3/clamav-milter/Makefile.am	Thu Apr 29 00:40:22 2004
@@ -28,6 +28,8 @@
     $(top_srcdir)/shared/getopt.h \
     $(top_srcdir)/shared/memory.c \
     $(top_srcdir)/shared/memory.h \
+    $(top_srcdir)/shared/vsnprintf_alloc.h\
+    $(top_srcdir)/shared/vsnprintf_alloc.c\
     clamav-milter.c
 
 man_MANS = $(top_srcdir)/docs/man/clamav-milter.8
diff -urNw clamav-devel/clamav-milter/clamav-milter.c clamav-devel.jm-pl3/clamav-milter/clamav-milter.c
--- clamav-devel/clamav-milter/clamav-milter.c	Wed Apr 28 10:28:29 2004
+++ clamav-devel.jm-pl3/clamav-milter/clamav-milter.c	Thu Apr 29 00:40:22 2004
@@ -616,7 +616,7 @@
  */
 static	char	const	rcsid[] = "$Id: clamav-milter.c,v 1.84 2004/04/28 14:28:29 nigelhorne Exp $";
 
-#define	CM_VERSION	"0.70t"
+#define	CM_VERSION	"0.70t-jm-pl2"
 
 /*#define	CONFDIR	"/usr/local/etc"*/
 
@@ -684,6 +684,27 @@
 typedef	unsigned short	in_port_t;
 #endif
 
+#define ALLOC_CHECK(_function_,_pointer_,_cleanup_)	{\
+	int save_errno = errno;				\
+	if(!_pointer_){					\
+		fprintf(stderr,"%s: %s() line %d, %s: ",\
+			__FILE__,			\
+			__func__,			\
+			__LINE__,			\
+			_function_ );			\
+		errno = save_errno;			\
+		perror("");				\
+		if(!_cleanup_)				\
+			exit(save_errno);		\
+		else {					\
+			ret_code = save_errno;		\
+			if(!ret_code)			\
+				ret_code = 1;		\
+			goto cleanup;			\
+		}					\
+	}						\
+}
+
 /*
  * TODO: optional: xmessage on console when virus stopped (SNMP would be real nice!)
  *	Having said that, with LogSysLog you can (on Linux) configure the system
@@ -728,7 +749,8 @@
 	u_char	*body;		/* body of the message if Sflag is set */
 	size_t	bodyLen;	/* number of bytes in body */
 	header_list_t headers;	/* Message headers */
-	long	numBytes;	/* Number of bytes sent so far */
+ 	size_t	numBytes;	/* Number of bytes sent so far */
+ 	char	*envid;		/* Sendmail envid ($i) */
 	char	*received;	/* keep track of received from */
 	const	char	*rejectCode;	/* 550 or 554? */
 	int	discard;	/*
@@ -750,7 +772,7 @@
 static	sfsistat	clamfi_close(SMFICTX *ctx);
 static	void		clamfi_cleanup(SMFICTX *ctx);
 static	void		clamfi_free(struct privdata *privdata);
-static	int		clamfi_send(const struct privdata *privdata, size_t len, const char *format, ...);
+static	size_t		clamfi_send(struct privdata *privdata, size_t len, const char *format, ...);
 static	char		*strrcpy(char *dest, const char *source);
 static	int		clamd_recv(int sock, char *buf, size_t len);
 static	off_t		updateSigFile(void);
@@ -822,10 +844,11 @@
 				 * number of seconds to wait for clamd to
 				 * respond, see ReadTimeout in clamav.conf
 				 */
-static	long	streamMaxLength = -1;	/* StreamMaxLength from clamav.conf */
+static	size_t	streamMaxLength = -1;	/* StreamMaxLength from clamav.conf */
 static	int	logClean = 1;	/*
 				 * Add clean items to the log file
 				 */
+static	int	logInfected = 1; /* Redundantly log verbose infected messages */
 static	char	*signature = "-- \nScanned by ClamAv - http://www.clamav.net\n";
 static	time_t	signatureStamp;
 static	char	*templatefile;	/* e-mail to be sent when virus detected */
@@ -838,6 +861,12 @@
 static	pthread_cond_t	n_children_cond = PTHREAD_COND_INITIALIZER;
 static	unsigned	int	n_children = 0;
 static	unsigned	int	max_children = 0;
+/* 
+ * -1 wait 60 seconds for max_children and continue.
+ * 0  no waiting, exit if max_children.
+ * >0 means wait that long, then exit if neccessary.
+ */ 
+static	int	max_child_wait = 0; 
 short	use_syslog = 0;
 static	const	char	*pidFile;
 static	int	logVerbose = 0;
@@ -871,6 +900,7 @@
 	puts("\t--config-file=FILE\t-c FILE\tRead configuration from FILE.");
 	puts("\t--debug\t\t\t-D\tPrint debug messages.");
 	puts("\t--dont-log-clean\t-C\tDon't add an entry to syslog that a mail is clean.");
+	puts("\t--dont-log-infected\t-I\tDon't add our own entry to syslog that a mail is infected.");
 	puts("\t--dont-scan-on-error\t-d\tPass e-mails through unscanned if a system error occurs.");
 	puts("\t--from=EMAIL\t\t-a EMAIL\tError messages come from here.");
 	puts("\t--force-scan\t\t-f\tForce scan all messages (overrides (-o and -l).");
@@ -878,6 +908,13 @@
 	puts("\t--headers\t\t-H\tInclude original message headers in the report.");
 	puts("\t--local\t\t\t-l\tScan messages sent from machines on our LAN.");
 	puts("\t--outgoing\t\t-o\tScan outgoing messages from this machine.");
+	puts("\t--max-children\t\t-m\tMaximum amount of children to run.");
+	puts("\t--max-child-wait=secs\t-w\tAfter maximum amount of children,");
+	puts("\t\t\t\t\thow long do we wait for less children and do we exit?");
+	puts("\t\t\t\t\t0 or unspecified means no wait and exit.");
+	puts("\t\t\t\t\tNegative value means wait 60 seconds and continue.");
+	puts("\t\t\t\t\tPositive value means wait value seconds ");
+	puts("\t\t\t\t\tand exit if still max-children.");
 	puts("\t--noreject\t\t-N\tDon't reject viruses, silently throw them away.");
 	puts("\t--noxheader\t\t-n\tSuppress X-Virus-Scanned/X-Virus-Status headers.");
 	puts("\t--pidfile=FILE\t\t-i FILE\tLocation of pidfile.");
@@ -899,6 +936,7 @@
 int
 main(int argc, char **argv)
 {
+	int	ret_code = 0;
 	extern char *optarg;
 	const char *cfgfile = CL_DEFAULT_CFG;
 	struct cfgstruct *cpt;
@@ -938,9 +976,9 @@
 	for(;;) {
 		int opt_index = 0;
 #ifdef	CL_DEBUG
-		const char *args = "bc:CDfF:lm:nNop:PqQ:dhHs:St:U:Vx:";
+		const char *args = "bc:CDfF:Ilm:nNop:PqQ:dhHs:St:U:Vw::x:";
 #else
-		const char *args = "bc:CDfF:lm:nNop:PqQ:dhHs:St:U:V";
+		const char *args = "bc:CDfF:Ilm:nNop:PqQ:dhHs:St:U:Vw::";
 #endif
 
 		static struct option long_options[] = {
@@ -957,6 +995,9 @@
 				"dont-log-clean", 0, NULL, 'C'
 			},
 			{
+				"dont-log-infected", 0, NULL, 'I'
+			},
+			{
 				"dont-scan-on-error", 0, NULL, 'd'
 			},
 			{
@@ -1005,6 +1046,9 @@
 				"max-children", 1, NULL, 'm'
 			},
 			{
+				"max-child-wait", 2, NULL, 'w'
+			},
+			{
 				"server", 1, NULL, 's'
 			},
 			{
@@ -1067,6 +1111,9 @@
 			case 'i':	/* pidfile */
 				pidfile = optarg;
 				break;
+			case 'I':	/* pidfile */
+				logInfected = 0;
+				break;
 			case 'l':	/* scan mail from the lan */
 				lflag++;
 				break;
@@ -1116,6 +1163,12 @@
 			case 'V':
 				puts(clamav_version);
 				return EX_OK;
+			case 'w':
+				if(optarg)
+					max_child_wait = atoi(optarg);
+				else
+					max_child_wait = 0;
+				break;
 #ifdef	CL_DEBUG
 			case 'x':
 				debug_level = atoi(optarg);
@@ -1271,6 +1324,8 @@
 		umask(077);
 
 		serverIPs = (long *)cli_malloc(sizeof(long));
+		ALLOC_CHECK("cli_malloc",serverIPs,0);
+			
 		serverIPs[0] = inet_addr("127.0.0.1");
 	} else if((cpt = cfgopt(copt, "TCPSocket")) != NULL) {
 		int i, activeServers;
@@ -1301,6 +1356,7 @@
 		cli_dbgmsg("numServers: %d\n", numServers);
 
 		serverIPs = (long *)cli_malloc(numServers * sizeof(long));
+		ALLOC_CHECK("cli_malloc",serverIPs,0);
 		activeServers = 0;
 
 		for(i = 0; i < numServers; i++) {
@@ -1367,19 +1423,19 @@
 		if((open("/dev/console", O_WRONLY) == 1) ||
 		   (open("/dev/null", O_WRONLY) == 1))
 			dup(1);
-#endif
 
 #ifdef HAVE_SETPGRP
 #ifdef SETPGRP_VOID
 		setpgrp();
-#else
+#else /* SETPGRP_VOID */
 		setpgrp(0,0);
-#endif
-#else
+#endif /* SETPGRP_VOID */
+#else  /* HAVE_SETPGRP */
 #ifdef HAVE_SETSID
 		 setsid();
-#endif
-#endif
+#endif /* HAVE_SETSID */
+#endif /* HAVE_SETPGRP */
+#endif /* CL_DEBUG */
 	}
 
 	if((cpt = cfgopt(copt, "PidFile")) != NULL)
@@ -1453,6 +1509,8 @@
 	signal(SIGPIPE, SIG_IGN);
 
 	return smfi_main();
+cleanup:
+	return(ret_code);
 }
 
 /*
@@ -1575,6 +1633,7 @@
 	fd_set rfds;
 	struct timeval tv;
 	int retval;
+	int ret_code = 0;
 
 	assert(tcpSocket != 0);
 	assert(numServers > 0);
@@ -1583,7 +1642,9 @@
 		return 0;
 
 	servers = (struct sockaddr_in *)cli_calloc(numServers, sizeof(struct sockaddr_in));
+	ALLOC_CHECK("cli_calloc",servers,1);
 	socks = (int *)cli_malloc(numServers * sizeof(int));
+	ALLOC_CHECK("cli_malloc",socks,1);
 
 	FD_ZERO(&rfds);
 
@@ -1663,7 +1724,15 @@
 	cli_dbgmsg("findServer: No response from any server\n");
 	if(use_syslog)
 		syslog(LOG_WARNING, "findServer: No response from any server");
+cleanup:
+	if(ret_code){
+		if(servers)
+			free(servers);
+		if(socks)
+			free(socks);
+	}
 	return 0;
+	
 }
 
 /*
@@ -1817,12 +1886,15 @@
 clamfi_envfrom(SMFICTX *ctx, char **argv)
 {
 	struct privdata *privdata;
+	int	ret_code = 0;
+	char	*envid = smfi_getsymval(ctx,"i"); 
 
 	if(logVerbose)
 		syslog(LOG_DEBUG, "clamfi_envfrom: %s", argv[0]);
 
 	cli_dbgmsg("clamfi_envfrom: %s\n", argv[0]);
 
+
 	if(max_children > 0) {
 		int rc = 0;
 
@@ -1839,6 +1911,22 @@
 			struct timezone tz;
 
 			/*
+			 * If --max-child-wait=0, then we dont bs around with 
+			 * waiting for children to exit.
+			 */
+
+			if(max_child_wait == 0) {
+				pthread_mutex_unlock(&n_children_mutex);
+				if(use_syslog)
+					syslog(LOG_NOTICE,
+						"%s: hit max-children limit (%u >= %u): exiting.",
+						envid, n_children, max_children);
+				clamfi_cleanup(ctx);
+				return cl_error;
+			}
+				
+
+			/*
 			 * Use pthread_cond_timedwait rather than
 			 * pthread_cond_wait since the sendmail which calls
 			 * us will have a timeout that we don't want to exceed
@@ -1849,13 +1937,13 @@
 			 * It stops sendmail getting fidgety.
 			 */
 			gettimeofday(&now, &tz);
-			timeout.tv_sec = now.tv_sec + 60;
+			timeout.tv_sec = now.tv_sec + ((max_child_wait > 0) ? max_child_wait : 60);
 			timeout.tv_nsec = 0;
 
 			if(use_syslog)
 				syslog(LOG_NOTICE,
-					"hit max-children limit (%u >= %u): waiting for some to exit",
-					n_children, max_children);
+					"hit max-children limit (%u >= %u): waiting %d seconds for some to exit",
+					n_children, max_children, timeout.tv_sec - now.tv_sec);
 			do
 				rc = pthread_cond_timedwait(&n_children_cond, &n_children_mutex, &timeout);
 			while(rc != ETIMEDOUT);
@@ -1868,16 +1956,20 @@
 		if(rc == ETIMEDOUT) {
 #ifdef	CL_DEBUG
 			if(use_syslog)
-				syslog(LOG_NOTICE, "Timeout waiting for a child to die");
+#else
+			if(use_syslog && (max_child_wait > 0))
 #endif
+				syslog(LOG_NOTICE, "Timeout waiting for a child to die");
 			cli_dbgmsg("Timeout waiting for a child to die\n");
+			if(max_child_wait > 0 ) {
+				clamfi_cleanup(ctx);
+				return cl_error;
+			}
 		}
 	}
 
 	privdata = (struct privdata *)cli_calloc(1, sizeof(struct privdata));
-	if(privdata == NULL)
-		return cl_error;
-
+ 	ALLOC_CHECK("cli_calloc",privdata,1);
 	privdata->dataSocket = -1;	/* 0.4 */
 	privdata->cmdSocket = -1;	/* 0.4 */
 
@@ -1889,18 +1981,18 @@
 	privdata->rejectCode = "550";
 
 	privdata->from = strdup(argv[0]);
-
-	if(streamMaxLength > 0L)
-		privdata->numBytes = (long)(strlen(argv[0]) + 6);
+	privdata->envid = envid; 
+	if(!privdata->envid)
+		privdata->envid = "Uknown";
 
 	if(hflag)
-		privdata->headers = header_list_new();
+		if(!(privdata->headers = header_list_new()))
+			goto cleanup;
 
 	if(smfi_setpriv(ctx, privdata) == MI_SUCCESS)
 		return SMFIS_CONTINUE;
-
+cleanup:
 	clamfi_free(privdata);
-
 	return cl_error;
 }
 
@@ -1908,29 +2000,35 @@
 clamfi_envrcpt(SMFICTX *ctx, char **argv)
 {
 	struct privdata *privdata = (struct privdata *)smfi_getpriv(ctx);
+	int ret_code = 0;
+	void * p = NULL;
 
 	if(logVerbose)
 		syslog(LOG_DEBUG, "clamfi_envrcpt: %s", argv[0]);
-
 	cli_dbgmsg("clamfi_envrcpt: %s\n", argv[0]);
 
+ 	if(!privdata)
+ 		return cl_error;
+
 	if(privdata->to == NULL) {
 		privdata->to = cli_malloc(sizeof(char *) * 2);
+		ALLOC_CHECK("cli_malloc",privdata->to,1);
 
 		assert(privdata->numTo == 0);
-	} else
-		privdata->to = cli_realloc(privdata->to, sizeof(char *) * (privdata->numTo + 2));
-
+	} else {
+		p = cli_realloc(privdata->to, (sizeof(char *) * (privdata->numTo + 2)));
+		ALLOC_CHECK("cli_realloc",p,1);
+		privdata->to = p;
+	}
 	if(privdata->to == NULL)
 		return cl_error;
 
 	privdata->to[privdata->numTo] = strdup(argv[0]);
 	privdata->to[++privdata->numTo] = NULL;
 
-	if(streamMaxLength > 0L)
-		privdata->numBytes += (long)(strlen(argv[0]) + 4);
-
 	return SMFIS_CONTINUE;
+cleanup:
+	return cl_error;
 }
 
 static sfsistat
@@ -1966,9 +2064,6 @@
 		return cl_error;
 	}
 
-	if(streamMaxLength > 0L)
-		privdata->numBytes += (long)(strlen(headerf) + strlen(headerv) + 3);
-
 	if(hflag)
 		header_list_add(privdata->headers, headerf, headerv);
 	else if((strcasecmp(headerf, "Received") == 0) &&
@@ -2020,8 +2115,6 @@
 		clamfi_cleanup(ctx);
 		return cl_error;
 	}
-	if(streamMaxLength > 0L)
-		privdata->numBytes++;
 
 	/*
 	 * See if the e-mail is only going to members of the list
@@ -2071,27 +2164,17 @@
 clamfi_body(SMFICTX *ctx, u_char *bodyp, size_t len)
 {
 	struct privdata *privdata = (struct privdata *)smfi_getpriv(ctx);
+	void * p = NULL;
+	int ret_code = 0;
 
 	if(logVerbose)
 		syslog(LOG_DEBUG, "clamfi_envbody: %u bytes", len);
 #ifdef	CL_DEBUG
 	cli_dbgmsg("clamfi_envbody: %u bytes\n", len);
 #endif
+	if(!privdata)
+		return cl_error;
 
-	if(streamMaxLength > 0L) {
-		privdata->numBytes += (long)len;
-		if(privdata->numBytes > streamMaxLength) {
-			if(use_syslog) {
-				const char *sendmailId = smfi_getsymval(ctx, "i");
-				if(sendmailId == NULL)
-					sendmailId = "Unknown";
-				syslog(LOG_NOTICE, "%s: Message more than StreamMaxLength (%ld) bytes - not scanned",
-					sendmailId, streamMaxLength);
-			}
-			clamfi_cleanup(ctx);	/* not needed, but just to be safe */
-			return SMFIS_ACCEPT;
-		}
-	}
 	if(clamfi_send(privdata, len, (char *)bodyp) < 0) {
 		clamfi_cleanup(ctx);	/* not needed, but just to be safe */
 		return cl_error;
@@ -2099,17 +2182,22 @@
 	if(Sflag) {
 		if(privdata->body) {
 			assert(privdata->bodyLen > 0);
-			privdata->body = cli_realloc(privdata->body, privdata->bodyLen + len);
+			p = cli_realloc(privdata->body, privdata->bodyLen + len);
+			ALLOC_CHECK("cli_realloc",p,1);
+			privdata->body = p;
 			memcpy(&privdata->body[privdata->bodyLen], bodyp, len);
 			privdata->bodyLen += len;
 		} else {
 			assert(privdata->bodyLen == 0);
 			privdata->body = cli_malloc(len);
+ 			ALLOC_CHECK("cli_malloc",privdata->body,1);
 			memcpy(privdata->body, bodyp, len);
 			privdata->bodyLen = len;
 		}
 	}
 	return SMFIS_CONTINUE;
+cleanup:
+	return cl_error;
 }
 
 static sfsistat
@@ -2117,12 +2205,15 @@
 {
 	int rc = SMFIS_CONTINUE;
 	char *ptr;
-	const char *sendmailId;
 	struct privdata *privdata = (struct privdata *)smfi_getpriv(ctx);
 	char mess[128];
+	int ret_code = 0;
+	void * p = NULL;
+	char **to, *err = NULL;
 
 	if(logVerbose)
 		syslog(LOG_DEBUG, "clamfi_eom");
+
 #ifdef	CL_DEBUG
 	cli_dbgmsg("clamfi_eom\n");
 	assert(privdata != NULL);
@@ -2130,6 +2221,8 @@
 	assert(!((privdata->cmdSocket >= 0) && (privdata->filename != NULL)));
 	assert(privdata->dataSocket >= 0);
 #endif
+	if(!privdata)
+		goto cleanup;
 
 	close(privdata->dataSocket);
 	privdata->dataSocket = -1;
@@ -2159,7 +2252,7 @@
 			return cl_error;
 		}
 
-		snprintf(cmdbuf, sizeof(cmdbuf) - 1, "SCAN %s", privdata->filename);
+		snprintf(cmdbuf, sizeof(cmdbuf) - 1, "MAILSCAN %s", privdata->filename);
 
 		nbytes = (int)strlen(cmdbuf);
 
@@ -2193,10 +2286,6 @@
 	close(privdata->cmdSocket);
 	privdata->cmdSocket = -1;
 
-	sendmailId = smfi_getsymval(ctx, "i");
-	if(sendmailId == NULL)
-		sendmailId = "Unknown";
-
 	if(!nflag)
 		smfi_addheader(ctx, "X-Virus-Scanned", clamav_version);
 
@@ -2207,22 +2296,25 @@
 		if(strstr(mess, "Size exceeded") != NULL) {
 			/*
 			 * Clamd has stopped on StreamMaxLength before us
+			 *
+			 * With my clamd-stream-maxsizenoreturn patch this will never happen.
 			 */
 			if(use_syslog)
 				syslog(LOG_NOTICE, "%s: Message more than StreamMaxLength (%ld) bytes - not scanned",
-					sendmailId, streamMaxLength);
+ 					privdata->envid, streamMaxLength);
 			clamfi_cleanup(ctx);	/* not needed, but just to be safe */
 			return SMFIS_ACCEPT;
 		}
 
-		cli_warnmsg("%s: %s\n", sendmailId, mess);
+		cli_warnmsg("%s: %s\n", privdata->envid, mess);
 		if(use_syslog)
-			syslog(LOG_ERR, "%s: %s\n", sendmailId, mess);
+			syslog(LOG_ERR, "%s: %s\n", privdata->envid, mess);
 		clamfi_cleanup(ctx);
 		return cl_error;
 	}
 
 	if((ptr = strstr(mess, "FOUND")) == NULL) {
+		rc = SMFIS_ACCEPT;
 		if(!nflag)
 			smfi_addheader(ctx, "X-Virus-Status", "Clean");
 
@@ -2230,10 +2322,11 @@
 		 * TODO: if privdata->from is NULL it's probably SPAM, and
 		 * me might consider bouncing it...
 		 */
+		
 		if(use_syslog && logClean)
 			/* Include the sendmail queue ID in the log */
 			syslog(LOG_NOTICE, "%s: clean message from %s",
-				sendmailId,
+				privdata->envid,
 				(privdata->from) ? privdata->from : "an unknown sender");
 
 		if(privdata->body) {
@@ -2243,18 +2336,21 @@
 			off_t len = updateSigFile();
 
 			if(len) {
+				p = NULL;
+
 				assert(Sflag != 0);
 
-				privdata->body = cli_realloc(privdata->body, privdata->bodyLen + len);
-				if(privdata->body) {
+				p = cli_realloc(privdata->body, privdata->bodyLen + len);
+				ALLOC_CHECK("cli_realloc",p,1);
+				privdata->body = p;
 					memcpy(&privdata->body[privdata->bodyLen], signature, len);
 					smfi_replacebody(ctx, privdata->body, privdata->bodyLen + len);
-				}
+				
 			}
 		}
 	} else {
 		char reject[1024];
-		char **to, *virusname;
+		char *virusname;
 
 		*ptr = '\0';	/* Remove the "FOUND" word */
 
@@ -2267,53 +2363,38 @@
 		if(!nflag)
 			smfi_addheader(ctx, "X-Virus-Status", "Infected");
 
-		if(use_syslog) {
+#ifndef	CL_DEBUG
+		if(use_syslog && logInfected) {
+#else
+		{
+#endif /* CL_DEBUG */
+			int i;
 			/*
 			 * Setup err as a list of recipients
 			 */
-			char *err = (char *)cli_malloc(1024);
-			int i;
-
-			if(err == NULL) {
-				clamfi_cleanup(ctx);
-				return cl_error;
-			}
 
-			/*
-			 * Use snprintf rather than printf since we don't know the
-			 * length of privdata->from and may get a buffer overrun
-			 */
-			snprintf(err, 1023, "Intercepted virus from %s to",
+			sprintf_alloc(&err,"Intercepted virus from %s to",
 				privdata->from);
 
-			ptr = strchr(err, '\0');
-
-			i = 1024;
-
 			for(to = privdata->to; *to; to++) {
-				/*
-				 * Re-alloc if we are about run out of buffer space
-				 */
-				if(&ptr[strlen(*to) + 2] >= &err[i]) {
-					i += 1024;
-					err = cli_realloc(err, i);
-					if(err == NULL) {
-						clamfi_cleanup(ctx);
-						return cl_error;
-					}
-					ptr = strchr(err, '\0');
-				}
-				ptr = strrcpy(ptr, " ");
-				ptr = strrcpy(ptr, *to);
+				ptr = NULL;
+				sprintf_alloc(&ptr,"%s %s",err,*to);
+				free(err);
+				err = ptr;
 			}
-			(void)strcpy(ptr, "\n");
 
+			err = NULL;
+			sprintf_alloc(&err,"%s\n",ptr);
+			free(ptr);
+ 			ptr = NULL;
+			if(use_syslog)
 			/* Include the sendmail queue ID in the log */
-			syslog(LOG_NOTICE, "%s: %s%s", sendmailId, mess, err);
+				syslog(LOG_NOTICE, "%s: %s %s", privdata->envid, mess, err);
 #ifdef	CL_DEBUG
 			cli_dbgmsg("%s\n", err);
-#endif
+#endif /* CL_DEBUG */
 			free(err);
+
 		}
 
 		if(!qflag) {
@@ -2381,7 +2462,7 @@
 						 * information
 						 */
 						fprintf(sendmail, "The message %s sent from %s to\n",
-							sendmailId, from);
+							privdata->envid, from);
 					else
 						fprintf(sendmail, "A message sent from %s to\n",
 							from);
@@ -2469,8 +2550,12 @@
 		snprintf(reject, sizeof(reject) - 1, "%sdetected by ClamAV - http://www.clamav.net", virusname);
 		smfi_setreply(ctx, (char *)privdata->rejectCode, "5.7.1", reject);
 	}
+cleanup:
 	clamfi_cleanup(ctx);
-
+	if(ret_code){
+		if(err)
+			free(err);
+	}
 	return rc;
 }
 
@@ -2616,13 +2701,16 @@
 }
 
 /*
- * Returns < 0 for failure
+ * Return number of bytes written or < 0 for failure
+ * 
  */
-static int
-clamfi_send(const struct privdata *privdata, size_t len, const char *format, ...)
+static size_t
+clamfi_send(struct privdata *privdata, size_t len, const char *format, ...)
 {
-	char output[BUFSIZ];
+	char * output = NULL;
 	const char *ptr;
+	size_t numBytes = 0;
+	size_t ret_code = 0;
 
 	assert(format != NULL);
 
@@ -2636,7 +2724,9 @@
 		va_list argp;
 
 		va_start(argp, format);
-		vsnprintf(output, sizeof(output), format, argp);
+		vsprintf_alloc(&output, format, argp);
+		ALLOC_CHECK("vsprintf_alloc",output,1);
+			
 		va_end(argp);
 
 		len = strlen(output);
@@ -2656,6 +2746,23 @@
 	}
 #endif
 
+	if(!quarantine_dir && (
+		len + privdata->numBytes > streamMaxLength) 
+	   ){
+		if(use_syslog && privdata->numBytes != streamMaxLength){
+                        char buf[1024];
+                        syslog(LOG_INFO,"%s: size exceeded max of %u , "
+					"already wrote %u, will write %u more instead "
+					"of len %u",
+                                        privdata->envid,
+                                        streamMaxLength,
+                                        privdata->numBytes,
+                                        streamMaxLength - privdata->numBytes,
+					len);
+                }
+		len = (streamMaxLength - privdata->numBytes);
+	}
+
 	while(len > 0) {
 		const int nbytes = (quarantine_dir) ?
 			write(privdata->dataSocket, ptr, len) :
@@ -2679,13 +2786,24 @@
 #endif
 			}
 			checkClamd();
-
-			return -1;
+			ret_code = -1;
+			goto cleanup;
 		}
+		numBytes += nbytes;
+		privdata->numBytes += nbytes;
 		len -= nbytes;
 		ptr = &ptr[nbytes];
 	}
-	return 0;
+cleanup:
+	if(output)
+		free(output);
+	if(ret_code){
+#ifdef CL_DEBUG
+		cli_dbgmsg("vsprintf_alloc: %s\n",output);
+#endif
+		return(-1);
+	}
+	return numBytes;
 }
 
 /*
@@ -2743,6 +2861,8 @@
 {
 	struct stat statb;
 	int fd;
+	int ret_code = 0;
+	void * p = NULL;
 
 	if(sigFilename == NULL)
 		/* nothing to read */
@@ -2767,25 +2887,32 @@
 	}
 
 	signatureStamp = statb.st_mtime;
+	p = cli_realloc(signature, statb.st_size + 1);
+	ALLOC_CHECK("cli_realloc",p,1);
+	signature = p;
 
-	cli_realloc(signature, statb.st_size);
 	read(fd, signature, statb.st_size);
 	close(fd);
 
 	return statb.st_size;
+cleanup:
+	return strlen(signature);
 }
 
 static header_list_t
 header_list_new(void)
 {
+	int ret_code = 0;
+	void * p = NULL;
 	header_list_t ret;
 
 	ret = (header_list_t)cli_malloc(sizeof(struct header_list_struct));
-	if(ret) {
+	ALLOC_CHECK("cli_malloc",ret,1);
 		ret->first = NULL;
 		ret->last = NULL;
-	}
 	return ret;
+cleanup:
+	return NULL;
 }
 
 static void
@@ -2809,19 +2936,16 @@
 	char *header;
 	size_t len;
 	struct header_node_t *new_node;
+	int ret_code = 0;
 
 	len = strlen(headerf) + strlen(headerv) + 3;
 
 	header = (char *)cli_malloc(len);
-	if(header == NULL)
-		return;
+	ALLOC_CHECK("cli_malloc",header,1);
 
 	sprintf(header, "%s: %s", headerf, headerv);
 	new_node = (struct header_node_t *)cli_malloc(sizeof(struct header_node_t));
-	if(new_node == NULL) {
-		free(header);
-		return;
-	}
+	ALLOC_CHECK("cli_malloc",new_node,1);
 	new_node->header = header;
 	new_node->next = NULL;
 	if(!list->first)
@@ -2830,6 +2954,13 @@
 		list->last->next = new_node;
 
 	list->last = new_node;
+cleanup:
+	if(ret_code){
+		if(header)
+			free(header);
+		if(new_node)
+			free(new_node);
+	}	
 }
 
 static void
@@ -2851,6 +2982,9 @@
 static int
 connect2clamd(struct privdata *privdata)
 {
+	int  ret = 0;
+	int	ret_code = 0;
+
 	char **to;
 
 	assert(privdata != NULL);
@@ -2887,7 +3021,7 @@
 		DD = tm->tm_mday;
 
 		privdata->filename = (char *)cli_malloc(strlen(quarantine_dir) + 19);
-
+		ALLOC_CHECK("cli_malloc",privdata->filename,1);
 		sprintf(privdata->filename, "%s/%02d%02d%02d", quarantine_dir,
 			YY, MM, DD);
 
@@ -2980,7 +3114,7 @@
 
 		shutdown(privdata->dataSocket, SHUT_RD);
 
-		if(send(privdata->cmdSocket, "STREAM\n", 7, 0) < 7) {
+		if(send(privdata->cmdSocket, "MAILSTREAM\n", 11, 0) < 7) {
 			perror("send");
 			if(use_syslog)
 				syslog(LOG_ERR, "send failed to clamd");
@@ -3058,6 +3192,8 @@
 	cli_dbgmsg("connect2clamd OK\n");
 
 	return 1;
+cleanup:
+	return 0;
 }
 
 /*
diff -urNw clamav-devel/clamd/scanner.c clamav-devel.jm-pl3/clamd/scanner.c
--- clamav-devel/clamd/scanner.c	Tue Apr 13 21:27:22 2004
+++ clamav-devel.jm-pl3/clamd/scanner.c	Thu Apr 29 00:40:22 2004
@@ -33,6 +33,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
+#include <errno.h>
 #include <clamav.h>
 
 #include "cfgparser.h"
@@ -194,7 +195,7 @@
 
 int scanstream(int odesc, unsigned long int *scanned, const struct cl_node *root, const struct cl_limits *limits, int options, const struct cfgstruct *copt)
 {
-	int ret, portscan = CL_DEFAULT_MAXPORTSCAN, sockfd, port, acceptd, tmpd, bread, retval, timeout;
+	int ret, portscan = CL_DEFAULT_MAXPORTSCAN, sockfd, port, acceptd, tmpd, bread, btread, retval, timeout;
 	long int size = 0, maxsize = 0;
 	short bound = 0;
 	const char *virname;
@@ -287,24 +288,15 @@
 	if((cpt = cfgopt(copt, "StreamMaxLength")))
 	    maxsize = cpt->numarg;
 
+	btread = sizeof(buff);
+
 	while((retval = poll_fd(acceptd, timeout)) == 1) {
-	    bread = read(acceptd, buff, sizeof(buff));
+	    bread = read(acceptd, buff, btread);
 	    if (bread <= 0) {
 		break;
 	    }
 	    size += bread;
 
-	    if(maxsize && (size + sizeof(buff)) > maxsize) {
-		shutdown(sockfd, 2);
-		close(sockfd);
-		close(acceptd);
-		mdprintf(odesc, "Size exceeded ERROR\n");
-		logg("^ScanStream: Size exceeded (stopped at %d, max: %d)\n", size, maxsize);
-		if(tmp)
-		    fclose(tmp);
-		return -1;
-	    }
-
 	    if(writen(tmpd, buff, bread) != bread) {
 		shutdown(sockfd, 2);
 		close(sockfd);
@@ -316,7 +308,20 @@
 		return -1;
 	    }
 
+	    if(maxsize && (size + btread > maxsize))
+		    btread = (maxsize - size); /* only read up to max */
+	    if (!btread) {
+		logg("^ScanStream: Size limit reached ( max: %d)\n", maxsize);
+	    	break; /* Scan what we have */
+	    }
+
 	}
+	if(retval == 0)
+            logg("!ScanStream: poll_fd timedout %d\n",timeout);
+        if(retval == -1)
+            logg("!ScanStream: poll_fd returned %s\n",strerror(errno));
+
+
 
 	lseek(tmpd, 0, SEEK_SET);
 	ret = cl_scandesc(tmpd, &virname, scanned, root, limits, options);
diff -urNw clamav-devel/clamd/session.c clamav-devel.jm-pl3/clamd/session.c
--- clamav-devel/clamd/session.c	Mon Mar 29 10:06:07 2004
+++ clamav-devel.jm-pl3/clamd/session.c	Thu Apr 29 00:40:22 2004
@@ -54,6 +54,9 @@
 #define CMD9 "SESSION"
 #define CMD10 "END"
 #define CMD11 "SHUTDOWN"
+#define CMD12 "MAILSTREAM"
+#define CMD13 "MAILSCAN"
+#define CMD14 "CONTMAILSCAN"
 
 
 int command(int desc, const struct cl_node *root, const struct cl_limits *limits, int options, const struct cfgstruct *copt)
@@ -150,6 +153,27 @@
     } else if(!strncmp(buff, CMD11, strlen(CMD11))) { /* SHUTDOWN */
 	return COMMAND_QUIT;
 
+    } else if(!strncmp(buff, CMD12, strlen(CMD12))) { /* MAILSTREAM */
+	if((cpt = cfgopt(copt,"ScanMail"))) {
+	    options |= CL_UNKNOWN_MAIL;
+	    scanstream(desc, NULL, root, limits, options, copt);
+	} else {
+	    mdprintf(desc, "UNKNOWN COMMAND\n");
+	}
+    } else if(!strncmp(buff, CMD13, strlen(CMD13))) { /* MAILSCAN */
+	if((cpt = cfgopt(copt,"ScanMail"))) {
+	    options |= CL_UNKNOWN_MAIL;
+	    scan(buff + strlen(CMD13) + 1, NULL, root, limits, options, copt, desc, 0);
+	} else {
+	    mdprintf(desc, "UNKNOWN COMMAND\n");
+	}
+    } else if(!strncmp(buff, CMD14, strlen(CMD14))) { /* CONTMAILSCAN */
+	if((cpt = cfgopt(copt,"ScanMail"))) {
+	    options |= CL_UNKNOWN_MAIL;
+	    scan(buff + strlen(CMD14) + 1, NULL, root, limits, options, copt, desc, 1);
+	} else {
+	    mdprintf(desc, "UNKNOWN COMMAND\n");
+	}
     } else {
 	mdprintf(desc, "UNKNOWN COMMAND\n");
     }
diff -urNw clamav-devel/clamdscan/clamdscan.c clamav-devel.jm-pl3/clamdscan/clamdscan.c
--- clamav-devel/clamdscan/clamdscan.c	Sat Apr 10 18:43:41 2004
+++ clamav-devel.jm-pl3/clamdscan/clamdscan.c	Thu Apr 29 00:40:22 2004
@@ -126,6 +126,8 @@
     mprintf("    --verbose           -v             Be verbose\n");
     mprintf("    --quiet                            Be quiet, only output error messages\n");
     mprintf("    --stdout                           Write to stdout instead of stderr\n");
+    mprintf("    --mail, --mbox-force, -M           All unknown file type will be a RFC822 mail file\n");
+    mprintf("    --stdout                           Write to stdout instead of stderr\n");
     mprintf("                                       (this help is always written to stdout)\n");
     mprintf("    --log=FILE          -l FILE        Save scan report in FILE\n");
     mprintf("    --log-verbose                      Log additional messages\n");
diff -urNw clamav-devel/clamdscan/client.c clamav-devel.jm-pl3/clamdscan/client.c
--- clamav-devel/clamdscan/client.c	Tue Apr  6 18:43:43 2004
+++ clamav-devel.jm-pl3/clamdscan/client.c	Thu Apr 29 00:40:22 2004
@@ -55,6 +55,7 @@
 	int sockd, wsockd, loopw = 60, bread, port;
 	const char *clamav_conf = getargl(opt, "config-file");
 	FILE *fd;
+	short unknown_mail = 0;
 
     if(!clamav_conf)
 	clamav_conf = DEFAULT_CFG;
@@ -64,6 +65,15 @@
 	return 2;
     }
 
+     if((cfgopt(copt, "ScanMail")) &&
+	(
+	    (optl(opt, "mbox-force")) ||
+	    (optl(opt, "mail")) ||
+	    (optc(opt, 'M'))
+         )
+        ) 
+	unknown_mail = 1;	    
+
     /* Set default address to connect to; needed for scanning a stream and no TCP address specified */
     server2.sin_addr.s_addr = inet_addr("127.0.0.1");    
     if(cfgopt(copt, "ScannerDaemonOutputFormat")) {
@@ -137,7 +147,7 @@
 	file = (char *) strdup(cwd);
 
     } else if(!strcmp(opt->filename, "-")) { /* scan data from stdin */
-	if(write(sockd, "STREAM", 6) <= 0) {
+	if(write(sockd, (unknown_mail) ? "MAILSTREAM" : "STREAM", (unknown_mail) ? 10 : 6) <= 0) {
 	    mprintf("@Can't write to the socket.\n");
 	    close(sockd);
 	    return 2;
@@ -229,7 +239,7 @@
 
 
     scancmd = mcalloc(strlen(file) + 20, sizeof(char));
-    sprintf(scancmd, "CONTSCAN %s", file);
+    sprintf(scancmd, "%s %s", (unknown_mail)? "CONTMAILSCAN" : "CONTSCAN", file);
     free(file);
 
     if(write(sockd, scancmd, strlen(scancmd)) <= 0) {
diff -urNw clamav-devel/clamscan/clamscan.c clamav-devel.jm-pl3/clamscan/clamscan.c
--- clamav-devel/clamscan/clamscan.c	Fri Apr 16 11:46:39 2004
+++ clamav-devel.jm-pl3/clamscan/clamscan.c	Thu Apr 29 00:40:22 2004
@@ -208,6 +208,10 @@
     mprintf("    --bell                               Sound bell on virus detection\n");
     mprintf("    --no-summary                         Disable summary at end of scanning\n");
     mprintf("    --mbox                -m             Treat stdin as a mailbox\n");
+    mprintf("    --mbox-force          -M\n");
+    mprintf("    --mail                -M             Unrecognized filetypes  will be be treated\n");
+    mprintf("                                         as RFC822 mail file.\n");
+    mprintf("                                         This implies --mbox (-m)\n");
     mprintf("\n");
     mprintf("    --no-ole2                            Disable OLE2 support\n");
     mprintf("    --no-archive                         Disable libclamav archive support\n");
diff -urNw clamav-devel/clamscan/manager.c clamav-devel.jm-pl3/clamscan/manager.c
--- clamav-devel/clamscan/manager.c	Tue Apr 27 08:55:18 2004
+++ clamav-devel.jm-pl3/clamscan/manager.c	Thu Apr 29 00:40:22 2004
@@ -373,6 +373,12 @@
     if(optc(opt, 'm'))
 	options |= CL_MAIL;
 
+    if(optc(opt, 'M') || optl(opt,"mail")) {
+	options |= CL_MAIL;
+	options |= CL_UNKNOWN_MAIL;
+    }
+	
+
     /* 
      * check the extension  - this is a special case, normally we don't need to
      * do this (libclamav detects archive by its magic string), but here we
diff -urNw clamav-devel/clamscan/options.c clamav-devel.jm-pl3/clamscan/options.c
--- clamav-devel/clamscan/options.c	Tue Apr 20 18:33:26 2004
+++ clamav-devel.jm-pl3/clamscan/options.c	Thu Apr 29 00:40:22 2004
@@ -43,7 +43,7 @@
 	int ret, opt_index, i, len;
 	struct optstruct *opt;
 
-	const char *getopt_parameters = "hvd:wriVl:m";
+	const char *getopt_parameters = "hvd:wriVl:mM";
 
 	static struct option long_options[] = {
 	    /* 
@@ -82,6 +82,8 @@
 	    {"block-encrypted", 0, 0, 0},
 	    {"no-ole2", 0, 0, 0},
 	    {"mbox", 0, 0, 'm'},
+	    {"mbox-force", 0, 0, 'M'},
+	    {"mail", 0, 0, 0},
 	    {"stdout", 0, 0, 0},
 	    {"unzip", 2, 0, 0},
 	    {"unrar", 2, 0, 0},
diff -urNw clamav-devel/docs/man/clamav-milter.8 clamav-devel.jm-pl3/docs/man/clamav-milter.8
--- clamav-devel/docs/man/clamav-milter.8	Wed Apr 28 10:29:06 2004
+++ clamav-devel.jm-pl3/docs/man/clamav-milter.8	Thu Apr 29 00:40:22 2004
@@ -64,6 +64,13 @@
 \fBclamav.conf\fR since it gives a feel-good factor.
 This option turns that off.
 .TP
+\fB-I, \-\-dont-log-infected\fR
+Messages with viruses are usually logged if SysLog is set in
+\fBclamav.conf\fR since it gives a feel-good factor.
+
+However, since sendmail will log it for us (if MilterLogLevel > 1 or if LOG_LEVEL is high enough), you may find that to be redundant.
+This option turns that off.
+.TP
 \fB-d, \-\-dont-scan-on-error\fR
 If a system error occurs pass messages through unscanned,
 usually when a system error occurs the milter raises a temporary failure which
@@ -143,7 +150,13 @@
 \fB\-\-max\-children=n, \-m n\fR
 Maximum number of children.
 There is no default, if this argument is not \fBclamav\-milter\fR will
-spawn as many children as is necessary.
+spawn as many children as is necessary, except see clamav.conf(5) for the MaxThreads option.
+.TP
+\fB\-\-max\-child\-wait=n, \-w n\fR
+Maximum amount of time to wait for number of children to climb down from max\-children.
+If this is negative than we wait 60 seconds and then continue.
+If this is zero or unspecified we do not wait and we exit. This is the default.
+If this is positive we wait that many seconds for less than max\-children and if not, we then exit.
 .TP
 \fB\-\-template\-file=file \-t file\fR
 File points to a file whose contents is sent whenever a virus is intercepted.
diff -urNw clamav-devel/docs/man/clamav.conf.5 clamav-devel.jm-pl3/docs/man/clamav.conf.5
--- clamav-devel/docs/man/clamav.conf.5	Fri Apr 16 11:46:39 2004
+++ clamav-devel.jm-pl3/docs/man/clamav.conf.5	Thu Apr 29 00:40:22 2004
@@ -169,6 +169,11 @@
 .br 
 Default: disabled.
 .TP 
+\fBScanUnknownAsMail\fR
+If ScanMail is enabled, and we cannot recognize the file type, treat it as a Mbox, Maildir or raw mail file.
+.br 
+Default: disabled.
+.TP 
 \fBScanArchive\fR
 Enable archive scanning.
 .br 
diff -urNw clamav-devel/docs/man/clamdscan.1 clamav-devel.jm-pl3/docs/man/clamdscan.1
--- clamav-devel/docs/man/clamdscan.1	Fri Feb 20 10:49:29 2004
+++ clamav-devel.jm-pl3/docs/man/clamdscan.1	Thu Apr 29 00:40:22 2004
@@ -5,7 +5,7 @@
 clamdscan \- scan files and directories against viruses using Clam AntiVirus Daemon
 .SH "SYNOPSIS"
 .LP 
-clamdscan [options] [file/directory]
+clamdscan [options] [file/directory] [-]
 .SH "DESCRIPTION"
 .LP 
 clamdscan is a simple clamd client which may be used as a clamscan replacement. clamdscan accepts all the options implemented in clamscan but most of them will be ignored because its scanning abilities only depend on clamd. clamdscan is a part of the Clam AntiVirus package.
@@ -34,6 +34,9 @@
 \fB\-l FILE, \-\-log=FILE\fR
 Save the scan report to FILE.
 .TP 
+\fB\-M, \-\-mail, \-\-mbox-force\fR
+Use protocol commands to clamd to request mbox mode on to be scanned content, if it is unrecognized by clamd. 
+.TP
 \fB\-\-log\-verbose\fR
 Save additional messages (mostly useless) to the report file.
 .TP 
@@ -53,6 +56,11 @@
 (2) To scan all files in /home:
 
 \fBclamdscan /home\fR
+.TP
+(3) To scan standard in (stream):
+
+\fBcat myfile | clamdscan -\fR
+
 .SH "RETURN CODES"
 .LP 
 0 : No virus found.
diff -urNw clamav-devel/docs/man/clamscan.1 clamav-devel.jm-pl3/docs/man/clamscan.1
--- clamav-devel/docs/man/clamscan.1	Tue Apr 20 18:33:29 2004
+++ clamav-devel.jm-pl3/docs/man/clamscan.1	Thu Apr 29 00:40:22 2004
@@ -57,6 +57,9 @@
 .TP 
 \fB\-\-mbox\fR
 Enable scanning of various mail file types (also treat stdin as a mailbox \- for backward compatibility).
+.TP
+\fB\-M, \-\-mail, \-\-mbox-force\fR
+Request mbox mode on to be scanned content, if it is unrecognized by libclamav. This implies \-\-mbox. 
 .TP 
 \fB\-i, \-\-infected\fR
 Only print infected files.
diff -urNw clamav-devel/libclamav/clamav.h clamav-devel.jm-pl3/libclamav/clamav.h
--- clamav-devel/libclamav/clamav.h	Sat Mar 13 15:08:10 2004
+++ clamav-devel.jm-pl3/libclamav/clamav.h	Thu Apr 29 00:40:22 2004
@@ -69,6 +69,7 @@
 #define CL_DISABLERAR	4
 #define CL_OLE2		8
 #define CL_ENCRYPTED    16
+#define CL_UNKNOWN_MAIL	32
 
 struct cli_patt {
     short int *pattern;
diff -urNw clamav-devel/libclamav/scanners.c clamav-devel.jm-pl3/libclamav/scanners.c
--- clamav-devel/libclamav/scanners.c	Tue Apr 27 19:37:32 2004
+++ clamav-devel.jm-pl3/libclamav/scanners.c	Thu Apr 29 00:40:22 2004
@@ -58,6 +58,7 @@
 #define SCAN_OLE2	    (options & CL_OLE2)
 #define DISABLE_RAR	    (options & CL_DISABLERAR)
 #define DETECT_ENCRYPTED    (options & CL_ENCRYPTED)
+#define SCAN_UNKNOWN_MAIL    (options & CL_UNKNOWN_MAIL)
 
 struct cli_magic_s {
     int offset;
@@ -885,6 +886,9 @@
     }
 
     type = cli_filetype(magic, bread);
+
+	if(type == CL_UNKNOWN_TYPE && SCAN_UNKNOWN_MAIL)
+		type = CL_MAILFILE;
 
     switch(type) {
 	case CL_RARFILE:
diff -urNw clamav-devel/shared/cfgparser.c clamav-devel.jm-pl3/shared/cfgparser.c
--- clamav-devel/shared/cfgparser.c	Fri Apr 16 11:46:40 2004
+++ clamav-devel.jm-pl3/shared/cfgparser.c	Thu Apr 29 00:40:22 2004
@@ -62,6 +62,7 @@
 	    {"TemporaryDirectory", OPT_STR},
 	    {"MaxFileSize", OPT_COMPSIZE},
 	    {"ScanMail", OPT_NOARG},
+	    {"ScanUnknownAsMail", OPT_NOARG},
 	    {"ScanOLE2", OPT_NOARG},
 	    {"ScanArchive", OPT_NOARG},
 	    {"ScanRAR", OPT_NOARG},
diff -urNw clamav-devel/shared/vsnprintf_alloc.c clamav-devel.jm-pl3/shared/vsnprintf_alloc.c
--- clamav-devel/shared/vsnprintf_alloc.c	Wed Dec 31 19:00:00 1969
+++ clamav-devel.jm-pl3/shared/vsnprintf_alloc.c	Thu Apr 29 00:40:22 2004
@@ -0,0 +1,133 @@
+#include <vsnprintf_alloc.h>
+
+
+
+
+size_t vsnprintf_alloc(char **p, size_t len, const char * fmt, va_list argp)
+{
+	char	*buf = NULL;
+	short	we_malloced = 0;
+	size_t	retlen = 0;
+
+	if(!fmt)
+		return -1;
+	if(!p)
+		return -1;
+	if(len < 0)
+		return len;
+
+	if(*p)
+		buf = *p;
+	
+	{
+		size_t	print_len = strlen(fmt) + BUFSIZ;
+		char	*bufp = NULL;
+
+	do 
+	{
+		if(!buf && !(buf = malloc(print_len + 1)))
+			return -1;
+		else
+			we_malloced = 1;
+		if(retlen)
+		{
+			if(retlen == -1)
+			{/* For optimization, switch this to doubling? */
+				print_len += BUFSIZ;
+			} 
+			else if(retlen > print_len) 
+			{
+				print_len = retlen;
+			}
+			if(len && print_len > len)
+				print_len = len;
+			bufp = realloc(buf, print_len + 1);
+			if(!bufp)
+			{
+				if(we_malloced)
+					free(buf);
+				else
+					*p = buf;
+				return -1;
+			}
+			else
+				buf = bufp;
+		}
+		retlen  = vsnprintf(buf, print_len + 1, fmt, argp);
+		buf[print_len] = '\0';
+
+	} while( (!len || print_len < len ) && (retlen == -1 || retlen > print_len) );
+		/* This block intentionaly left blank */
+	}
+	
+	*p = buf;
+	return(retlen);
+}
+
+size_t vsprintf_alloc(char **p, const char * fmt, va_list argp)
+{
+	size_t retlen = 0;
+	char * buf = NULL;
+
+	if(!fmt)
+		return -1;
+	if(!p)
+		return -1;
+
+	buf = *p;
+	retlen = vsnprintf_alloc(&buf, 0, fmt, argp);
+	*p = buf;
+
+	return(retlen);
+
+}	
+
+size_t snprintf_alloc(char **p, size_t len, const char * fmt, ...)
+{
+	size_t retlen = 0;
+	char * buf = NULL;
+	va_list argp;
+
+	if(!fmt)
+		return -1;
+	if(!p)
+		return -1;
+	if(len < 0)
+		return -1;
+
+	va_start(argp, fmt);
+	buf = *p;
+	retlen = vsnprintf_alloc(&buf, len, fmt, argp);
+	*p = buf;
+	va_end(argp);
+
+	return(retlen);
+
+}	
+
+size_t sprintf_alloc(char **p, const char * fmt, ...)
+{
+	size_t retlen = 0;
+	char * buf = NULL;
+	va_list argp;
+
+	if(!fmt)
+		return -1;
+	if(!p)
+		return -1;
+
+	va_start(argp, fmt);
+	buf = *p;
+	retlen = vsprintf_alloc(&buf, fmt, argp);
+	*p = buf;
+	va_end(argp);
+
+	return(retlen);
+
+}	
+
+struct vsnprintf_alloc_cfg *
+vsnprintf_alloc_configure(struct vsnprintf_alloc_cfg * cfg)
+{
+
+}
diff -urNw clamav-devel/shared/vsnprintf_alloc.h clamav-devel.jm-pl3/shared/vsnprintf_alloc.h
--- clamav-devel/shared/vsnprintf_alloc.h	Wed Dec 31 19:00:00 1969
+++ clamav-devel.jm-pl3/shared/vsnprintf_alloc.h	Thu Apr 29 00:40:22 2004
@@ -0,0 +1,58 @@
+#ifndef VSNPRINTF_ALLOC_H
+	#define VSNPRINTF_ALLOC_H
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+
+/*
+ * Takes: address of pointer to char, optional maximum length, printf(3) format string, and a variable list of arguments
+ * Returns: -1 for error or number of bytes (that would have been) printed into string.
+ * 
+ * The address of pointer to char MUST not be null. 
+ *
+ * If the pointer to char is NOT null, it MUST be a valid malloc'd memory string.
+ * 
+ * if pointer to char is null, malloc will be called and the address stored back in the passed in addressed pointer
+ * otherwise realloc will be used as needed on the passed in pointer address with the result stored back in.
+ *
+ * 
+ * Passing in a NULL address or a negative length or a NULL format string 
+ * OR
+ * Running out of memory will return -1.  
+ *
+ * On error the pointer to char will be valid if it was originaly supplied by you and you must free it.
+ *
+ * Passing in a length of zero will allow the function to allocate memory until the entire string is printed.
+ * Otherwise it will only allocate and print into the string up to the size specified, including terminating '\0'.
+ * 
+ */
+size_t snprintf_alloc(char **p, size_t len, const char *fmt, ...);
+
+/*
+ * Same as above except 0 is assumed for length
+ */
+size_t sprintf_alloc(char **p, const char *fmt, ...);
+
+/*
+ * same as snprintf_alloc except you pass it argp instead of variable list of arguments
+ */
+size_t vsnprintf_alloc(char **p, size_t len, const char *fmt, va_list argp);
+
+/*
+ * same as above except 0 is assumed for length
+ */
+size_t vsprintf_alloc(char **p, const char *fmt, va_list argp);
+
+
+struct vsnprintf_alloc_cfg 
+{
+	void (*malloc) (size_t);
+	void (*free) (void *, size_t);
+	short 	multiply;
+	short	assertive;
+	short	internal_limit;	
+	short	free_on_error;
+};
+
+#endif /* VSNPRINTF_ALLOC_H */
