Skip to content
Snippets Groups Projects
js_bbs.cpp 139 KiB
Newer Older
					jsval val;
					if (!JS_GetElement(cx, hdrobj, j, &val)) {
						error = true;
						break;
					}
					if ((js_str = JS_ValueToString(cx, val)) == NULL) {
						error = true;
						break;
					}
					char* cstr = NULL;
					JSSTRING_TO_ASTRING(cx, js_str, cstr, 64, NULL);
						error = true;
						break;
					}
					strListPush(&to_list, cstr);
				}
				continue;
			}
			if (!js_GetMsgHeaderObjectPrivates(cx, hdrobj, &resmb, &remsg, /* post: */ NULL)) {
				if (!js_ParseMsgHeaderObject(cx, hdrobj, &msg)) {
					JS_ReportError(cx, "msg hdr object cannot be parsed");
					error = true;
					break;
	rc = JS_SUSPENDREQUEST(cx);
	if (!error)
		JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(sbbs->netmail(to, subj, mode, resmb, remsg, to_list)));
	strListFree(&to_list);
rswindell's avatar
rswindell committed
	FREE_AND_NULL(subj);
	FREE_AND_NULL(to);
js_bulkmail(JSContext *cx, uintN argc, jsval *arglist)
	jsval *    argv = JS_ARGV(cx, arglist);
	uchar*     ar = NULL;
	sbbs_t*    sbbs;
	jsrefcount rc;
	char *     p;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
deuce's avatar
deuce committed
		JSVALUE_TO_MSTRING(cx, argv[0], p, NULL);
		ar = arstr(NULL, p, &sbbs->cfg, NULL);
deuce's avatar
deuce committed
		free(p);
	rc = JS_SUSPENDREQUEST(cx);
	sbbs->bulkmail(ar);
js_upload_file(JSContext *cx, uintN argc, jsval *arglist)
	jsval *    argv = JS_ARGV(cx, arglist);
	uint       dirnum = 0;
	sbbs_t*    sbbs;
	jsrefcount rc;
	char*      fname = nullptr;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	dirnum = get_dirnum(cx, sbbs, argv[0], argc == 0);
	if (!dirnum_is_valid(&sbbs->cfg, dirnum)) {
		JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
	if (argc > 1 && JSVAL_IS_STRING(argv[1])) {
		JSString* js_str;
		if ((js_str = JS_ValueToString(cx, argv[1])) == NULL)
			return JS_FALSE;
		JSSTRING_TO_MSTRING(cx, js_str, fname, NULL);
	}

	rc = JS_SUSPENDREQUEST(cx);
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(sbbs->upload(dirnum, fname)));
	free(fname);
static JSBool
js_batch_upload(JSContext *cx, uintN argc, jsval *arglist)
{
	sbbs_t*    sbbs;
	jsrefcount rc;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	rc = JS_SUSPENDREQUEST(cx);
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(sbbs->batch_upload()));
	JS_RESUMEREQUEST(cx, rc);
	return JS_TRUE;
}

