From 729eb16b838bbb3471a7753bfff6d1b51c4023d6 Mon Sep 17 00:00:00 2001
From: rswindell <>
Date: Wed, 21 Oct 2009 19:39:28 +0000
Subject: [PATCH] * Mail processors may now be configured to not run for
 DNSBL-listed servers or   SPAM-bait takers by using the mailproc.ini keys
 ProcessDNSBL and ProcessSPAM   (default: True) respectively. * sockmimetext()
 (used for sending message text over SMTP and POP3) now handles   lines longer
 than 998 characters correctly (doesn't drop any characters).   We may need to
 change this function to split at 510 chars for POP3 and/or use  
 quoted-printable content-transfer-encoding for messages with long lines. *
 "!SMTP ..." log lines changed to "SMTP ..." for non-terminal SPAM-related log
   entries. * Handle header "field : value" syntax for subject, from, and to
 field parsing    for early filtering. * Don't tag message (subject and/or
 header) from DNSBL-listed servers when    DNSBL_IGNORE option is set. * Don't
 hash message subjects < 10 chars in length (too short for SPAM   detection).
 * Support Base64 and Quoted-Printable Content-Transfer-Encodings in SMTP   
 message headers (decode and store message body accordingly). * Clear mailproc
 'to' match results when receiving SMTP MAIL FROM command. * Allow SMTP
 authenticated clients to feed the SPAM database by sending mail   to one of
 the spam-bait addresses (the sender won't be added to   spamblock.cfg).

---
 src/sbbs3/mailsrvr.c | 314 +++++++++++++++++++++++++++++++------------
 1 file changed, 230 insertions(+), 84 deletions(-)

diff --git a/src/sbbs3/mailsrvr.c b/src/sbbs3/mailsrvr.c
index 099f21f218..6d2c866d04 100644
--- a/src/sbbs3/mailsrvr.c
+++ b/src/sbbs3/mailsrvr.c
@@ -81,6 +81,7 @@ static char* badrsp_err	=	"%s replied with:\r\n\"%s\"\r\n"
 
 #define TIMEOUT_THREAD_WAIT		60		/* Seconds */
 #define DNSBL_THROTTLE_VALUE	5000	/* Milliseconds */
+#define SPAM_HASH_SUBJECT_MIN_LEN	10	/* characters */
 
 #define STATUS_WFC	"Listening"
 
@@ -115,6 +116,8 @@ struct mailproc {
 	BOOL		native;
 	BOOL		ignore_on_error;	/* Ignore mail message if cmdline fails */
 	BOOL		disabled;
+	BOOL		process_spam;
+	BOOL		process_dnsbl;
 	uint8_t*	ar;
 } *mailproc_list;
 
@@ -426,7 +429,13 @@ static BOOL sockgetrsp(SOCKET socket, char* rsp, char *buf, int len)
 	return(TRUE);
 }
 
-#define MAX_LINE_LEN	1000
+/* RFC822: The maximum total length of a text line including the
+   <CRLF> is 1000 characters (but not counting the leading
+   dot duplicated for transparency). 
+
+   POP3 (RFC1939) actually calls for a 512 byte line length limit!
+*/
+#define MAX_LINE_LEN	998		
 
 static ulong sockmimetext(SOCKET socket, smbmsg_t* msg, char* msgtxt, ulong maxlines
 						  ,str_list_t file_list, char* mime_boundary)
