diff --git a/src/sbbs3/js_msgbase.c b/src/sbbs3/js_msgbase.c
index 311ed55796a217730172edb76d633637fb32b275..4a7c915e5705022025b9fe8f348272fb764dd8de 100644
--- a/src/sbbs3/js_msgbase.c
+++ b/src/sbbs3/js_msgbase.c
@@ -1,6 +1,7 @@
 /* Synchronet JavaScript "MsgBase" Object */
 
 /* $Id$ */
+// vi: tabstop=4
 
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
@@ -2493,6 +2494,47 @@ js_how_user_voted(JSContext *cx, uintN argc, jsval *arglist)
 	return JS_TRUE;
 }
 
+static JSBool
+js_close_poll(JSContext *cx, uintN argc, jsval *arglist)
+{
+	JSObject*	obj=JS_THIS_OBJECT(cx, arglist);
+	jsval*		argv=JS_ARGV(cx, arglist);
+	int32		msgnum;
+	private_t*	p;
+	char*		name;
+	int			result;
+	jsrefcount	rc;
+	scfg_t*		scfg;
+
+	scfg = JS_GetRuntimePrivate(JS_GetRuntime(cx));
+
+	JS_SET_RVAL(cx, arglist, JSVAL_VOID);
+	
+	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
+		JS_ReportError(cx,getprivate_failure,WHERE);
+		return JS_FALSE;
+	}
+
+	if(!SMB_IS_OPEN(&(p->smb)))
+		return JS_TRUE;
+
+	if(!JS_ValueToInt32(cx, argv[0], &msgnum))
+		return JS_FALSE;
+
+	JSVALUE_TO_MSTRING(cx, argv[1], name, NULL)
+	HANDLE_PENDING(cx);
+	if(name==NULL)
+		return JS_TRUE;
+
+	rc=JS_SUSPENDREQUEST(cx);
+	result = closepoll(scfg, &(p->smb), msgnum, name);
+	JS_RESUMEREQUEST(cx, rc);
+
+	JS_SET_RVAL(cx, arglist, result == SMB_SUCCESS ? JSVAL_TRUE : JSVAL_FALSE);
+
+	return JS_TRUE;
+}
+
 /* MsgBase Object Properties */
 enum {
 	 SMB_PROP_LAST_ERROR
@@ -2831,6 +2873,10 @@ static jsSyncMethodSpec js_msgbase_functions[] = {
 	)
 	,317
 	},
+	{"close_poll",		js_close_poll,		2, JSTYPE_BOOLEAN,	JSDOCSTR("message number, user name or alias")
+	,JSDOCSTR("close an existing poll")
+	,317
+	},
 	{"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