diff -urN clamav-devel/clamav-milter/Makefile.am clamav-devel-jm/clamav-milter/Makefile.am
--- clamav-devel/clamav-milter/Makefile.am	Tue Apr  6 18:43:43 2004
+++ clamav-devel-jm/clamav-milter/Makefile.am	Sat Apr 24 22:41:38 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 -urN clamav-devel/clamav-milter/clamav-milter.c clamav-devel-jm/clamav-milter/clamav-milter.c
--- clamav-devel/clamav-milter/clamav-milter.c	Fri Apr 23 15:11:05 2004
+++ clamav-devel-jm/clamav-milter/clamav-milter.c	Sat Apr 24 22:41:38 2004
@@ -598,7 +598,7 @@
  */
 static	char	const	rcsid[] = "$Id: clamav-milter.c,v 1.82 2004/04/23 09:13:30 nigelhorne Exp $";
 
-#define	CM_VERSION	"0.70r"
+#define	CM_VERSION	"0.70r-jm"
 
 /*#define	CONFDIR	"/usr/local/etc"*/
 
@@ -666,6 +666,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
@@ -710,7 +731,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 */
 };
 
@@ -727,7 +749,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);
@@ -799,10 +821,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 = 0; /* Redundandtly 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 */
@@ -848,6 +871,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).");
@@ -875,6 +899,7 @@
 int
 main(int argc, char **argv)
 {
+	int	ret_code = 0;
 	extern char *optarg;
 	const char *cfgfile = CL_DEFAULT_CFG;
 	struct cfgstruct *cpt;
@@ -913,9 +938,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:Vx:";
 #else
-		const char *args = "bc:CDfF:lm:nNop:PqQ:dhHs:St:U:V";
+		const char *args = "bc:CDfF:Ilm:nNop:PqQ:dhHs:St:U:V";
 #endif
 
 		static struct option long_options[] = {
@@ -932,6 +957,9 @@
 				"dont-log-clean", 0, NULL, 'C'
 			},
 			{
+				"dont-log-infected", 0, NULL, 'I'
+			},
+			{
 				"dont-scan-on-error", 0, NULL, 'd'
 			},
 			{
@@ -1240,6 +1268,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;
@@ -1270,6 +1300,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++) {
@@ -1328,6 +1359,7 @@
 			default:	/* parent */
 				return EX_OK;
 		}
+#ifndef CL_DEBUG
 		close(0);
 		close(1);
 		close(2);
@@ -1335,6 +1367,8 @@
 		if((open("/dev/console", O_WRONLY) == 1) ||
 		   (open("/dev/null", O_WRONLY) == 1))
 			dup(1);
+#endif
+
 #ifdef HAVE_SETPGRP
 #ifdef SETPGRP_VOID
 		setpgrp();
@@ -1402,6 +1436,8 @@
 	signal(SIGPIPE, SIG_IGN);
 
 	return smfi_main();
+cleanup:
+	return(ret_code);
 }
 
 /*
@@ -1524,6 +1560,7 @@
 	fd_set rfds;
 	struct timeval tv;
 	int retval;
+	int ret_code = 0;
 
 	assert(tcpSocket != 0);
 	assert(numServers > 0);
@@ -1532,7 +1569,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);
 
@@ -1612,7 +1651,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;
+	
 }
 
 /*
@@ -1766,6 +1813,7 @@
 clamfi_envfrom(SMFICTX *ctx, char **argv)
 {
 	struct privdata *privdata;
+	int	ret_code = 0;
 
 	if(logVerbose)
 		syslog(LOG_DEBUG, "clamfi_envfrom: %s", argv[0]);
@@ -1824,25 +1872,23 @@
 	}
 
 	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 */
 
 	privdata->from = strdup(argv[0]);
-
-	if(streamMaxLength > 0L)
-		privdata->numBytes = (long)(strlen(argv[0]) + 6);
+	privdata->envid = smfi_getsymval(ctx,"i");
+	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;
 }
 
