From d79e9514b39faee53db1fae0b4e1fb4e81edaeb7 Mon Sep 17 00:00:00 2001
From: Rob Swindell <rob@synchro.net>
Date: Thu, 10 Dec 2020 17:42:41 -0800
Subject: [PATCH] Support forwarding of single-part HTML emails, add "Fwd:"
 subject prefix

When forwarding a single-part MIME-encoded HTML email, the preamble (original message header info) and any user comments, need to be HTML-encoded.

Add the commonly-used "Fwd: " prefix to the default message subject, when forwarding.

This required that smb_getplaintext() no longer always-NULLify the message's text_subtype (e.g. "html"). For single-part messages, this element was getting freed and NULLed.

Add/use a new SMBLIB convenience function to add a string header field, but only if non-NULL: smb_hfield_string()
---
 src/sbbs3/writemsg.cpp | 55 +++++++++++++++++++++++++++++-------------
 src/smblib/smblib.c    | 12 ++++++++-
 src/smblib/smblib.h    |  1 +
 src/smblib/smbtxt.c    |  6 +++--
 4 files changed, 54 insertions(+), 20 deletions(-)

diff --git a/src/sbbs3/writemsg.cpp b/src/sbbs3/writemsg.cpp
index f23d137d0d..784ef5e38b 100644
--- a/src/sbbs3/writemsg.cpp
+++ b/src/sbbs3/writemsg.cpp
@@ -743,11 +743,8 @@ bool sbbs_t::writemsg(const char *fname, const char *top, char *subj, long mode,
 
 void sbbs_t::editor_info_to_msg(smbmsg_t* msg, const char* editor, const char* charset)
 {
-	if(editor != NULL)
-		smb_hfield_str(msg, SMB_EDITOR, editor);
-
-	if(charset != NULL)
-		smb_hfield_str(msg, FIDOCHARSET, charset);
+	smb_hfield_string(msg, SMB_EDITOR, editor);
+	smb_hfield_string(msg, FIDOCHARSET, charset);
 
 	ushort useron_xedit = useron.xedit;
 
@@ -1375,7 +1372,7 @@ bool sbbs_t::forwardmail(smbmsg_t* orgmsg, const char* to, const char* subject,
 
 	if(subject == NULL) {
 		subject = subj;
-		SAFECOPY(subj, orgmsg->subj);
+		SAFEPRINTF(subj, "Fwd: %s", orgmsg->subj);
 		bputs(text[SubjectPrompt]);
 		if(!getstr(subj, sizeof(subj) - 1, K_LINE | K_EDIT | K_AUTODEL | K_TRIM))
 			return false;
@@ -1441,33 +1438,57 @@ bool sbbs_t::forwardmail(smbmsg_t* orgmsg, const char* to, const char* subject,
 	time32_t now32 = time32(NULL);
 	smb_hfield(&msg, FORWARDED, sizeof(now32), &now32);
 
+	char* br = NULL;
+	char* pg = nulstr;
+	char* lt = "<";
+	char* gt = ">";
+	if(orgmsg->text_subtype != NULL && stricmp(orgmsg->text_subtype, "html") == 0) {
+		lt = "&lt;";
+		gt = "&gt;";
+		br = "<br>";
+		pg = "<p>";
+	}
+
 	if(comment == NULL) {
-		while(online) {
+		while(online && !msgabort()) {
 			bputs(text[UeditComment]);
 			if(!getstr(str, 70, K_WRAP))
 				break;
-			smb_hfield_str(&msg, SMB_COMMENT, str);
+			smb_hfield_string(&msg, SMB_COMMENT, str);
+			smb_hfield_string(&msg, SMB_COMMENT, br);
+		}
+		if(!online || msgabort()) {
+			smb_freemsgmem(&msg);
+			return false; 
 		}
 	} else {
 		if(*comment)
-			smb_hfield_str(&msg, SMB_COMMENT, comment);
+			smb_hfield_string(&msg, SMB_COMMENT, comment);
 	}
-	smb_hfield_str(&msg, SMB_COMMENT, "-----Forwarded Message-----");
+	if(smb_get_hfield(&msg, SMB_COMMENT, NULL) != NULL)
+		smb_hfield_string(&msg, SMB_COMMENT, pg);
+	smb_hfield_string(&msg, SMB_COMMENT, "-----Forwarded Message-----");
+	smb_hfield_string(&msg, SMB_COMMENT, br);
 	if(orgmsg->from_net.addr != NULL)
-		safe_snprintf(str, sizeof(str), "From: %s <%s>",orgmsg->from, smb_netaddrstr(&orgmsg->from_net, tmp));
+		safe_snprintf(str, sizeof(str), "From: %s %s%s%s"
+			,orgmsg->from, lt, smb_netaddrstr(&orgmsg->from_net, tmp), gt);
 	else
 		safe_snprintf(str, sizeof(str), "From: %s", orgmsg->from);
-	smb_hfield_str(&msg, SMB_COMMENT, str);
+	smb_hfield_string(&msg, SMB_COMMENT, str);
+	smb_hfield_string(&msg, SMB_COMMENT, br);
 	safe_snprintf(str, sizeof(str), "Date: %s", msgdate(orgmsg->hdr.when_written, tmp));
-	smb_hfield_str(&msg, SMB_COMMENT, str);
+	smb_hfield_string(&msg, SMB_COMMENT, str);
+	smb_hfield_string(&msg, SMB_COMMENT, br);
 	if(orgmsg->to_net.addr != NULL)
-		safe_snprintf(str, sizeof(str), "To: %s <%s>", orgmsg->to, smb_netaddrstr(&orgmsg->to_net, tmp));
+		safe_snprintf(str, sizeof(str), "To: %s %s%s%s"
+			,orgmsg->to, lt, smb_netaddrstr(&orgmsg->to_net, tmp), gt);
 	else
 		safe_snprintf(str, sizeof(str), "To: %s", orgmsg->to);
-	smb_hfield_str(&msg, SMB_COMMENT, str);
+	smb_hfield_string(&msg, SMB_COMMENT, str);
+	smb_hfield_string(&msg, SMB_COMMENT, br);
 	safe_snprintf(str, sizeof(str), "Subject: %s", orgmsg->subj);
-	smb_hfield_str(&msg, SMB_COMMENT, str);
-	smb_hfield_str(&msg, SMB_COMMENT, nulstr);
+	smb_hfield_string(&msg, SMB_COMMENT, str);
+	smb_hfield_string(&msg, SMB_COMMENT, pg);
 
 	// Re-use the original message's data
 	if((result = smb_open_da(&smb)) != SMB_SUCCESS) {
diff --git a/src/smblib/smblib.c b/src/smblib/smblib.c
index 14b669f878..9f77bbeb88 100644
--- a/src/smblib/smblib.c
+++ b/src/smblib/smblib.c
@@ -1218,13 +1218,23 @@ int	SMBCALL smb_hfield_add_list(smbmsg_t* msg, hfield_t** hfield_list, void** hf
 }
 
 /****************************************************************************/
-/* Convenience function to add an ASCIIZ string header field				*/
+/* Convenience function to add an ASCIIZ string header field (or blank)		*/
 /****************************************************************************/
 int SMBCALL smb_hfield_add_str(smbmsg_t* msg, uint16_t type, const char* str, BOOL insert)
 {
 	return smb_hfield_add(msg, type, str==NULL ? 0:strlen(str), (void*)str, insert);
 }
 
+/****************************************************************************/
+/* Convenience function to add an ASCIIZ string header field (NULL ignored)	*/
+/****************************************************************************/
+int SMBCALL smb_hfield_string(smbmsg_t* msg, uint16_t type, const char* str)
+{
+	if(str == NULL)
+		return SMB_ERR_HDR_FIELD;
+	return smb_hfield_add(msg, type, strlen(str), (void*)str, /* insert */FALSE);
+}
+
 /****************************************************************************/
 /* Convenience function to a network address header field to msg			*/
 /* Pass NULL for net_type to have the auto-detected net_type hfield	added	*/
diff --git a/src/smblib/smblib.h b/src/smblib/smblib.h
index 5c1c55e7a9..fbe37ffbf9 100644
--- a/src/smblib/smblib.h
+++ b/src/smblib/smblib.h
@@ -160,6 +160,7 @@ SMBEXPORT int		SMBCALL smb_hfield_append(smbmsg_t* msg, uint16_t type, size_t le
 SMBEXPORT int		SMBCALL smb_hfield_append_str(smbmsg_t* msg, uint16_t type, const char* data);
 SMBEXPORT int		SMBCALL smb_hfield_add_list(smbmsg_t* msg, hfield_t** hfield_list, void** hfield_dat, BOOL insert);
 SMBEXPORT int		SMBCALL smb_hfield_add_netaddr(smbmsg_t* msg, uint16_t type, const char* str, uint16_t* nettype, BOOL insert);
+SMBEXPORT int		SMBCALL	smb_hfield_string(smbmsg_t*, uint16_t type, const char*);
 /* Convenience macro: */
 #define smb_hfield_bin(msg, type, data) smb_hfield_add(msg, type, sizeof(data), &(data), /* insert: */FALSE)
 /* Backward compatibility macros: */
diff --git a/src/smblib/smbtxt.c b/src/smblib/smbtxt.c
index 4b65c9c429..0ffce0d1d5 100644
--- a/src/smblib/smbtxt.c
+++ b/src/smblib/smbtxt.c
@@ -495,7 +495,6 @@ char* SMBCALL smb_getplaintext(smbmsg_t* msg, char* buf)
 	const char*	txt;
 	enum content_transfer_encoding xfer_encoding = CONTENT_TRANFER_ENCODING_NONE;
 
-	FREE_AND_NULL(msg->text_subtype);
 	if(msg->mime_version == NULL || msg->content_type == NULL)	/* not MIME */
 		return NULL;
 	txt = mime_getcontent(buf, msg->content_type, "text/plain", 0, &xfer_encoding, &msg->text_charset
@@ -505,9 +504,12 @@ char* SMBCALL smb_getplaintext(smbmsg_t* msg, char* buf)
 			,/* attachment: */NULL, /* attachment_len: */0, /* index: */0);
 		if(txt == NULL)
 			return NULL;
+		free(msg->text_subtype);
 		msg->text_subtype = strdup("html");
-	} else
+	} else {
+		free(msg->text_subtype);
 		msg->text_subtype = strdup("plain");
+	}
 
 	memmove(buf, txt, strlen(txt)+1);
 	if(*buf == 0)	/* No decoding necessary */
-- 
GitLab