From f7aa784c780d32545b81e78b7cd13e7189e5d198 Mon Sep 17 00:00:00 2001
From: rswindell <>
Date: Wed, 10 Apr 2019 21:10:52 +0000
Subject: [PATCH] Added smb_getcontenttype(): returns the MIME content-type of
 the message or NULL if not relevant (not a MIME-encoded message). Added
 smb_countattachments(): returns the number of file attachments in a
 MIME-encoded message. Added SMBMSGTXT_NO_TAILS definition to be used in place
 of '0' for common smb_getmsgtxt() mode argument value. The amount of
 white-space after "Content-Type:" and the content-type value is now more
 flexible (0 or +1 spaces/tabs are fine).

---
 src/smblib/smblib.h | 17 +++++----
 src/smblib/smbtxt.c | 85 ++++++++++++++++++++++++++++++++-------------
 2 files changed, 72 insertions(+), 30 deletions(-)

diff --git a/src/smblib/smblib.h b/src/smblib/smblib.h
index 5669890e9e..2e1e94d025 100644
--- a/src/smblib/smblib.h
+++ b/src/smblib/smblib.h
@@ -99,13 +99,16 @@
 
 #define SMB_ALL_REFS		0			/* Free all references to data		*/
 
-#define GETMSGTXT_TAILS 		(1<<0)	/* Get message tail(s)				*/
-#define GETMSGTXT_NO_BODY		(1<<1)	/* Don't retrieve message body		*/
-#define GETMSGTXT_NO_HFIELDS	(1<<2)	/* Don't include text header fields	*/
+										/* smb_getmsgtxt() mode flags		*/
+#define GETMSGTXT_TAILS 		(1<<0)	/* Incude message tail(s)			*/
+#define GETMSGTXT_NO_BODY		(1<<1)	/* Exclude message body				*/
+#define GETMSGTXT_NO_HFIELDS	(1<<2)	/* Exclude text header fields		*/
 #define GETMSGTXT_PLAIN			(1<<3)	/* Get plaintext portion only of MIME-encoded body (all, otherwise) */
+										/* common smb_getmsgtxt() mode values */
 #define GETMSGTXT_BODY_ONLY		GETMSGTXT_NO_HFIELDS
 #define GETMSGTXT_TAIL_ONLY		(GETMSGTXT_TAILS|GETMSGTXT_NO_BODY|GETMSGTXT_NO_HFIELDS)
 #define GETMSGTXT_ALL			GETMSGTXT_TAILS
+#define GETMSGTXT_NO_TAILS		0		/* Exclude message tails(s)			*/
 
 #define SMB_IS_OPEN(smb)	((smb)->shd_fp!=NULL)
 
@@ -266,9 +269,11 @@ SMBEXPORT enum smb_net_type SMBCALL smb_get_net_type_by_addr(const char* addr);
 SMBEXPORT void		SMBCALL smb_dump_msghdr(FILE* fp, smbmsg_t* msg);
 
 /* smbtxt.c */
-SMBEXPORT char*		SMBCALL smb_getmsgtxt(smb_t* smb, smbmsg_t* msg, ulong mode);
-SMBEXPORT char*		SMBCALL smb_getplaintext(smbmsg_t* msg, char* buf);
-SMBEXPORT uint8_t*	SMBCALL smb_getattachment(smbmsg_t* msg, char* buf, char* filename, size_t filename_len, uint32_t* filelen, int index);
+SMBEXPORT char*		SMBCALL smb_getmsgtxt(smb_t*, smbmsg_t*, ulong mode);
+SMBEXPORT char*		SMBCALL smb_getplaintext(smbmsg_t*, char* body);
+SMBEXPORT char*		SMBCALL smb_getcontenttype(smbmsg_t*);
+SMBEXPORT uint8_t*	SMBCALL smb_getattachment(smbmsg_t*, char* body, char* filename, size_t filename_len, uint32_t* filelen, int index);
+SMBEXPORT ulong		SMBCALL	smb_countattachments(smb_t*, smbmsg_t*, const char* body);
 
 /* smbfile.c */
 SMBEXPORT int 		SMBCALL smb_feof(FILE* fp);