static JSBool
js_bulkupload(JSContext *cx, uintN argc, jsval *arglist)
	jsval *    argv = JS_ARGV(cx, arglist);
	uint       dirnum = 0;
	sbbs_t*    sbbs;
	jsrefcount rc;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	dirnum = get_dirnum(cx, sbbs, argv[0], argc == 0);
	if (!dirnum_is_valid(&sbbs->cfg, dirnum)) {
		JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
	rc = JS_SUSPENDREQUEST(cx);
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(sbbs->bulkupload(dirnum) == 0));
rswindell's avatar
rswindell committed
static JSBool
js_telnet_gate(JSContext *cx, uintN argc, jsval *arglist)
rswindell's avatar
rswindell committed
{
	jsval *    argv = JS_ARGV(cx, arglist);
	uintN      argn;
	char*      addr;
	uint32     mode = 0;
	uint32     timeout = 10;
	JSString*  js_addr;
	sbbs_t*    sbbs;
	str_list_t send_strings = NULL;
	jsrefcount rc;
	if (js_argcIsInsufficient(cx, argc, 1))
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	if ((js_addr = JS_ValueToString(cx, argv[0])) == NULL)
deuce's avatar
deuce committed
	JSSTRING_TO_MSTRING(cx, js_addr, addr, NULL);
	if (argc > argn && JSVAL_IS_NUMBER(argv[argn])) {
		if (!JS_ValueToECMAUint32(cx, argv[argn], &mode)) {
deuce's avatar
deuce committed
			free(addr);
	if (argc > argn && JSVAL_IS_NUMBER(argv[argn])) {
		if (!JS_ValueToECMAUint32(cx, argv[argn], &timeout)) {
	if (argc > argn && JSVAL_IS_OBJECT(argv[argn])) {
		JSObject* array = JSVAL_TO_OBJECT(argv[argn]);
		jsuint    count = 0;
		if (array != NULL && JS_IsArrayObject(cx, array) && JS_GetArrayLength(cx, array, &count)) {
			for (jsuint i = 0; i < count; ++i) {
				if (!JS_GetElement(cx, array, i, &val))
					break;
				JSVALUE_TO_RASTRING(cx, val, tmp, &tmplen, NULL);
				strListPush(&send_strings, tmp);
			}
			free(tmp);
			++argn;
		}
	rc = JS_SUSPENDREQUEST(cx);
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(sbbs->telnet_gate(addr, mode, timeout, send_strings)));
deuce's avatar
deuce committed
	free(addr);
#define TG_MODE_UNSPECIFIED ~0U
static JSBool
js_rlogin_gate(JSContext *cx, uintN argc, jsval *arglist)
{
	jsval*     argv = JS_ARGV(cx, arglist);
	uintN      argn;
	char*      addr;
	char*      client_user_name = NULL;
	char*      server_user_name = NULL;
	char*      term_type = NULL;
	bool       fail = false;
	uint32     mode = TG_MODE_UNSPECIFIED;
	uint32     timeout = 10;
	JSString*  js_str;
	sbbs_t*    sbbs;
	str_list_t send_strings = NULL;
	jsrefcount rc;
	if (js_argcIsInsufficient(cx, argc, 1))
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	if ((js_str = JS_ValueToString(cx, argv[0])) == NULL)
	JSSTRING_TO_MSTRING(cx, js_str, addr, NULL);
	/* Parse optional arguments if provided */
	for (argn = 1; argn < argc; argn++) {
		if (JSVAL_IS_STRING(argv[argn])) {
			if ((js_str = JS_ValueToString(cx, argv[argn])) == NULL) {
			if (client_user_name == NULL) {
				JSSTRING_TO_MSTRING(cx, js_str, client_user_name, NULL);
			} else if (server_user_name == NULL) {
				JSSTRING_TO_MSTRING(cx, js_str, server_user_name, NULL);
			} else if (term_type == NULL) {
				JSSTRING_TO_MSTRING(cx, js_str, term_type, NULL);
			}
		} else if (JSVAL_IS_NUMBER(argv[argn])) {
			if (mode == TG_MODE_UNSPECIFIED) {
				if (!JS_ValueToECMAUint32(cx, argv[argn], &mode)) {
				if (!JS_ValueToECMAUint32(cx, argv[argn], &timeout)) {
		} else if (JSVAL_IS_OBJECT(argv[argn])) {
			JSObject* array = JSVAL_TO_OBJECT(argv[argn]);
			jsuint    count = 0;
			if (array != NULL && JS_IsArrayObject(cx, array) && JS_GetArrayLength(cx, array, &count)) {
				for (jsuint i = 0; i < count; ++i) {
					if (!JS_GetElement(cx, array, i, &val))
						break;
					JSVALUE_TO_RASTRING(cx, val, tmp, &tmplen, NULL);
					strListPush(&send_strings, tmp);
				}
				free(tmp);
			}
	if (!fail) {
		if (mode == TG_MODE_UNSPECIFIED)
		rc = JS_SUSPENDREQUEST(cx);
		            , BOOLEAN_TO_JSVAL(sbbs->telnet_gate(addr, mode | TG_RLOGIN, timeout, send_strings, client_user_name, server_user_name, term_type)));
	FREE_AND_NULL(client_user_name);
	FREE_AND_NULL(server_user_name);
	FREE_AND_NULL(term_type);
	return fail ? JS_FALSE : JS_TRUE;
js_pagesysop(JSContext *cx, uintN argc, jsval *arglist)
	sbbs_t*    sbbs;
	jsrefcount rc;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	rc = JS_SUSPENDREQUEST(cx);
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(sbbs->sysop_page()));
js_pageguru(JSContext *cx, uintN argc, jsval *arglist)
	sbbs_t*    sbbs;
	jsrefcount rc;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	rc = JS_SUSPENDREQUEST(cx);
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(sbbs->guru_page()));
js_multinode_chat(JSContext *cx, uintN argc, jsval *arglist)
	jsval *    argv = JS_ARGV(cx, arglist);
	sbbs_t*    sbbs;
	int32      channel = 1;
	jsrefcount rc;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	if (argc > 0 && JSVAL_IS_NUMBER(argv[0])) {
		if (!JS_ValueToInt32(cx, argv[0], &channel))
	rc = JS_SUSPENDREQUEST(cx);
rswindell's avatar
rswindell committed
	sbbs->multinodechat(channel);
js_private_message(JSContext *cx, uintN argc, jsval *arglist)
	sbbs_t*    sbbs;
	jsrefcount rc;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	rc = JS_SUSPENDREQUEST(cx);
rswindell's avatar
rswindell committed
	sbbs->nodemsg();
js_private_chat(JSContext *cx, uintN argc, jsval *arglist)
	jsval *    argv = JS_ARGV(cx, arglist);
	sbbs_t*    sbbs;
	JSBool     local = false;
	jsrefcount rc;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	if (argc)
		JS_ValueToBoolean(cx, argv[0], &local);
	rc = JS_SUSPENDREQUEST(cx);
	sbbs->privchat(local ? true:false); // <- eliminates stupid msvc6 "performance warning"
js_get_node_message(JSContext *cx, uintN argc, jsval *arglist)
	jsval*     argv = JS_ARGV(cx, arglist);
	sbbs_t*    sbbs;
	jsrefcount rc;
	JSBool     clearline = false;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	if (argc > 0 && JSVAL_IS_BOOLEAN(argv[0]))
		clearline = JSVAL_TO_BOOLEAN(argv[0]);

	rc = JS_SUSPENDREQUEST(cx);
	sbbs->getnmsg(clearline ? true : false);
js_put_node_message(JSContext *cx, uintN argc, jsval *arglist)
	jsval *    argv = JS_ARGV(cx, arglist);
	uintN      argn = 0;
	sbbs_t*    sbbs;
	int32      nodenum = 0;
	JSString*  js_msg;
	char*      msg = NULL;
	char       str[256];
	char       tmp[512];
	jsrefcount rc;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	/* Get the destination node number */
	if (argn < argc && JSVAL_IS_NUMBER(argv[argn])) {
		if (!JS_ValueToInt32(cx, argv[argn], &nodenum))
		rc = JS_SUSPENDREQUEST(cx);
		nodenum = sbbs->getnodetopage(/* all: */ TRUE, /* telegram: */ FALSE);
		JS_RESUMEREQUEST(cx, rc);
	node_t node{};
	if (nodenum >= 1) {  /* !all */
		usernumber = node.useron;
		if ((node.misc & NODE_POFF) && !user_is_sysop(&sbbs->useron)) {
			sbbs->bprintf(sbbs->text[CantPageNode]
			              , node.misc & NODE_ANON ? sbbs->text[UNKNOWN_USER] : username(&sbbs->cfg, node.useron, tmp));
	/* Get the node message text */
	if (argn < argc) {
		if ((js_msg = JS_ValueToString(cx, argv[argn])) == NULL)
			return JS_FALSE;
		argn++;
		JSSTRING_TO_MSTRING(cx, js_msg, msg, NULL);
	} else {
			sbbs->bprintf(sbbs->text[SendingMessageToUser]
			              , node.misc & NODE_ANON ? sbbs->text[UNKNOWN_USER]
			    : username(&sbbs->cfg, node.useron, tmp)
			              , node.misc & NODE_ANON ? 0 : node.useron);
		sbbs->bputs(sbbs->text[NodeMsgPrompt]);
		rc = JS_SUSPENDREQUEST(cx);
		int  result = sbbs->getstr(line, 69, K_LINE);
		JS_RESUMEREQUEST(cx, rc);
		snprintf(str, sizeof str, sbbs->text[nodenum >= 1 ? NodeMsgFmt : AllNodeMsgFmt]
		         , sbbs->cfg.node_num
		         , sbbs->thisnode.misc & NODE_ANON
		        ? sbbs->text[UNKNOWN_USER] : sbbs->useron.alias, line);
		return JS_FALSE;

	/* Send the message(s) */
	rc = JS_SUSPENDREQUEST(cx);
	if (nodenum < 0) {  /* ALL */
		for (int i = 1; i <= sbbs->cfg.sys_nodes && success; i++) {
			if (i == sbbs->cfg.node_num)
			if ((node.status == NODE_INUSE
			     || (user_is_sysop(&sbbs->useron) && node.status == NODE_QUIET))
			    && (user_is_sysop(&sbbs->useron) || !(node.misc & NODE_POFF)))
				if (putnmsg(&sbbs->cfg, i, msg) != 0)
			sbbs->logline("C", "sent message to all nodes");
			sbbs->logline(nulstr, msg);
		success = putnmsg(&sbbs->cfg, nodenum, msg) == 0;
		if (success && !(node.misc & NODE_ANON))
			sbbs->bprintf(sbbs->text[MsgSentToUser], "Message"
			              , username(&sbbs->cfg, usernumber, tmp), usernumber);
		SAFEPRINTF3(str, "%s message to %s on node %d:"
		            , success ? "sent" : "FAILED to send", username(&sbbs->cfg, usernumber, tmp), nodenum);
		sbbs->logline("C", str);
		sbbs->logline(nulstr, msg);
	}
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(success));
js_get_telegram(JSContext *cx, uintN argc, jsval *arglist)
	jsval *    argv = JS_ARGV(cx, arglist);
	sbbs_t*    sbbs;
	int32      usernumber;
	jsrefcount rc;
	JSBool     clearline = false;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	usernumber = sbbs->useron.number;
	if (argc && JSVAL_IS_NUMBER(argv[0])) {
		if (!JS_ValueToInt32(cx, argv[0], &usernumber))
	if (argc > 1 && JSVAL_IS_BOOLEAN(argv[1]))
		clearline = JSVAL_TO_BOOLEAN(argv[1]);
	rc = JS_SUSPENDREQUEST(cx);
	sbbs->getsmsg(usernumber, clearline ? true : false);
js_put_telegram(JSContext *cx, uintN argc, jsval *arglist)
	jsval *    argv = JS_ARGV(cx, arglist);
	uintN      argn = 0;
	sbbs_t*    sbbs;
	int32      usernumber = 0;
	JSString*  js_msg = NULL;
	char*      msg = NULL;
	char       str[256];
	char       tmp[512];
	char       logbuf[512] = "";
	jsrefcount rc;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	/* Get the destination user number */
	if (argn < argc && JSVAL_IS_NUMBER(argv[argn])) {
		if (!JS_ValueToInt32(cx, argv[argn], &usernumber))
		rc = JS_SUSPENDREQUEST(cx);
		usernumber = sbbs->getnodetopage(/* all: */ FALSE, /* telegram: */ TRUE);
		JS_RESUMEREQUEST(cx, rc);
	}

	/* Validate the destination user number */
	if (usernumber == 1 && sbbs->useron.rest & FLAG('S')) { /* ! val fback */
		sbbs->bprintf(sbbs->text[R_Feedback], sbbs->cfg.sys_op);
		return JS_TRUE;
	}
	if (usernumber > 1 && sbbs->useron.rest & FLAG('E')) {
		sbbs->bputs(sbbs->text[R_Email]);
		return JS_TRUE;
	/* Get the telegram message text */
	if (argn < argc) {
		if ((js_msg = JS_ValueToString(cx, argv[argn])) == NULL)
			return JS_FALSE;
		argn++;
		JSSTRING_TO_MSTRING(cx, js_msg, msg, NULL);
	} else {
		char buf[512];

		rc = JS_SUSPENDREQUEST(cx);
		sbbs->bprintf(sbbs->text[SendingTelegramToUser]
		              , username(&sbbs->cfg, usernumber, tmp), usernumber);
		SAFEPRINTF2(buf, sbbs->text[TelegramFmt]
		            , sbbs->thisnode.misc & NODE_ANON ? sbbs->text[UNKNOWN_USER] : sbbs->useron.alias
		            , sbbs->timestr(time(NULL)));
		int i = 0;
		while (sbbs->online && i < 5) {
			if (!sbbs->getstr(line, 70, i < 4 ? (K_WORDWRAP | K_MSG) : (K_MSG)))
			SAFEPRINTF2(str, "%4s%s\r\n", nulstr, line);
				SAFECAT(logbuf, " ");
			SAFECAT(logbuf, line);
			i++;
		}
		JS_RESUMEREQUEST(cx, rc);
		if (sbbs->sys_status & SS_ABORT) {
			sbbs->bputs(crlf);
			return JS_TRUE;
		}
		msg = strdup(buf);
	}
	rc = JS_SUSPENDREQUEST(cx);
	bool success = putsmsg(&sbbs->cfg, usernumber, msg) == 0;
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(success));
deuce's avatar
deuce committed
	free(msg);
	SAFEPRINTF3(str, "%s telegram to %s #%u"
	            , success ? "sent" : "FAILED to send", username(&sbbs->cfg, usernumber, tmp), usernumber);
	sbbs->logline("C", str);
	if (logbuf[0])
		sbbs->logline(nulstr, logbuf);
	if (success)
		sbbs->bprintf(sbbs->text[MsgSentToUser], "Telegram", username(&sbbs->cfg, usernumber, tmp), usernumber);
js_cmdstr(JSContext *cx, uintN argc, jsval *arglist)
	jsval *     argv = JS_ARGV(cx, arglist);
	char*       p = NULL;
	const char *def = "";
	char*       fpath = (char *)def;
	char*       fspec = (char *)def;
	JSString*   js_str;
	sbbs_t*     sbbs;
	jsrefcount  rc;
	if (js_argcIsInsufficient(cx, argc, 1))
		return JS_FALSE;

	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

	js_str = JS_ValueToString(cx, argv[0]);
	if (!js_str)
deuce's avatar
deuce committed
	JSSTRING_TO_MSTRING(cx, js_str, p, NULL);
	for (uintN i = 1; i < argc; i++) {
		if (JSVAL_IS_STRING(argv[i])) {
			js_str = JS_ValueToString(cx, argv[i]);
deuce's avatar
deuce committed
				JSSTRING_TO_MSTRING(cx, js_str, fpath, NULL);
				if (fpath == NULL) {
					if (fspec != def)
deuce's avatar
deuce committed
					return JS_FALSE;
			else if (fspec == def) {
deuce's avatar
deuce committed
				JSSTRING_TO_MSTRING(cx, js_str, fspec, NULL);
				if (fspec == NULL) {
					if (fpath != def)
deuce's avatar
deuce committed
					return JS_FALSE;
	rc = JS_SUSPENDREQUEST(cx);
	char* cmd = sbbs->cmdstr(p, fpath, fspec, NULL);
	free(p);
deuce's avatar
deuce committed
		free(fpath);
deuce's avatar
deuce committed
		free(fspec);
	if ((js_str = JS_NewStringCopyZ(cx, cmd)) == NULL)
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
js_getfilespec(JSContext *cx, uintN argc, jsval *arglist)
	char*      p;
	char       tmp[128];
	sbbs_t*    sbbs;
	jsrefcount rc;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	rc = JS_SUSPENDREQUEST(cx);
	p = sbbs->getfilespec(tmp);
	if (p == NULL)
		JS_SET_RVAL(cx, arglist, JSVAL_NULL);
	else {
		JSString* js_str = JS_NewStringCopyZ(cx, p);
		JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
static JSBool
js_export_filelist(JSContext *cx, uintN argc, jsval *arglist)
{
	jsval *    argv = JS_ARGV(cx, arglist);
	uint32     mode = 0;
	char*      fname = NULL;
	JSString*  js_str;
	sbbs_t*    sbbs;
	jsrefcount rc;

	if (js_argcIsInsufficient(cx, argc, 1))
		return JS_FALSE;

	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
		return JS_FALSE;

	uintN argn = 0;
	js_str = JS_ValueToString(cx, argv[argn]);
	JSSTRING_TO_MSTRING(cx, js_str, fname, NULL);
	HANDLE_PENDING(cx, fname);
	argn++;
	if (JSVAL_IS_NUMBER(argv[argn])) {
		if (!JS_ValueToECMAUint32(cx, argv[argn], &mode)) {
			free(fname);
			return JS_FALSE;
		}
		argn++;
	}
	rc = JS_SUSPENDREQUEST(cx);
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(sbbs->create_filelist(fname, mode)));
	free(fname);
	JS_RESUMEREQUEST(cx, rc);
	return JS_TRUE;
}

js_listfiles(JSContext *cx, uintN argc, jsval *arglist)
	jsval *     argv = JS_ARGV(cx, arglist);
	uint32      mode = 0;
	const char *def = ALLFILES;
	char*       afspec = NULL;
	char*       fspec = (char *)def;
	uint        dirnum;
	JSString*   js_str;
	sbbs_t*     sbbs;
	jsrefcount  rc;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	dirnum = get_dirnum(cx, sbbs, argv[0], argc == 0);
	if (!dirnum_is_valid(&sbbs->cfg, dirnum)) {
		JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(0));
	for (uintN i = 1; i < argc; i++) {
		if (JSVAL_IS_NUMBER(argv[i])) {
			if (!JS_ValueToECMAUint32(cx, argv[i], &mode)) {
				if (fspec != def)
		else if (JSVAL_IS_STRING(argv[i])) {
			js_str = JS_ValueToString(cx, argv[i]);
			JSSTRING_TO_MSTRING(cx, js_str, afspec, NULL);
deuce's avatar
deuce committed
				return JS_FALSE;
	rc = JS_SUSPENDREQUEST(cx);
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(sbbs->listfiles(dirnum, fspec, 0 /* tofile */, mode)));
	if (afspec)
js_listfileinfo(JSContext *cx, uintN argc, jsval *arglist)
	jsval *     argv = JS_ARGV(cx, arglist);
	uint32      mode = FI_INFO;
	const char *def = ALLFILES;
	char*       fspec = (char *)def;
	uint        dirnum;
	JSString*   js_str;
	sbbs_t*     sbbs;
	jsrefcount  rc;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	dirnum = get_dirnum(cx, sbbs, argv[0], argc == 0);
	if (!dirnum_is_valid(&sbbs->cfg, dirnum)) {
		JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(0));
	for (uintN i = 1; i < argc; i++) {
		if (JSVAL_IS_NUMBER(argv[i])) {
			if (!JS_ValueToECMAUint32(cx, argv[i], &mode)) {
				if (fspec != def)
					free(fspec);
		else if (JSVAL_IS_STRING(argv[i])) {
			js_str = JS_ValueToString(cx, argv[i]);
			if (fspec != def && fspec != NULL)
deuce's avatar
deuce committed
			JSSTRING_TO_MSTRING(cx, js_str, fspec, NULL);
deuce's avatar
deuce committed
				return JS_FALSE;
	rc = JS_SUSPENDREQUEST(cx);
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(sbbs->listfileinfo(dirnum, fspec, mode)));
deuce's avatar
deuce committed
		free(fspec);
js_post_msg(JSContext *cx, uintN argc, jsval *arglist)
	jsval *    argv = JS_ARGV(cx, arglist);
	uint32     mode = 0;
	uint       subnum;
	uintN      n;
	JSObject*  hdrobj;
	sbbs_t*    sbbs;
	smb_t*     resmb = NULL;
	smbmsg_t*  remsg = NULL;
	smbmsg_t   msg;
	jsrefcount rc;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)
	subnum = get_subnum(cx, sbbs, argv, argc, 0);
	if (!subnum_is_valid(&sbbs->cfg, subnum))
	for (n = 1; n < argc; n++) {
		if (JSVAL_IS_NUMBER(argv[n])) {
			if (!JS_ValueToECMAUint32(cx, argv[n], &mode))
		else if (JSVAL_IS_OBJECT(argv[n]) && !JSVAL_IS_NULL(argv[n])) {
			if ((hdrobj = JSVAL_TO_OBJECT(argv[n])) == NULL)
			if (!js_GetMsgHeaderObjectPrivates(cx, hdrobj, &resmb, &remsg, /* post: */ NULL)) {
				if (!js_ParseMsgHeaderObject(cx, hdrobj, &msg)) {
					JS_ReportError(cx, "msg hdr object cannot be parsed");
	rc = JS_SUSPENDREQUEST(cx);
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(sbbs->postmsg(subnum, mode, resmb, remsg)));
static JSBool
js_forward_msg(JSContext *cx, uintN argc, jsval *arglist)
{
	jsval *    argv = JS_ARGV(cx, arglist);
	uintN      n;
	JSObject*  hdrobj;
	sbbs_t*    sbbs;
	smb_t*     smb = NULL;
	smbmsg_t*  msg = NULL;
	char*      to = NULL;
	char*      subject = NULL;
	char*      comment = NULL;
	jsrefcount rc;
	if ((sbbs = js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist))) == NULL)

	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

	for (n = 0; n < argc; n++) {
		if (JSVAL_IS_OBJECT(argv[n]) && !JSVAL_IS_NULL(argv[n])) {
			if ((hdrobj = JSVAL_TO_OBJECT(argv[n])) == NULL) {
				free(to);
				free(subject);
				free(comment);
			if (!js_GetMsgHeaderObjectPrivates(cx, hdrobj, &smb, &msg, /* post_t */ NULL)) {
				JS_ReportError(cx, "msg hdr object lacks privates");
				free(to);
				free(subject);
				free(comment);
		} else if (JSVAL_IS_STRING(argv[n])) {
			JSString* str = JS_ValueToString(cx, argv[n]);
				JSSTRING_TO_MSTRING(cx, str, to, NULL);
			} else if (subject == NULL) {
				JSSTRING_TO_MSTRING(cx, str, subject, NULL);
			} else if (comment == NULL) {
				JSSTRING_TO_MSTRING(cx, str, comment, NULL);
			}
		}
	}
	if (smb != NULL && msg != NULL && to != NULL) {
		rc = JS_SUSPENDREQUEST(cx);
		JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(sbbs->forwardmsg(smb, msg, to, subject, comment)));
		JS_RESUMEREQUEST(cx, rc);
	}
	free(subject);
	free(comment);
	free(to);