diff --git a/src/sbbs3/js_bbs.cpp b/src/sbbs3/js_bbs.cpp
index 4f7cb66028909905af3df23ac65da175c8651727..7c4d80059fb3317f527d8776eff63e40a07826e8 100644
--- a/src/sbbs3/js_bbs.cpp
+++ b/src/sbbs3/js_bbs.cpp
@@ -2316,6 +2316,31 @@ js_batch_sort(JSContext *cx, uintN argc, jsval *arglist)
 	return(JS_TRUE);
 }
 
+static JSBool
+js_xfer_prot_menu(JSContext *cx, uintN argc, jsval *arglist)
+{
+	jsval *argv=JS_ARGV(cx, arglist);
+	sbbs_t*		sbbs;
+	jsrefcount	rc;
+	enum XFER_TYPE xfer_type = XFER_DOWNLOAD;
+
+	if((sbbs=js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist)))==NULL)
+		return(JS_FALSE);
+
+	JS_SET_RVAL(cx, arglist, JSVAL_VOID);
+
+	if(argc > 0 && argv[0] == JSVAL_TRUE)
+		xfer_type = XFER_BATCH_UPLOAD;
+	if(argc > 1 && argv[1] == JSVAL_TRUE)
+		xfer_type = (xfer_type == XFER_UPLOAD) ? XFER_BATCH_UPLOAD : XFER_BATCH_DOWNLOAD;
+
+	rc=JS_SUSPENDREQUEST(cx);
+	sbbs->xfer_prot_menu(xfer_type);
+	JS_RESUMEREQUEST(cx, rc);
+
+	return(JS_TRUE);
+}
+
 static JSBool
 js_viewfile(JSContext *cx, uintN argc, jsval *arglist)
 {
@@ -4652,6 +4677,10 @@ static jsSyncMethodSpec js_bbs_functions[] = {
 	,JSDOCSTR("Display the file transfer policy")
 	,310
 	},
+	{"xfer_prot_menu",	js_xfer_prot_menu,	0,	JSTYPE_VOID,	JSDOCSTR("[<i>bool</i> upload=false] [,<i>bool</i> batch=false]")
+	,JSDOCSTR("Display file transfer protocol menu")
+	,320
+	},
 	{"batch_menu",		js_batchmenu,		0,	JSTYPE_VOID,	JSDOCSTR("")
 	,JSDOCSTR("Enter the batch file transfer menu")
 	,310