diff --git a/src/smblib/smbtxt.c b/src/smblib/smbtxt.c
index 2580e1ecbd..07c0985d0b 100644
--- a/src/smblib/smbtxt.c
+++ b/src/smblib/smbtxt.c
@@ -338,8 +338,8 @@ static char* mime_getcontent(char* buf, const char* content_type, const char* co
 	int		found = 0;
 
 	if(content_match != NULL) {
-		match_len = sprintf(match1, "Content-Type: %s;", content_match);
-					sprintf(match2, "Content-Type: %s\r", content_match);
+		match_len = sprintf(match1, "%s;", content_match);
+					sprintf(match2, "%s\r", content_match);
 	}
 
 	if(depth > 2)
@@ -372,8 +372,11 @@ static char* mime_getcontent(char* buf, const char* content_type, const char* co
 			continue;
 		for(content_type = txt; content_type < p; content_type++) {
 			SKIP_WHITESPACE(content_type);
-			if(strnicmp(content_type, "Content-Type:", 13) == 0)
+			if(strnicmp(content_type, "Content-Type:", 13) == 0) {
+				content_type += 13;
+				SKIP_WHITESPACE(content_type);
 				break;
+			}
 			FIND_CHAR(content_type, '\r');
 		}
 		if(content_type >= p)
@@ -400,23 +403,31 @@ static char* mime_getcontent(char* buf, const char* content_type, const char* co
 	return NULL;
 }
 
+/* Returns the MIME content-type or NULL if not a MIME-encoded message */
+char* SMBCALL smb_getcontenttype(smbmsg_t* msg)
+{
+	int		i;
+
+	for(i = 0; i < msg->total_hfields; i++) {
+		if(msg->hfield[i].type == RFC822HEADER) {
+			if(strnicmp((char*)msg->hfield_dat[i], "Content-Type:", 13) == 0) {
+				char* result = msg->hfield_dat[i] + 13;
+				SKIP_WHITESPACE(result);
+				return result;
+			}
+        }
+    }
+	return NULL;	/* not MIME */
+}
+
 /* Get just the plain-text portion of a MIME-encoded message body */
 /* Returns NULL if there is no MIME-encoded plain-text portion of the message */
 char* SMBCALL smb_getplaintext(smbmsg_t* msg, char* buf)
 {
-	int		i;
 	char*	txt;
-	char*	content_type = NULL;
+	char*	content_type = smb_getcontenttype(msg);
 	enum content_transfer_encoding xfer_encoding = CONTENT_TRANFER_ENCODING_NONE;
 
-	for(i=0;i<msg->total_hfields;i++) {
-		if(msg->hfield[i].type==RFC822HEADER) {
-			if(strnicmp((char*)msg->hfield_dat[i],"Content-Type:",13)==0) {
-				content_type=msg->hfield_dat[i];
-				break;
-			}
-        }
-    }
 	if(content_type == NULL)	/* not MIME */
 		return NULL;
 	txt = mime_getcontent(buf, content_type, "text/plain", 0, &xfer_encoding
@@ -442,21 +453,13 @@ char* SMBCALL smb_getplaintext(smbmsg_t* msg, char* buf)
 }
 
 /* Get just an attachment (just one) from MIME-encoded message body */
+/* This function is destructive (over-writes 'buf' with decoded attachment)! */
 uint8_t* SMBCALL smb_getattachment(smbmsg_t* msg, char* buf, char* filename, size_t filename_len, uint32_t* filelen, int index)
 {
-	int		i;
 	char*	txt;
-	char*	content_type = NULL;
+	char*	content_type = smb_getcontenttype(msg);
 	enum content_transfer_encoding xfer_encoding = CONTENT_TRANFER_ENCODING_NONE;
 
-	for(i=0;i<msg->total_hfields;i++) {
-		if(msg->hfield[i].type==RFC822HEADER) {
-			if(strnicmp((char*)msg->hfield_dat[i],"Content-Type:",13)==0) {
-				content_type=msg->hfield_dat[i];
-				break;
-			}
-        }
-    }
 	if(content_type == NULL)	/* not MIME */
 		return NULL;
 	txt = mime_getcontent(buf, content_type, /* match-type: */NULL, 0, &xfer_encoding
@@ -466,9 +469,43 @@ uint8_t* SMBCALL smb_getattachment(smbmsg_t* msg, char* buf, char* filename, siz
 		int result = b64_decode(buf, strlen(buf), buf, strlen(buf));
 		if(result < 1)
 			return NULL;
-		*filelen = result;
+		if(filelen != NULL)
+			*filelen = result;
 		return (uint8_t*)buf;
 	}
 
 	return NULL;	/* No attachment */
 }
+
+/* Return number of file attachments contained in MIME-encoded message body */
+/* 'body' may be NULL if the body text is not already read/available */
+ulong SMBCALL smb_countattachments(smb_t* smb, smbmsg_t* msg, const char* body)
+{
+	char* content_type = smb_getcontenttype(msg);
+
+	if(content_type == NULL)	/* not MIME */
+		return 0;
+
+	ulong count = 0;
+	char* buf;
+
+	if(body == NULL)
+		buf = smb_getmsgtxt(smb, msg, GETMSGTXT_ALL);
+	else
+		buf = strdup(body);
+
+	if(buf == NULL)
+		return 0;
+
+	char* tmp;
+	while((tmp = strdup(buf)) != NULL) {
+		uint8_t* attachment = smb_getattachment(msg, tmp, NULL, 0, NULL, count);
+		free(tmp);
+		if(attachment == NULL)
+			break;
+		count++;
+	}
+
+	free(buf);
+	return count;
+}
-- 
GitLab