@@ -436,13 +445,13 @@ static ulong sockmimetext(SOCKET socket, smbmsg_t* msg, char* msgtxt, ulong maxl
 	char		fromhost[256];
 	char		msgid[256];
 	char		date[64];
-	char*		p;
-	char*		np;
-	char*		tp;
+	uchar*		p;
+	uchar*		np;
 	char*		content_type=NULL;
 	int			i;
 	int			s;
 	ulong		lines;
+	int			len,tlen;
 
 	/* HEADERS (in recommended order per RFC822 4.1) */
 
@@ -556,23 +565,22 @@ static ulong sockmimetext(SOCKET socket, smbmsg_t* msg, char* msgtxt, ulong maxl
 	lines=0;
 	p=msgtxt;
 	while(*p && lines<maxlines) {
-		tp=strchr(p,'\n');
-		if(tp) {
-			if(tp-p>MAX_LINE_LEN)
-				tp=p+MAX_LINE_LEN;
-			*tp=0;
-		}
-		truncsp(p);	/* Takes care of '\r' or spaces */
-		if(*p=='.')
-			i=sockprintf(socket,".%.*s",MAX_LINE_LEN,p);
-		else
-			i=sockprintf(socket,"%.*s",MAX_LINE_LEN,p);
-		if(!i)
+		len=0;
+		while(len<MAX_LINE_LEN && *(p+len)!=0 && *(p+len)!='\n')
+			len++;
+
+		tlen=len;
+		while(tlen && *(p+(tlen-1))<=' ') /* Takes care of '\r' or spaces */
+			tlen--;
+
+		if(!sockprintf(socket, "%s%.*s", *p=='.' ? ".":"", tlen, p))
 			break;
 		lines++;
-		if(tp==NULL)
+		if(*(p+len)==0)
 			break;
-		p=tp+1;
+		if(len!=MAX_LINE_LEN)
+			len++;
+		p+=len;
 		/* release time-slices every x lines */
 		if(startup->lines_per_yield
 			&& !(lines%startup->lines_per_yield))	
@@ -1826,6 +1834,27 @@ void js_cleanup(JSRuntime* js_runtime, JSContext* js_cx)
 }
 #endif
 
+static char* get_header_field(uchar* buf, char* name, size_t maxlen)
+{
+	char*	p;
+	size_t	len;
+
+	if(buf[0]<=' ')	/* folded header */
+		return NULL;
+
+	if((p=strchr(buf,':'))==NULL)
+		return NULL;
+
+	len = p-buf;
+	if(len > maxlen)
+		len = maxlen;
+	sprintf(name,"%.*s",len,buf);
+	truncsp(name);
+
+	p++;	/* skip colon */
+	SKIP_WHITESPACE(p);
+	return p;
+}
 
 static int parse_header_field(uchar* buf, smbmsg_t* msg, ushort* type)
 {
@@ -1940,7 +1969,7 @@ static int chk_received_hdr(SOCKET socket,const char *buf,IN_ADDR *dnsbl_result,
 		check_addr.s_addr = inet_addr(ip);
 		lprintf(LOG_DEBUG,"%04d DEBUG checking %s [%s]",socket,host_name,ip);
 		if((dnsbl_result->s_addr=dns_blacklisted(socket,check_addr,host_name,dnsbl,dnsbl_ip))!=0)
-				lprintf(LOG_NOTICE,"%04d !SMTP BLACKLISTED SERVER on %s: %s [%s] = %s"
+				lprintf(LOG_NOTICE,"%04d SMTP BLACKLISTED SERVER on %s: %s [%s] = %s"
 					,socket, dnsbl, host_name, ip, inet_ntoa(*dnsbl_result));
 	} while(0);
 	free(fromstr);
@@ -1984,6 +2013,44 @@ static void parse_mail_address(char* p
 	truncsp(name);
 }
 
+/* Decode quoted-printable content-transfer-encoded text */
+/* Ignores (strips) unsupported ctrl chars and non-ASCII chars */
+/* Does not enforce 76 char line length limit */
+static char* qp_decode(uchar* buf)
+{
+	uchar*	p=buf;
+	uchar*	dest=buf;
+
+	for(;;p++) {
+		if(*p==0) {
+			*dest++='\r';
+			*dest++='\n';
+			break;
+		}
+		if(*p==' ' || (*p>='!' && *p<='~' && *p!='=') || *p=='\t')
+			*dest++=*p;
+		else if(*p=='=') {
+			p++;
+			if(*p==0) 	/* soft link break */
+				break;
+			if(isxdigit(*p) && isxdigit(*(p+1))) {
+				char hex[3];
+				hex[0]=*p;
+				hex[1]=*(p+1);
+				hex[2]=0;
+				/* ToDo: what about encoded NULs and the like? */
+				*dest++=(uchar)strtoul(hex,NULL,16);
+				p++;
+			} else {	/* bad encoding */
+				*dest++='=';
+				*dest++=*p;
+			}
+		}
+	}
+	*dest=0;
+	return buf;
+}
+
 static BOOL checktag(scfg_t *scfg, char *tag, uint usernum)
 {
 	char	fname[MAX_PATH+1];
@@ -2150,6 +2217,12 @@ static void smtp_thread(void* arg)
 
 	} cmd = SMTP_CMD_NONE;
 
+	enum {
+			 ENCODING_NONE
+			,ENCODING_BASE64
+			,ENCODING_QUOTED_PRINTABLE
+	} content_encoding = ENCODING_NONE;
+
 	SetThreadName("SMTP");
 	thread_up(TRUE /* setuid */);
 
@@ -2242,7 +2315,7 @@ static void smtp_thread(void* arg)
 		/*  SPAM Filters (mail-abuse.org) */
 		dnsbl_result.s_addr = dns_blacklisted(socket,smtp.client_addr.sin_addr,host_name,dnsbl,dnsbl_ip);
 		if(dnsbl_result.s_addr) {
-			lprintf(LOG_NOTICE,"%04d !SMTP BLACKLISTED SERVER on %s: %s [%s] = %s"
+			lprintf(LOG_NOTICE,"%04d SMTP BLACKLISTED SERVER on %s: %s [%s] = %s"
 				,socket, dnsbl, host_name, dnsbl_ip, inet_ntoa(dnsbl_result));
 			if(startup->options&MAIL_OPT_DNSBL_REFUSE) {
 				SAFEPRINTF2(str,"Listed on %s as %s", dnsbl, inet_ntoa(dnsbl_result));
@@ -2426,6 +2499,12 @@ static void smtp_thread(void* arg)
 						if(mailproc_list[i].disabled)
 							continue;
 
+						if(!mailproc_list[i].process_dnsbl && dnsbl_result.s_addr)
+							continue;
+
+						if(!mailproc_list[i].process_spam && spam_bait_result)
+							continue;
+
 						if(!chk_ar(&scfg,mailproc_list[i].ar,&relay_user,&client))
 							continue;
 
@@ -2452,7 +2531,7 @@ static void smtp_thread(void* arg)
 							lprintf(LOG_DEBUG,"%04d SMTP Executing external command: %s"
 								,socket, str);
 							if((j=system(str))!=0) {
-								lprintf(LOG_NOTICE,"%04d !SMTP system(%s) returned %d (errno: %d)"
+								lprintf(LOG_NOTICE,"%04d SMTP system(%s) returned %d (errno: %d)"
 									,socket, str, j, errno);
 								if(mailproc_list[i].ignore_on_error) {
 									lprintf(LOG_WARNING,"%04d !SMTP IGNORED MAIL due to mail processor (%s) error: %d"
@@ -2559,37 +2638,39 @@ static void smtp_thread(void* arg)
 				smb_error=SMB_SUCCESS; /* no SMB error */
 				errmsg=insuf_stor;
 				while(!feof(msgtxt)) {
+					char field[32];
+
 					if(!fgets(buf,sizeof(buf),msgtxt))
 						break;
 					truncsp(buf);
 					if(buf[0]==0)	/* blank line marks end of header */
 						break;
 
-					if(!strnicmp(buf, "SUBJECT:",8)) {
-						p=buf+8;
-						SKIP_WHITESPACE(p);
-						if(relay_user.number==0	&& dnsbl_result.s_addr && startup->dnsbl_tag[0]) {
-							safe_snprintf(str,sizeof(str),"%.*s: %.*s"
-								,(int)sizeof(str)/2, startup->dnsbl_tag
-								,(int)sizeof(str)/2, p);
-							p=str;
-							lprintf(LOG_NOTICE,"%04d !SMTP TAGGED MAIL SUBJECT from blacklisted server with: %s"
-								,socket, startup->dnsbl_tag);
+					if((p=get_header_field(buf, field, sizeof(field)))!=NULL) {
+						if(stricmp(field, "SUBJECT")==0) {
+							if(relay_user.number==0	&& dnsbl_result.s_addr && startup->dnsbl_tag[0] && !(startup->options&MAIL_OPT_DNSBL_IGNORE)) {
+								safe_snprintf(str,sizeof(str),"%.*s: %.*s"
+									,(int)sizeof(str)/2, startup->dnsbl_tag
+									,(int)sizeof(str)/2, p);
+								p=str;
+								lprintf(LOG_NOTICE,"%04d SMTP TAGGED MAIL SUBJECT from blacklisted server with: %s"
+									,socket, startup->dnsbl_tag);
+							}
+							smb_hfield_str(&msg, SUBJECT, p);
+							continue;
+						}
+						if(stricmp(field, "FROM")==0
+							&& !chk_email_addr(socket,p,host_name,host_ip,rcpt_addr,reverse_path,"FROM")) {
+							errmsg="554 Sender not allowed.";
+							smb_error=SMB_FAILURE;
+							break;
+						}
+						if(stricmp(field, "TO")==0 && !spam_bait_result
+							&& !chk_email_addr(socket,p,host_name,host_ip,rcpt_addr,reverse_path,"TO")) {
+							errmsg="550 Unknown user.";
+							smb_error=SMB_FAILURE;
+							break;
 						}
-						smb_hfield_str(&msg, SUBJECT, p);
-						continue;
-					}
-					if(!strnicmp(buf, "FROM:", 5)
-						&& !chk_email_addr(socket,buf+5,host_name,host_ip,rcpt_addr,reverse_path,"FROM")) {
-						errmsg="554 Sender not allowed.";
-						smb_error=SMB_FAILURE;
-						break;
-					}
-					if(!strnicmp(buf, "TO:", 3) && !spam_bait_result
-						&& !chk_email_addr(socket,buf+3,host_name,host_ip,rcpt_addr,reverse_path,"TO")) {
-						errmsg="550 Unknown user.";
-						smb_error=SMB_FAILURE;
-						break;
 					}
 					if((smb_error=parse_header_field(buf,&msg,&hfield_type))!=SMB_SUCCESS) {
 						if(smb_error==SMB_ERR_HDR_LEN)
@@ -2618,7 +2699,7 @@ static void smtp_thread(void* arg)
 
 				/* SPAM Filtering/Logging */
 				if(relay_user.number==0 && msg.subj!=NULL && trashcan(&scfg,msg.subj,"subject")) {
-					lprintf(LOG_NOTICE,"%04d !SMTP BLOCKED SUBJECT (%s) from: %s"
+					lprintf(LOG_NOTICE,"%04d SMTP BLOCKED SUBJECT (%s) from: %s"
 						,socket, msg.subj, reverse_path);
 					SAFEPRINTF2(tmp,"Blocked subject (%s) from: %s"
 						,msg.subj, reverse_path);
@@ -2638,17 +2719,17 @@ static void smtp_thread(void* arg)
 						}
 					}
 				}
-				if(relay_user.number==0 && dnsbl_result.s_addr) {
+				if(relay_user.number==0 && dnsbl_result.s_addr && !(startup->options&MAIL_OPT_DNSBL_IGNORE)) {
 					/* tag message as spam */
 					if(startup->dnsbl_hdr[0]) {
 						safe_snprintf(str,sizeof(str),"%s: %s is listed on %s as %s"
 							,startup->dnsbl_hdr, dnsbl_ip
 							,dnsbl, inet_ntoa(dnsbl_result));
 						smb_hfield_str(&msg, RFC822HEADER, str);
-						lprintf(LOG_NOTICE,"%04d !SMTP TAGGED MAIL HEADER from blacklisted server with: %s"
+						lprintf(LOG_NOTICE,"%04d SMTP TAGGED MAIL HEADER from blacklisted server with: %s"
 							,socket, startup->dnsbl_hdr);
 					}
-					if((startup->dnsbl_hdr[0] || startup->dnsbl_tag[0]) && !(startup->options&MAIL_OPT_DNSBL_IGNORE)) {
+					if(startup->dnsbl_hdr[0] || startup->dnsbl_tag[0]) {
 						SAFEPRINTF2(str,"Listed on %s as %s", dnsbl, inet_ntoa(dnsbl_result));
 						spamlog(&scfg, "SMTP", "TAGGED", str, host_name, dnsbl_ip, rcpt_addr, reverse_path);
 					}
@@ -2673,7 +2754,7 @@ static void smtp_thread(void* arg)
 				length=filelength(fileno(msgtxt))-ftell(msgtxt);
 
 				if(startup->max_msg_size && length>startup->max_msg_size) {
-					lprintf(LOG_WARNING,"%04d !SMTP message size (%lu) exceeds maximum: %lu bytes"
+					lprintf(LOG_WARNING,"%04d !SMTP Message size (%lu) exceeds maximum: %lu bytes"
 						,socket,length,startup->max_msg_size);
 					sockprintf(socket, "552 Message size (%lu) exceeds maximum: %lu bytes"
 						,length,startup->max_msg_size);
@@ -2733,35 +2814,46 @@ static void smtp_thread(void* arg)
 				{
 					hash_t**	hashes;
 					BOOL		is_spam=spam_bait_result;
+					long		sources=SMB_HASH_SOURCE_SPAM;
 
 					if((dnsbl_recvhdr || dnsbl_result.s_addr) && startup->options&MAIL_OPT_DNSBL_SPAMHASH)
 						is_spam=TRUE;
 
+					if(msg.subj==NULL || strlen(msg.subj) < SPAM_HASH_SUBJECT_MIN_LEN)
+						sources&=~SMB_HASH_SOURCE_SUBJECT;
 					lprintf(LOG_DEBUG,"%04d SMTP Calculating message hashes", socket);
-					if((hashes=smb_msghashes(&msg, msgbuf, SMB_HASH_SOURCE_SPAM)) != NULL) {
+					if((hashes=smb_msghashes(&msg, msgbuf, sources)) != NULL) {
 						hash_t	found;
 
-						if((i=smb_findhash(&spam, hashes, &found, SMB_HASH_SOURCE_SPAM, /* Mark: */TRUE))==SMB_SUCCESS
-							&& !is_spam) {
-							SAFEPRINTF2(str,"%s '%s' found in SPAM database"
+						if((i=smb_findhash(&spam, hashes, &found, sources, /* Mark: */TRUE))==SMB_SUCCESS) {
+							SAFEPRINTF3(str,"%s (%s) found in SPAM database (added on %s)"
 								,smb_hashsourcetype(found.source)
 								,smb_hashsource(&msg,found.source)
+								,timestr(&scfg,found.time,tmp)
 								);
-							lprintf(LOG_NOTICE,"%04d !SMTP message %s", socket, str);
-							spamlog(&scfg, "SMTP", "IGNORED"
-								,str, host_name, host_ip, rcpt_addr, reverse_path);
-							is_spam=TRUE;
+							lprintf(LOG_NOTICE,"%04d SMTP Message %s", socket, str);
+							if(!is_spam) {
+								spamlog(&scfg, "SMTP", "IGNORED"
+									,str, host_name, host_ip, rcpt_addr, reverse_path);
+								is_spam=TRUE;
+							}
 						}
 						if(is_spam) {
 							size_t	n,total=0;
 							for(n=0;hashes[n]!=NULL;n++)
-								if(!(hashes[n]->flags&SMB_HASH_MARKED))
+								if(!(hashes[n]->flags&SMB_HASH_MARKED)) {
+									lprintf(LOG_INFO,"%04d SMTP Adding message %s (%s) to SPAM database"
+										,socket
+										,smb_hashsourcetype(hashes[n]->source)
+										,smb_hashsource(&msg,hashes[n]->source)
+										);
 									total++;
+								}
 							if(total) {
-								lprintf(LOG_INFO,"%04d SMTP Adding %u message hashes to SPAM database", socket, total);
+								lprintf(LOG_DEBUG,"%04d SMTP Adding %u message hashes to SPAM database", socket, total);
 								smb_addhashes(&spam, hashes, /* skip_marked: */TRUE);
 							}
-							if(i!=SMB_SUCCESS && !spam_bait_result && (dnsbl_recvhdr || dnsbl_result.s_addr) && !(startup->options&MAIL_OPT_DNSBL_IGNORE))
+							if(i!=SMB_SUCCESS && !spam_bait_result && (dnsbl_recvhdr || dnsbl_result.s_addr))
 								is_spam=FALSE;
 						}
 						smb_close_hash(&spam);
@@ -2772,7 +2864,7 @@ static void smtp_thread(void* arg)
 					if(is_spam || ((startup->options&MAIL_OPT_DNSBL_IGNORE) && (dnsbl_recvhdr || dnsbl_result.s_addr))) {
 						free(msgbuf);
 						if(is_spam)
-							lprintf(LOG_INFO,"%04d SMTP IGNORED SPAM MESSAGE",socket);
+							lprintf(LOG_NOTICE,"%04d !SMTP IGNORED SPAM MESSAGE",socket);
 						else {
 							SAFEPRINTF2(str,"Listed on %s as %s", dnsbl, inet_ntoa(dnsbl_result));
 							lprintf(LOG_NOTICE,"%04d !SMTP IGNORED MAIL from server: %s"
@@ -2864,19 +2956,27 @@ static void smtp_thread(void* arg)
 					}
 					lprintf(LOG_INFO,"%04d SMTP Created message #%ld from %s to %s <%s>"
 						,socket, newmsg.hdr.number, sender, rcpt_name, rcpt_addr);
-					if(!(startup->options&MAIL_OPT_NO_NOTIFY) && usernum
-						&& !dnsbl_recvhdr && !dnsbl_result.s_addr) {
-						safe_snprintf(str,sizeof(str)
-							,"\7\1n\1hOn %.24s\r\n\1m%s \1n\1msent you e-mail from: "
-							"\1h%s\1n\r\n"
-							,timestr(&scfg,newmsg.hdr.when_imported.time,tmp)
-							,sender,sender_addr);
-						if(!newmsg.idx.to) {	/* Forwarding */
-							strcat(str,"\1mand it was automatically forwarded to: \1h");
-							strcat(str,rcpt_addr);
-							strcat(str,"\1n\r\n");
+					if(!(startup->options&MAIL_OPT_NO_NOTIFY) && usernum) {
+						if(newmsg.idx.to)
+							for(i=1;i<=scfg.sys_nodes;i++) {
+								getnodedat(&scfg, i, &node, 0);
+								if(node.useron==usernum
+									&& (node.status==NODE_INUSE || node.status==NODE_QUIET))
+									break;
+							}
+						if(!newmsg.idx.to || i<=scfg.sys_nodes) {
+							safe_snprintf(str,sizeof(str)
+								,"\7\1n\1hOn %.24s\r\n\1m%s \1n\1msent you e-mail from: "
+								"\1h%s\1n\r\n"
+								,timestr(&scfg,newmsg.hdr.when_imported.time,tmp)
+								,sender,sender_addr);
+							if(!newmsg.idx.to) {	/* Forwarding */
+								strcat(str,"\1mand it was automatically forwarded to: \1h");
+								strcat(str,rcpt_addr);
+								strcat(str,"\1n\r\n");
+							}
+							putsmsg(&scfg, usernum, str);
 						}
-						putsmsg(&scfg, usernum, str);
 					}
 				}
 				iniFreeStringList(sec_list);
@@ -2908,8 +3008,26 @@ static void smtp_thread(void* arg)
 			if(state==SMTP_STATE_DATA_BODY) {
 				p=buf;
 				if(*p=='.') p++;	/* Transparency (RFC821 4.5.2) */
-				if(msgtxt!=NULL) 
-					fprintf(msgtxt, "%s\r\n", p);
+				if(msgtxt!=NULL) {
+					switch(content_encoding) {
+						case ENCODING_BASE64:
+							{
+								char	decode_buf[sizeof(buf)];
+
+								if(b64_decode(decode_buf, sizeof(decode_buf), p, strlen(p))<0)
+									fprintf(msgtxt,"\r\n!Base64 decode error: %s\r\n", p);
+								else
+									fputs(decode_buf, msgtxt);
+							}
+							break;
+						case ENCODING_QUOTED_PRINTABLE:
+							fputs(qp_decode(p), msgtxt);
+							break;
+						default:
+							fprintf(msgtxt, "%s\r\n", p);
+							break;
+					}
+				}
 				lines++;
 				/* release time-slices every x lines */
 				if(startup->lines_per_yield &&
@@ -2921,10 +3039,31 @@ static void smtp_thread(void* arg)
 			if(startup->options&MAIL_OPT_DEBUG_RX_HEADER)
 				lprintf(LOG_DEBUG,"%04d SMTP %s",socket, buf);
 
-			if(!strnicmp(buf, "FROM:", 5))
-				parse_mail_address(buf+5
-					,sender,		sizeof(sender)-1
-					,sender_addr,	sizeof(sender_addr)-1);
+			{
+				char field[32];
+
+				if((p=get_header_field(buf, field, sizeof(field)))!=NULL) {
+					if(stricmp(field, "FROM")==0) {
+						parse_mail_address(p
+							,sender,		sizeof(sender)-1
+							,sender_addr,	sizeof(sender_addr)-1);
+					}
+					else if(stricmp(field,"CONTENT-TRANSFER-ENCODING")==0) {
+						lprintf(LOG_INFO,"%04d SMTP %s = %s", socket, field, p);
+						if(stricmp(p,"base64")==0)
+							content_encoding=ENCODING_BASE64;
+						else if(stricmp(p,"quoted-printable")==0)
+							content_encoding=ENCODING_QUOTED_PRINTABLE;
+						else {	/* Other (e.g. 7bit, 8bit, binary) */
+							content_encoding=ENCODING_NONE;
+							if(msgtxt!=NULL) 
+								fprintf(msgtxt, "%s\r\n", buf);
+						}
+						hdr_lines++;
+						continue;
+					}
+				}
+			}
 
 			if(msgtxt!=NULL) 
 				fprintf(msgtxt, "%s\r\n", buf);
@@ -3186,6 +3325,7 @@ static void smtp_thread(void* arg)
 				break;
 			}
 			rcpt_count=0;
+			content_encoding=ENCODING_NONE;
 
 			memset(mailproc_to_match,FALSE,sizeof(BOOL)*mailproc_count);
 
@@ -3241,6 +3381,8 @@ static void smtp_thread(void* arg)
 				break;
 			}
 			rcpt_count=0;
+			content_encoding=ENCODING_NONE;
+			memset(mailproc_to_match,FALSE,sizeof(BOOL)*mailproc_count);
 			sockprintf(socket,ok_rsp);
 			badcmds=0;
 			continue;
@@ -3311,11 +3453,11 @@ static void smtp_thread(void* arg)
 
 			/* Check for SPAM bait recipient */
 			if((spam_bait_result=findstr(rcpt_addr,spam_bait))==TRUE) {
+				char	reason[256];
+				SAFEPRINTF(reason,"SPAM BAIT (%s) taken", rcpt_addr);
+				lprintf(LOG_NOTICE,"%04d SMTP %s by: %s"
+					,socket, reason, reverse_path);
 				if(relay_user.number==0) {
-					char	reason[256];
-					SAFEPRINTF(reason,"SPAM BAIT (%s) taken", rcpt_addr);
-					lprintf(LOG_NOTICE,"%04d !SMTP %s by: %s"
-						,socket, reason, reverse_path);
 					strcpy(tmp,"REFUSED");
 					if(dnsbl_result.s_addr==0)	{ /* Don't double-filter */
 						lprintf(LOG_NOTICE,"%04d !BLOCKING IP ADDRESS: %s in %s", socket, host_ip, spam_block);
@@ -4620,6 +4762,10 @@ void DLLCALL mail_server(void* arg)
 						iniReadBool(fp,sec_list[i],"Disabled",FALSE);
 					mailproc_list[i].ignore_on_error = 
 						iniReadBool(fp,sec_list[i],"IgnoreOnError",FALSE);
+					mailproc_list[i].process_spam =
+						iniReadBool(fp,sec_list[i],"ProcessSPAM",TRUE);
+					mailproc_list[i].process_dnsbl =
+						iniReadBool(fp,sec_list[i],"ProcessDNSBL",TRUE);
 					mailproc_list[i].ar = 
 						arstr(NULL,iniReadString(fp,sec_list[i],"AccessRequirements","",buf),&scfg);
 				}
-- 
GitLab