@@ -1850,29 +1896,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
@@ -1903,9 +1955,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) &&
@@ -1944,8 +1993,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
@@ -1995,27 +2042,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;
@@ -2023,17 +2060,22 @@
 	if(Sflag) {
 		if(privdata->body) {
 			assert(privdata->bodyLen > 0);
-			privdata->body = realloc(privdata->body, privdata->bodyLen + len);
+			p = realloc(privdata->body, privdata->bodyLen + len);
+			ALLOC_CHECK("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
@@ -2041,12 +2083,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);
@@ -2054,6 +2099,8 @@
 	assert(!((privdata->cmdSocket >= 0) && (privdata->filename != NULL)));
 	assert(privdata->dataSocket >= 0);
 #endif
+	if(!privdata)
+		goto cleanup;
 
 	close(privdata->dataSocket);
 	privdata->dataSocket = -1;
@@ -2083,7 +2130,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);
 
@@ -2117,10 +2164,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);
 
@@ -2131,22 +2174,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");
 
@@ -2154,10 +2200,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) {
@@ -2167,9 +2214,13 @@
 			off_t len = updateSigFile();
 
 			if(len) {
+				p = NULL;
+
 				assert(Sflag != 0);
 
-				privdata->body = realloc(privdata->body, privdata->bodyLen + len);
+				p = realloc(privdata->body, privdata->bodyLen + len);
+				ALLOC_CHECK("realloc",p,1);
+				privdata->body = p;
 				memcpy(&privdata->body[privdata->bodyLen], signature, len);
 
 				smfi_replacebody(ctx, privdata->body, privdata->bodyLen + len);
@@ -2177,7 +2228,7 @@
 		}
 	} else {
 		char reject[1024];
-		char **to, *virusname;
+		char *virusname;
 
 		*ptr = '\0';	/* Remove the "FOUND" word */
 
@@ -2189,50 +2240,37 @@
 
 		if(!nflag)
 			smfi_addheader(ctx, "X-Virus-Status", "Infected");
-
-		if(use_syslog) {
+#ifndef	CL_DEBUG
+		if(use_syslog && logInfected) {
+#else
+		{
+#endif /* CL_DEBUG */
 			/*
 			 * 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 = realloc(err, i);
-					ptr = strchr(err, '\0');
-				}
-				ptr = strrcpy(ptr, " ");
-				ptr = strrcpy(ptr, *to);
-			}
-			(void)strcpy(ptr, "\n");
-
-			/* Include the sendmail queue ID in the log */
-			syslog(LOG_NOTICE, "%s: %s%s", sendmailId, mess, err);
+				ptr = NULL;
+				sprintf_alloc(&ptr,"%s %s",err,*to);
+				free(err);
+				err = ptr;
+			}
+  
+			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", privdata->envid, mess, err);
 #ifdef	CL_DEBUG
 			cli_dbgmsg("%s\n", err);
-#endif
-			free(err);
+#endif /* CL_DEBUG */
+  			free(err);
+
 		}
 
 		if(!qflag) {
@@ -2300,7 +2338,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);
@@ -2385,8 +2423,12 @@
 		snprintf(reject, sizeof(reject) - 1, "%sdetected by ClamAV - http://www.clamav.net", virusname);
 		smfi_setreply(ctx, "550", "5.7.1", reject);
 	}
+cleanup:
 	clamfi_cleanup(ctx);
-
+	if(ret_code){
+		if(err)
+			free(err);
+	}
 	return rc;
 }
 
@@ -2532,13 +2574,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);
 
@@ -2552,7 +2597,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);
@@ -2572,6 +2619,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) :
@@ -2595,13 +2659,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;
 }
 
 /*
@@ -2659,6 +2734,8 @@
 {
 	struct stat statb;
 	int fd;
+	int ret_code = 0;
+	void * p = NULL;
 
 	if(sigFilename == NULL)
 		/* nothing to read */
@@ -2684,24 +2761,32 @@
 
 	signatureStamp = statb.st_mtime;
 
-	signature = realloc(signature, statb.st_size);
+	p = realloc(signature, statb.st_size + 1);
+	ALLOC_CHECK("realloc",p,1);
+	signature = p;
 	read(fd, signature, statb.st_size);
+	signature[statb.st_size] = '\0';
 	close(fd);
 
 	return statb.st_size;
+cleanup:
+	return strlen(signature);
 }
 
 static header_list_t
 header_list_new(void)
 {
 	header_list_t ret;
+	int ret_code = 0;
+	void * p = NULL;
 
 	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
@@ -2725,19 +2810,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)
@@ -2746,6 +2828,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
@@ -2768,7 +2857,11 @@
 connect2clamd(struct privdata *privdata)
 {
 	char **to;
+	int  ret = 0;
+	int	ret_code = 0;
+
 
+	assert(privdata);
 	assert(privdata->dataSocket == -1);
 	assert(privdata->from != NULL);
 	assert(privdata->to != NULL);
@@ -2802,7 +2895,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);
 
