diff --git a/src/sbbs3/getmsg.cpp b/src/sbbs3/getmsg.cpp
index 700bb519ce26f59965d30d1fe93a2e1156c63a8f..9d9fcd41ce23d87a5cb4f86689510c4948d5d9b3 100644
--- a/src/sbbs3/getmsg.cpp
+++ b/src/sbbs3/getmsg.cpp
@@ -176,14 +176,6 @@ void sbbs_t::show_msghdr(smbmsg_t* msg)
 	CRLF;
 }
 
-ulong sbbs_t::total_votes(post_t* post)
-{
-	ulong total = 0;
-	for(int i = 0; i < MSG_POLL_MAX_ANSWERS; i++)
-		total += post->votes[i];
-	return total;
-}
-
 /****************************************************************************/
 /* Displays message header and text (if not deleted)                        */
 /****************************************************************************/
@@ -224,8 +216,7 @@ void sbbs_t::show_msg(smbmsg_t* msg, long mode, post_t* post)
 			if(msg->hfield[i].type != SMB_POLL_ANSWER)
 				continue;
 			answer = (char*)msg->hfield_dat[i];
-			ulong total = total_votes(post);
-			float pct = total ? ((float)post->votes[answers] / total)*100.0F : 0.0F;
+			float pct = post->total_votes ? ((float)post->votes[answers] / post->total_votes)*100.0F : 0.0F;
 			char str[128];
 			int width = longest_answer;
 			if(width < cols/3) width = cols/3;
diff --git a/src/sbbs3/js_msgbase.c b/src/sbbs3/js_msgbase.c
index 7a398102838eb7b5144c3e04a627fe1bfdf1d0f1..0f308f5d102ddbff240e665aa88fd69ddbd2e00f 100644
--- a/src/sbbs3/js_msgbase.c
+++ b/src/sbbs3/js_msgbase.c
@@ -1615,6 +1615,7 @@ js_get_all_msg_headers(JSContext *cx, uintN argc, jsval *arglist)
 				if(post[u].idx.number == msg.idx.remsg)
 					break;
 			if(u < off) {
+				post[u].total_votes++;
 				switch(msg.idx.attr&MSG_VOTE) {
 				case MSG_UPVOTE:
 					post[u].upvotes++;
@@ -1623,7 +1624,7 @@ js_get_all_msg_headers(JSContext *cx, uintN argc, jsval *arglist)
 					post[u].downvotes++;
 					break;
 				default:
-					for(int b=0; b < 16; b++) {
+					for(int b=0; b < MSG_POLL_MAX_ANSWERS; b++) {
 						if(msg.idx.votes&(1<<b))
 							post[u].votes[b]++;
 					}
@@ -1669,13 +1670,24 @@ js_get_all_msg_headers(JSContext *cx, uintN argc, jsval *arglist)
 			return JS_TRUE;
 		}
 
+		JS_DefineProperty(cx, hdrobj, "total_votes", UINT_TO_JSVAL(post[off].total_votes)
+			,NULL, NULL, JSPROP_ENUMERATE);
 		if(post[off].upvotes)
 			JS_DefineProperty(cx, hdrobj, "upvotes", UINT_TO_JSVAL(post[off].upvotes)
-				,NULL,NULL,JSPROP_ENUMERATE);
+				,NULL, NULL, JSPROP_ENUMERATE);
 		if(post[off].downvotes)
 			JS_DefineProperty(cx, hdrobj, "downvotes", UINT_TO_JSVAL(post[off].downvotes)
-				,NULL,NULL,JSPROP_ENUMERATE);
-		/* ToDo: Handle votes[] array conversion to property/object/array */
+				,NULL, NULL, JSPROP_ENUMERATE);
+		if(post[off].total_votes) {
+			JSObject*		array;
+			if((array=JS_NewArrayObject(cx,0,NULL)) != NULL) {
+				JS_DefineProperty(cx, hdrobj, "tally", OBJECT_TO_JSVAL(array)
+					,NULL, NULL, JSPROP_ENUMERATE);
+				for(int i=0; i < MSG_POLL_MAX_ANSWERS;i++)
+					JS_DefineElement(cx, array, i, UINT_TO_JSVAL(post[off].votes[i])
+						,NULL, NULL, JSPROP_ENUMERATE);
+			}
+		}
 
 		if(!JS_SetPrivate(cx, hdrobj, p)) {
 			JS_ReportError(cx,"JS_SetPrivate failed");
@@ -2444,7 +2456,7 @@ js_add_poll(JSContext *cx, uintN argc, jsval *arglist)
 }
 
 static JSBool
