From 340116b44dfc479e36192357730b4f983a07cb39 Mon Sep 17 00:00:00 2001
From: rswindell <>
Date: Wed, 31 Mar 2004 11:25:25 +0000
Subject: [PATCH] Bugfix: memory leak in MsgBase.save_msg() - wasn't freeing
 msg header memory. MsgBase.save_msg() now supports an optional recipient_list
 argument (array of header objects) to send a single message to multiple
 recipients (e.g. bulkmail).

---
 src/sbbs3/js_msgbase.c | 203 +++++++++++++++++++++++++++--------------
 1 file changed, 135 insertions(+), 68 deletions(-)

diff --git a/src/sbbs3/js_msgbase.c b/src/sbbs3/js_msgbase.c
index 78c3538d97..1acb1cfe24 100644
--- a/src/sbbs3/js_msgbase.c
+++ b/src/sbbs3/js_msgbase.c
@@ -112,10 +112,71 @@ js_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 	return(JS_TRUE);
 }
 
-static BOOL parse_header_object(JSContext* cx, private_t* p, JSObject* hdr, smbmsg_t* msg)
+static BOOL parse_recipient_object(JSContext* cx, private_t* p, JSObject* hdr, smbmsg_t* msg)
 {
 	char*		cp;
 	char		to[256];
+	ushort		nettype;
+	ushort		agent;
+	int32		i32;
+	jsval		val;
+
+	if(JS_GetProperty(cx, hdr, "to", &val) && val!=JSVAL_VOID) {
+		if((cp=JS_GetStringBytes(JS_ValueToString(cx,val)))==NULL)
+			return(FALSE);
+	} else {
+		if(p->smb.status.attr&SMB_EMAIL)	/* e-mail */
+			return(FALSE);					/* "to" property required */
+		cp="All";
+	}
+	smb_hfield_str(msg, RECIPIENT, cp);
+	if(!(p->smb.status.attr&SMB_EMAIL)) {
+		SAFECOPY(to,cp);
+		strlwr(to);
+		msg->idx.to=crc16(to,0);
+	}
+
+		if(JS_GetProperty(cx, hdr, "to_ext", &val) && val!=JSVAL_VOID) {
+			if((cp=JS_GetStringBytes(JS_ValueToString(cx,val)))==NULL)
+				return(FALSE);
+			smb_hfield_str(msg, RECIPIENTEXT, cp);
+			if(p->smb.status.attr&SMB_EMAIL)
+				msg->idx.to=atoi(cp);
+		}
+
+		if(JS_GetProperty(cx, hdr, "to_org", &val) && val!=JSVAL_VOID) {
+			if((cp=JS_GetStringBytes(JS_ValueToString(cx,val)))==NULL)
+				return(FALSE);
+			smb_hfield_str(msg, RECIPIENTORG, cp);
+		}
+
+		if(JS_GetProperty(cx, hdr, "to_net_type", &val) && val!=JSVAL_VOID) {
+			JS_ValueToInt32(cx,val,&i32);
+			nettype=(ushort)i32;
+			smb_hfield(msg, RECIPIENTNETTYPE, sizeof(nettype), &nettype);
+			if(p->smb.status.attr&SMB_EMAIL && nettype!=NET_NONE)
+				msg->idx.to=0;
+		}
+
+		if(JS_GetProperty(cx, hdr, "to_net_addr", &val) && val!=JSVAL_VOID) {
+			if((cp=JS_GetStringBytes(JS_ValueToString(cx,val)))==NULL)
+				return(FALSE);
+			smb_hfield_str(msg, RECIPIENTNETADDR, cp);
+		}
+
+		if(JS_GetProperty(cx, hdr, "to_agent", &val) && val!=JSVAL_VOID) {
+			JS_ValueToInt32(cx,val,&i32);
+			agent=(ushort)i32;
+			smb_hfield(msg, RECIPIENTAGENT, sizeof(agent), &agent);
+		}
+
+	return(TRUE);
+}
+
+static BOOL parse_header_object(JSContext* cx, private_t* p, JSObject* hdr, smbmsg_t* msg
+								,BOOL recipient)
+{
+	char*		cp;
 	char		from[256];
 	ushort		nettype;
 	ushort		type;
@@ -130,6 +191,9 @@ static BOOL parse_header_object(JSContext* cx, private_t* p, JSObject* hdr, smbm
 	if(hdr==NULL)
 		return(FALSE);
 
+	if(recipient && !parse_recipient_object(cx,p,hdr,msg))
+		return(FALSE);
+
 	/* Required Header Fields */
 	if(JS_GetProperty(cx, hdr, "subject", &val) && val!=JSVAL_VOID) {
 		if((cp=JS_GetStringBytes(JS_ValueToString(cx,val)))==NULL)
@@ -139,21 +203,6 @@ static BOOL parse_header_object(JSContext* cx, private_t* p, JSObject* hdr, smbm
 	smb_hfield_str(msg, SUBJECT, cp);
 	msg->idx.subj=subject_crc(cp);
 
-	if(JS_GetProperty(cx, hdr, "to", &val) && val!=JSVAL_VOID) {
-		if((cp=JS_GetStringBytes(JS_ValueToString(cx,val)))==NULL)
-			return(FALSE);
-	} else {
-		if(p->smb.status.attr&SMB_EMAIL)	/* e-mail */
-			return(FALSE);					/* "to" property required */
-		cp="All";
-	}
-	smb_hfield_str(msg, RECIPIENT, cp);
-	if(!(p->smb.status.attr&SMB_EMAIL)) {
-		SAFECOPY(to,cp);
-		strlwr(to);
-		msg->idx.to=crc16(to,0);
-	}
-
 	if(JS_GetProperty(cx, hdr, "from", &val) && val!=JSVAL_VOID) {
 		if((cp=JS_GetStringBytes(JS_ValueToString(cx,val)))==NULL)
 			return(FALSE);
@@ -225,40 +274,6 @@ static BOOL parse_header_object(JSContext* cx, private_t* p, JSObject* hdr, smbm
 		smb_hfield(msg, SENDERPORT, sizeof(port), &port);
 	}
 
-	if(JS_GetProperty(cx, hdr, "to_ext", &val) && val!=JSVAL_VOID) {
-		if((cp=JS_GetStringBytes(JS_ValueToString(cx,val)))==NULL)
-			return(FALSE);
-		smb_hfield_str(msg, RECIPIENTEXT, cp);
-		if(p->smb.status.attr&SMB_EMAIL)
-			msg->idx.to=atoi(cp);
-	}
-
-	if(JS_GetProperty(cx, hdr, "to_org", &val) && val!=JSVAL_VOID) {
-		if((cp=JS_GetStringBytes(JS_ValueToString(cx,val)))==NULL)
-			return(FALSE);
-		smb_hfield_str(msg, RECIPIENTORG, cp);
-	}
-
-	if(JS_GetProperty(cx, hdr, "to_net_type", &val) && val!=JSVAL_VOID) {
-		JS_ValueToInt32(cx,val,&i32);
-		nettype=(ushort)i32;
-		smb_hfield(msg, RECIPIENTNETTYPE, sizeof(nettype), &nettype);
-		if(p->smb.status.attr&SMB_EMAIL && nettype!=NET_NONE)
-			msg->idx.to=0;
-	}
-
-	if(JS_GetProperty(cx, hdr, "to_net_addr", &val) && val!=JSVAL_VOID) {
-		if((cp=JS_GetStringBytes(JS_ValueToString(cx,val)))==NULL)
-			return(FALSE);
-		smb_hfield_str(msg, RECIPIENTNETADDR, cp);
-	}
-
-	if(JS_GetProperty(cx, hdr, "to_agent", &val) && val!=JSVAL_VOID) {
-		JS_ValueToInt32(cx,val,&i32);
-		agent=(ushort)i32;
-		smb_hfield(msg, RECIPIENTAGENT, sizeof(agent), &agent);
-	}
-
 	if(JS_GetProperty(cx, hdr, "replyto", &val) && val!=JSVAL_VOID) {
 		if((cp=JS_GetStringBytes(JS_ValueToString(cx,val)))==NULL)
 			return(FALSE);
@@ -898,7 +913,7 @@ js_put_msg_header(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *
 	JSObject*	hdr=NULL;
 	private_t*	p;
 
-	*rval = BOOLEAN_TO_JSVAL(JS_FALSE);
+	*rval = JSVAL_FALSE;
 
 	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
 		JS_ReportError(cx,getprivate_failure,WHERE);
@@ -952,13 +967,13 @@ js_put_msg_header(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *
 
 		smb_freemsghdrmem(&msg);	/* prevent duplicate header fields */
 
-		if(!parse_header_object(cx, p, hdr, &msg))
+		if(!parse_header_object(cx, p, hdr, &msg, TRUE))
 			break;
 
 		if(smb_putmsg(&(p->smb), &msg)!=0)
 			break;
 
-		*rval = BOOLEAN_TO_JSVAL(JS_TRUE);
+		*rval = JSVAL_TRUE;
 	} while(0);
 
 	smb_unlockmsghdr(&(p->smb),&msg); 
@@ -976,7 +991,7 @@ js_remove_msg(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval
 	smbmsg_t	msg;
 	private_t*	p;
 
-	*rval = BOOLEAN_TO_JSVAL(JS_FALSE);
+	*rval = JSVAL_FALSE;
 
 	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
 		JS_ReportError(cx,getprivate_failure,WHERE);
@@ -1031,7 +1046,7 @@ js_remove_msg(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval
 		if(smb_putmsg(&(p->smb), &msg)!=0)
 			break;
 
-		*rval = BOOLEAN_TO_JSVAL(JS_TRUE);
+		*rval = JSVAL_TRUE;
 	} while(0);
 
 	smb_unlockmsghdr(&(p->smb),&msg); 
@@ -1243,12 +1258,18 @@ js_save_msg(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
 	char*		body=NULL;
 	uintN		n;
+    jsuint      i;
+    jsuint      rcpt_list_length;
+	jsval       val;
 	JSObject*	hdr=NULL;
+	JSObject*	objarg;
+	JSObject*	rcpt_list=NULL;
+	smbmsg_t	rcpt_msg;
 	smbmsg_t	msg;
 	jsval		open_rval;
 	private_t*	p;
 
-	*rval = BOOLEAN_TO_JSVAL(JS_FALSE);
+	*rval = JSVAL_FALSE;
 
 	if(argc<2)
 		return(JS_TRUE);
@@ -1268,8 +1289,13 @@ js_save_msg(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 	memset(&msg,0,sizeof(msg));
 
 	for(n=0;n<argc;n++) {
-		if(JSVAL_IS_OBJECT(argv[n]))
-			hdr = JSVAL_TO_OBJECT(argv[n]);
+		if(JSVAL_IS_OBJECT(argv[n])) {
+			objarg = JSVAL_TO_OBJECT(argv[n]);
+			if(JS_IsArrayObject(cx, objarg)) 	/* recipient_list is an array of objects */
+				rcpt_list = objarg;
+			else
+				hdr = objarg;
+		}
 		else if(JSVAL_IS_STRING(argv[n])) {
 			if((body=JS_GetStringBytes(JSVAL_TO_STRING(argv[n])))==NULL) {
 				JS_ReportError(cx,"JS_GetStringBytes failed");
@@ -1281,17 +1307,52 @@ js_save_msg(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 	if(hdr==NULL || body==NULL)
 		return(JS_TRUE);
 
-	if(!parse_header_object(cx, p, hdr, &msg))
-		return(JS_TRUE);
+	if(rcpt_list!=NULL) {
+		if(!JS_GetArrayLength(cx, rcpt_list, &rcpt_list_length))
+			return(JS_TRUE);
+		if(!rcpt_list_length)
+			return(JS_TRUE);
+	}
 
-	if(msg.hdr.when_written.time==0) {
-		msg.hdr.when_written.time=time(NULL);
-		msg.hdr.when_written.zone=sys_timezone(scfg);
+	if(parse_header_object(cx, p, hdr, &msg, rcpt_list==NULL)) {
+
+		truncsp(body);
+		if(savemsg(scfg, &(p->smb), &msg, body)==0)
+			*rval = JSVAL_TRUE;
+
+		if(rcpt_list!=NULL) {	/* Sending to a list of recipients */
+
+			*rval = JSVAL_FALSE;	/* failure, by default */
+
+			memset(&rcpt_msg, 0, sizeof(rcpt_msg));
+
+			for(i=0;i<rcpt_list_length;i++) {
+
+				if(!JS_GetElement(cx, rcpt_list, i, &val))
+					break;
+				
+				if(!JSVAL_IS_OBJECT(val))
+					break;
+
+				if(smb_copymsgmem(&(p->smb), &rcpt_msg, &msg)!=0)
+					break;
+
+				if(!parse_recipient_object(cx, p, JSVAL_TO_OBJECT(val), &rcpt_msg))
+					break;
+
+				if(smb_addmsghdr(&(p->smb), &rcpt_msg, SMB_SELFPACK)!=0)
+					break;
+
+				smb_freemsgmem(&rcpt_msg);
+			}
+			smb_freemsgmem(&rcpt_msg);	/* just in case we broke the loop */
+
+			if(i==rcpt_list_length)
+				*rval = JSVAL_TRUE;	/* success */
+		}
 	}
 
-	truncsp(body);
-	if(savemsg(scfg, &(p->smb), &msg, body)==0)
-		*rval = BOOLEAN_TO_JSVAL(JS_TRUE);
+	smb_freemsgmem(&msg);
 
 	return(JS_TRUE);
 }
@@ -1514,7 +1575,7 @@ static jsSyncMethodSpec js_msgbase_functions[] = {
 	,JSDOCSTR("mark message as deleted")
 	,311
 	},
-	{"save_msg",		js_save_msg,		2, JSTYPE_BOOLEAN,	JSDOCSTR("object header, string body_text")
+	{"save_msg",		js_save_msg,		2, JSTYPE_BOOLEAN,	JSDOCSTR("object header, string body_text [,array rcpt_list]")
 	,JSDOCSTR("create a new message in message base, the <i>header</i> object may contain the following properties:<br>"
 	"<table>"
 	"<tr><td><tt>subject</tt><td>Message subject <i>(required)</i>"
@@ -1563,7 +1624,13 @@ static jsSyncMethodSpec js_msgbase_functions[] = {
 	"<tr><td><tt>thread_first</tt><td>Number of first reply to this message"
 	"<tr><td><tt>field_list[].type</tt><td>Other SMB header fields (type)"
 	"<tr><td><tt>field_list[].data</tt><td>Other SMB header fields (data)"
-	"</table>")
+	"</table>"
+	"<br>"
+	"The optional <i>rcpt_list</i> is an array of objects that specifies multiple recipients "
+	"for a single message (e.g. bulk e-mail). Each object in the array may include the following header properties "
+	"(described above): <br>"
+	"<i>to</i>, <i>to_ext</i>, <i>to_org</i>, <i>to_net_type</i>, <i>to_net_addr</i>, and <i>to_agent</i>"
+	)
 	,310
 	},
 	{0}
-- 
GitLab