@@ -2894,7 +2987,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");
@@ -2972,6 +3065,8 @@
 	cli_dbgmsg("connect2clamd OK\n");
 
 	return 1;
+cleanup:
+	return 0;
 }
 
 /*
diff -urN clamav-devel/clamd/scanner.c clamav-devel-jm/clamd/scanner.c
--- clamav-devel/clamd/scanner.c	Tue Apr 13 21:27:22 2004
+++ clamav-devel-jm/clamd/scanner.c	Sat Apr 24 22:41:38 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 -urN clamav-devel/clamd/session.c clamav-devel-jm/clamd/session.c
--- clamav-devel/clamd/session.c	Mon Mar 29 10:06:07 2004
+++ clamav-devel-jm/clamd/session.c	Sat Apr 24 22:41:38 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 -urN clamav-devel/clamdscan/clamdscan.c clamav-devel-jm/clamdscan/clamdscan.c
--- clamav-devel/clamdscan/clamdscan.c	Sat Apr 10 18:43:41 2004
+++ clamav-devel-jm/clamdscan/clamdscan.c	Sat Apr 24 22:41:38 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 -urN clamav-devel/clamdscan/client.c clamav-devel-jm/clamdscan/client.c
--- clamav-devel/clamdscan/client.c	Tue Apr  6 18:43:43 2004
+++ clamav-devel-jm/clamdscan/client.c	Sat Apr 24 22:41:38 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 -urN clamav-devel/clamscan/clamscan.c clamav-devel-jm/clamscan/clamscan.c
--- clamav-devel/clamscan/clamscan.c	Fri Apr 16 11:46:39 2004
+++ clamav-devel-jm/clamscan/clamscan.c	Sat Apr 24 22:41:38 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 -urN clamav-devel/clamscan/manager.c clamav-devel-jm/clamscan/manager.c
--- clamav-devel/clamscan/manager.c	Wed Apr 21 06:34:00 2004
+++ clamav-devel-jm/clamscan/manager.c	Sat Apr 24 22:41:38 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 -urN clamav-devel/clamscan/options.c clamav-devel-jm/clamscan/options.c
--- clamav-devel/clamscan/options.c	Wed Apr 21 06:34:00 2004
+++ clamav-devel-jm/clamscan/options.c	Sat Apr 24 22:41:38 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 -urN clamav-devel/libclamav/clamav.h clamav-devel-jm/libclamav/clamav.h
--- clamav-devel/libclamav/clamav.h	Sat Mar 13 15:08:10 2004
+++ clamav-devel-jm/libclamav/clamav.h	Sat Apr 24 22:41:38 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 -urN clamav-devel/libclamav/scanners.c clamav-devel-jm/libclamav/scanners.c
--- clamav-devel/libclamav/scanners.c	Wed Apr 21 06:34:00 2004
+++ clamav-devel-jm/libclamav/scanners.c	Sat Apr 24 22:41:38 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;
@@ -882,6 +883,9 @@
     }
 
     type = cli_filetype(magic, bread);
+
+	if(type == CL_UNKNOWN_TYPE && SCAN_UNKNOWN_MAIL)
+		type = CL_MAILFILE;
 
     switch(type) {
 	case CL_RARFILE:
diff -urN clamav-devel/shared/cfgparser.c clamav-devel-jm/shared/cfgparser.c
--- clamav-devel/shared/cfgparser.c	Fri Apr 16 11:46:40 2004
+++ clamav-devel-jm/shared/cfgparser.c	Sat Apr 24 22:41:38 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 -urN clamav-devel/shared/vsnprintf_alloc.c clamav-devel-jm/shared/vsnprintf_alloc.c
--- clamav-devel/shared/vsnprintf_alloc.c	Wed Dec 31 19:00:00 1969
+++ clamav-devel-jm/shared/vsnprintf_alloc.c	Sat Apr 24 22:41:38 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 -urN clamav-devel/shared/vsnprintf_alloc.h clamav-devel-jm/shared/vsnprintf_alloc.h
--- clamav-devel/shared/vsnprintf_alloc.h	Wed Dec 31 19:00:00 1969
+++ clamav-devel-jm/shared/vsnprintf_alloc.h	Sat Apr 24 22:41:38 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 */