-js_get_user_votes(JSContext *cx, uintN argc, jsval *arglist)
+js_how_user_voted(JSContext *cx, uintN argc, jsval *arglist)
 {
 	JSObject*	obj=JS_THIS_OBJECT(cx, arglist);
 	jsval*		argv=JS_ARGV(cx, arglist);
@@ -2476,8 +2488,6 @@ js_get_user_votes(JSContext *cx, uintN argc, jsval *arglist)
 	return JS_TRUE;
 }
 
-
-
 /* MsgBase Object Properties */
 enum {
 	 SMB_PROP_LAST_ERROR
@@ -2816,7 +2826,7 @@ static jsSyncMethodSpec js_msgbase_functions[] = {
 	)
 	,317
 	},
-	{"get_user_votes",		js_get_user_votes,		2, JSTYPE_NUMBER,	JSDOCSTR("message number, user name or alias")
+	{"how_user_voted",		js_how_user_voted,		2, JSTYPE_NUMBER,	JSDOCSTR("message number, user name or alias")
 	,JSDOCSTR("Returns 0 for no votes, 1 for an up-vote, 2 for a down-vote, or in the case of a poll-response: a bit-field of votes.")
 	,317
 	},
diff --git a/src/sbbs3/readmsgs.cpp b/src/sbbs3/readmsgs.cpp
index 458384d8ad1fabda252fb26c302b26aa80e6d72a..622affa151c6db4f3726030a7edd23e7e4a862df 100644
--- a/src/sbbs3/readmsgs.cpp
+++ b/src/sbbs3/readmsgs.cpp
@@ -277,6 +277,7 @@ post_t * sbbs_t::loadposts(uint32_t *posts, uint subnum, ulong ptr, long mode, u
 				if(post[u].idx.number == idx.remsg)
 					break;
 			if(u < l) {
+				post[u].total_votes++;
 				switch(idx.attr&MSG_VOTE) {
 				case MSG_UPVOTE:
 					post[u].upvotes++;
@@ -285,7 +286,7 @@ post_t * sbbs_t::loadposts(uint32_t *posts, uint subnum, ulong ptr, long mode, u
 					post[u].downvotes++;
 					break;
 				default:
-					for(int b=0; b < 16; b++) {
+					for(int b=0; b < MSG_POLL_MAX_ANSWERS; b++) {
 						if(idx.votes&(1<<b))
 							post[u].votes[b]++;
 					}
@@ -684,7 +685,7 @@ int sbbs_t::scanposts(uint subnum, long mode, const char *find)
 
 			msg.upvotes = post[smb.curmsg].upvotes;
 			msg.downvotes = post[smb.curmsg].downvotes;
-			msg.total_votes = total_votes(&post[smb.curmsg]);
+			msg.total_votes = post[smb.curmsg].total_votes;
 			show_msg(&msg
 				,msg.from_ext && !strcmp(msg.from_ext,"1") && !msg.from_net.type
 					? 0:P_NOATCODES
diff --git a/src/sbbs3/sbbs.h b/src/sbbs3/sbbs.h
index dcd6fe94d89cef31eb56d34469a8dcddf193b9f6..da28f7b3284edcb750299d0f203378ff8ce26389 100644
--- a/src/sbbs3/sbbs.h
+++ b/src/sbbs3/sbbs.h
@@ -648,7 +648,6 @@ public:
 	ulong	getlastmsg(uint subnum, uint32_t *ptr, time_t *t);
 	time_t	getmsgtime(uint subnum, ulong ptr);
 	ulong	getmsgnum(uint subnum, time_t t);
-	ulong	total_votes(post_t* post);
 
 	/* readmail.cpp */
 	void	readmail(uint usernumber, int sent);
diff --git a/src/sbbs3/sbbsdefs.h b/src/sbbs3/sbbsdefs.h
index efe82384657e7ce2a3c006d4de6a6e1a3acb6bdd..39128e6da1eaa042b6e57192b00d1d68728f6f71 100644
--- a/src/sbbs3/sbbsdefs.h
+++ b/src/sbbs3/sbbsdefs.h
@@ -1008,6 +1008,7 @@ typedef struct {
 		};
 		uint32_t	votes[MSG_POLL_MAX_ANSWERS];
 	};
+	uint32_t	total_votes;
 } post_t;
 typedef idxrec_t mail_t;				/* defined in smbdefs.h */
 typedef fidoaddr_t faddr_t;				/* defined in smbdefs.h */