Skip to content
Snippets Groups Projects
js_system.c 87.1 KiB
Newer Older
/* Synchronet JavaScript "system" Object */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
 *																			*
 * This program is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU General Public License				*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "sbbs.h"
#include "filedat.h"
} js_system_private_t;

extern JSClass js_system_class;

/* System Object Properties */
	SYS_PROP_NAME
	, SYS_PROP_OP
	, SYS_PROP_OP_AVAIL
	, SYS_PROP_GURU
	, SYS_PROP_ID
	, SYS_PROP_MISC
	, SYS_PROP_LOGIN
	, SYS_PROP_INETADDR
	, SYS_PROP_LOCATION
	, SYS_PROP_TIMEZONE
	, SYS_PROP_TZ_OFFSET
	, SYS_PROP_DATE_FMT
	, SYS_PROP_DATE_SEP
	, SYS_PROP_DATE_VERBAL
	, SYS_PROP_BIRTHDATE_FMT
	, SYS_PROP_BIRTHDATE_TEMPLATE
	, SYS_PROP_PWDAYS
	, SYS_PROP_MINPWLEN
	, SYS_PROP_MAXPWLEN
	, SYS_PROP_DELDAYS
	, SYS_PROP_AUTODEL

	, SYS_PROP_LASTUSER
	, SYS_PROP_LASTUSERON
	, SYS_PROP_FREEDISKSPACE
	, SYS_PROP_FREEDISKSPACEK

	, SYS_PROP_NODES
	, SYS_PROP_LASTNODE

	, SYS_PROP_MQTT_ENABLED

	, SYS_PROP_NEW_PASS
	, SYS_PROP_NEW_MAGIC
	, SYS_PROP_NEW_LEVEL
	, SYS_PROP_NEW_FLAGS1
	, SYS_PROP_NEW_FLAGS2
	, SYS_PROP_NEW_FLAGS3
	, SYS_PROP_NEW_FLAGS4
	, SYS_PROP_NEW_REST
	, SYS_PROP_NEW_EXEMPT
	, SYS_PROP_NEW_CDT
	, SYS_PROP_NEW_MIN
	, SYS_PROP_NEW_SHELL
	, SYS_PROP_NEW_XEDIT
	, SYS_PROP_NEW_MISC
	, SYS_PROP_NEW_PROT
	, SYS_PROP_NEW_EXPIRE
	, SYS_PROP_NEW_UQ

	, SYS_PROP_EXPIRED_LEVEL
	, SYS_PROP_EXPIRED_FLAGS1
	, SYS_PROP_EXPIRED_FLAGS2
	, SYS_PROP_EXPIRED_FLAGS3
	, SYS_PROP_EXPIRED_FLAGS4
	, SYS_PROP_EXPIRED_REST
	, SYS_PROP_EXPIRED_EXEMPT
	, SYS_PROP_NODE_DIR
	, SYS_PROP_CTRL_DIR
	, SYS_PROP_DATA_DIR
	, SYS_PROP_TEXT_DIR
	, SYS_PROP_TEMP_DIR
	, SYS_PROP_EXEC_DIR
	, SYS_PROP_MODS_DIR
	, SYS_PROP_LOGS_DIR
	/* clock/timer access */
	, SYS_PROP_CLOCK
	, SYS_PROP_CLOCK_PER_SEC
	, SYS_PROP_TIMER
	, SYS_PROP_DEVNULL
	, SYS_PROP_TEMP_PATH
	, SYS_PROP_CMD_SHELL
	, SYS_PROP_LOCAL_HOSTNAME
Deucе's avatar
Deucе committed
	/* last */
	, SYS_PROP_NAME_SERVERS
static JSBool js_system_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
	jsval                idval;
	char                 str[128];
	char*                p = NULL;
	jsint                tiny;
	JSString*            js_str;
	uint64_t             space;
	jsrefcount           rc;
	JSObject *           robj;
	jsval                jval;
	str_list_t           list;
	int                  i;
	if ((sys = (js_system_private_t*)js_GetClassPrivate(cx, obj, &js_system_class)) == NULL)
	scfg_t*              cfg = sys->cfg;
	JS_IdToValue(cx, id, &idval);
	tiny = JSVAL_TO_INT(idval);
		case SYS_PROP_NAME:
			break;
		case SYS_PROP_OP:
			*vp = BOOLEAN_TO_JSVAL(sysop_available(cfg));
		case SYS_PROP_GURU:
			p = cfg->sys_guru;
			break;
		case SYS_PROP_ID:
			break;
		case SYS_PROP_MISC:
			*vp = UINT_TO_JSVAL(cfg->sys_misc);
			*vp = UINT_TO_JSVAL(cfg->sys_login);
		case SYS_PROP_INETADDR:
			p = cfg->sys_inetaddr;
			break;
		case SYS_PROP_LOCATION:
			p = cfg->sys_location;
			break;
		case SYS_PROP_TIMEZONE:
			*vp = INT_TO_JSVAL(sys_timezone(cfg));
			*vp = INT_TO_JSVAL(smb_tzutc(sys_timezone(cfg)));
		case SYS_PROP_DATE_FMT:
			*vp = INT_TO_JSVAL(cfg->sys_date_fmt);
			break;
		case SYS_PROP_DATE_SEP:
			snprintf(str, sizeof str, "%c", cfg->sys_date_sep);
			p = str;
			break;
		case SYS_PROP_DATE_VERBAL:
			*vp = BOOLEAN_TO_JSVAL(cfg->sys_date_verbal);
			break;
		case SYS_PROP_BIRTHDATE_FMT:
			birthdate_format(cfg, str, sizeof str);
			p = str;
			break;
		case SYS_PROP_BIRTHDATE_TEMPLATE:
			birthdate_template(cfg, str, sizeof str);
			p = str;
			break;
		case SYS_PROP_NODES:
			*vp = INT_TO_JSVAL(cfg->sys_nodes);
			break;
		case SYS_PROP_LASTNODE:
			*vp = INT_TO_JSVAL(cfg->sys_lastnode);
			break;
		case SYS_PROP_MQTT_ENABLED:
			*vp = BOOLEAN_TO_JSVAL(cfg->mqtt.enabled);
			break;
		case SYS_PROP_PWDAYS:
			*vp = INT_TO_JSVAL(cfg->sys_pwdays);
			break;
rswindell's avatar
rswindell committed
		case SYS_PROP_MINPWLEN:
			*vp = INT_TO_JSVAL(cfg->min_pwlen);
rswindell's avatar
rswindell committed
			break;
		case SYS_PROP_MAXPWLEN:
			*vp = INT_TO_JSVAL(LEN_PASS);
			break;
		case SYS_PROP_DELDAYS:
			*vp = INT_TO_JSVAL(cfg->sys_deldays);
			break;
		case SYS_PROP_AUTODEL:
			*vp = INT_TO_JSVAL(cfg->sys_autodel);
			break;
		case SYS_PROP_LASTUSER:
			*vp = INT_TO_JSVAL(lastuser(cfg));
			break;
		case SYS_PROP_LASTUSERON:
		case SYS_PROP_FREEDISKSPACE:
			rc = JS_SUSPENDREQUEST(cx);
			if (tiny == SYS_PROP_FREEDISKSPACE)
				space = getfreediskspace(cfg->temp_dir, 0);
				space = getfreediskspace(cfg->temp_dir, 1024);
			*vp = DOUBLE_TO_JSVAL((double)space);
		case SYS_PROP_NEW_PASS:
			break;
		case SYS_PROP_NEW_MAGIC:
			p = cfg->new_magic;
			break;
		case SYS_PROP_NEW_LEVEL:
			*vp = INT_TO_JSVAL(cfg->new_level);
			break;
		case SYS_PROP_NEW_FLAGS1:
			*vp = INT_TO_JSVAL(cfg->new_flags1);
			break;
		case SYS_PROP_NEW_FLAGS2:
			*vp = INT_TO_JSVAL(cfg->new_flags2);
			break;
		case SYS_PROP_NEW_FLAGS3:
			*vp = INT_TO_JSVAL(cfg->new_flags3);
			break;
		case SYS_PROP_NEW_FLAGS4:
			*vp = INT_TO_JSVAL(cfg->new_flags4);
			break;
		case SYS_PROP_NEW_REST:
			*vp = INT_TO_JSVAL(cfg->new_rest);
			break;
		case SYS_PROP_NEW_EXEMPT:
			*vp = INT_TO_JSVAL(cfg->new_exempt);
			break;
		case SYS_PROP_NEW_CDT:
			*vp = UINT_TO_JSVAL(cfg->new_cdt);
			break;
		case SYS_PROP_NEW_MIN:
			*vp = UINT_TO_JSVAL(cfg->new_min);
			break;
		case SYS_PROP_NEW_SHELL:
			if (cfg->new_shell < cfg->total_shells)
				p = cfg->shell[cfg->new_shell]->code;
			break;
		case SYS_PROP_NEW_XEDIT:
			p = cfg->new_xedit;
			break;
		case SYS_PROP_NEW_MISC:
			*vp = UINT_TO_JSVAL(cfg->new_misc);
			break;
		case SYS_PROP_NEW_PROT:
			sprintf(str, "%c", cfg->new_prot);
			p = str;
			break;
		case SYS_PROP_NEW_EXPIRE:
			*vp = UINT_TO_JSVAL(cfg->new_expire);
			break;
		case SYS_PROP_NEW_UQ:
			*vp = UINT_TO_JSVAL(cfg->uq);
			break;

		case SYS_PROP_EXPIRED_LEVEL:
			*vp = INT_TO_JSVAL(cfg->expired_level);
			break;
		case SYS_PROP_EXPIRED_FLAGS1:
			*vp = INT_TO_JSVAL(cfg->expired_flags1);
			break;
		case SYS_PROP_EXPIRED_FLAGS2:
			*vp = INT_TO_JSVAL(cfg->expired_flags2);
			break;
		case SYS_PROP_EXPIRED_FLAGS3:
			*vp = INT_TO_JSVAL(cfg->expired_flags3);
			break;
		case SYS_PROP_EXPIRED_FLAGS4:
			*vp = INT_TO_JSVAL(cfg->expired_flags4);
			break;
		case SYS_PROP_EXPIRED_REST:
			*vp = INT_TO_JSVAL(cfg->expired_rest);
			break;
		case SYS_PROP_EXPIRED_EXEMPT:
			*vp = INT_TO_JSVAL(cfg->expired_exempt);
			break;
		case SYS_PROP_MODS_DIR:
			break;
		case SYS_PROP_LOGS_DIR:
rswindell's avatar
rswindell committed
		case SYS_PROP_CMD_SHELL:
			rc = JS_SUSPENDREQUEST(cx);
			p = os_cmdshell();
			*vp = DOUBLE_TO_JSVAL((double)xp_timer64());
			*vp = UINT_TO_JSVAL(1000);
		case SYS_PROP_TIMER:
			*vp = DOUBLE_TO_JSVAL(xp_timer());
			rc = JS_SUSPENDREQUEST(cx);
			gethostname(str, sizeof(str));
Deucе's avatar
Deucе committed
		case SYS_PROP_NAME_SERVERS:
			rc = JS_SUSPENDREQUEST(cx);
Deucе's avatar
Deucе committed
			robj = JS_NewArrayObject(cx, 0, NULL);
			if (robj == NULL)
				return JS_FALSE;
			*vp = OBJECT_TO_JSVAL(robj);
			list = getNameServerList();
			if (list != NULL) {
				for (i = 0; list[i]; i++) {
					jval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, list[i]));
					if (!JS_SetElement(cx, robj, i, &jval))
						break;
				}
			}
			freeNameServerList(list);
			JS_RESUMEREQUEST(cx, rc);
			break;
	if (p != NULL) {   /* string property */
		if ((js_str = JS_NewStringCopyZ(cx, p)) == NULL)
		*vp = STRING_TO_JSVAL(js_str);
	}

static JSBool js_system_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
	if ((sys = (js_system_private_t*)js_GetClassPrivate(cx, obj, &js_system_class)) == NULL)
Deucе's avatar
Deucе committed
#ifndef JSDOOR
	jsval                idval;
	jsint                tiny;

	JS_IdToValue(cx, id, &idval);
	tiny = JSVAL_TO_INT(idval);
		case SYS_PROP_MISC:
			JS_ValueToECMAUint32(cx, *vp, (uint32_t*)&sys->cfg->sys_misc);
		case SYS_PROP_LOGIN:
			JS_ValueToECMAUint32(cx, *vp, (uint32_t*)&sys->cfg->sys_login);
			break;
			if (!set_sysop_availability(sys->cfg, JSVAL_TO_BOOLEAN(*vp))) {
				JS_ReportError(cx, "%s: Failed to set sysop availability", __FUNCTION__);
				return JS_FALSE;
			}
			break;
#define SYSOBJ_FLAGS JSPROP_ENUMERATE | JSPROP_READONLY
static jsSyncPropertySpec js_system_properties[] = {
/*		 name,						tinyid,				flags,				ver	*/

	{   "name",                     SYS_PROP_NAME,      SYSOBJ_FLAGS,       310
		, JSDOCSTR("BBS name")},
	{   "operator",                 SYS_PROP_OP,        SYSOBJ_FLAGS,       310
		, JSDOCSTR("Operator name")},
	{   "operator_available",       SYS_PROP_OP_AVAIL,  JSPROP_ENUMERATE,   31801
		, JSDOCSTR("Operator is available for chat")},
	{   "guru",                     SYS_PROP_GURU,      SYSOBJ_FLAGS,       32000
		, JSDOCSTR("Default Guru (AI) name")},
	{   "qwk_id",                   SYS_PROP_ID,        SYSOBJ_FLAGS,       310
		, JSDOCSTR("System QWK-ID (for QWK packets)")},
	{   "settings",                 SYS_PROP_MISC,      JSPROP_ENUMERATE,   310
		, JSDOCSTR("Settings bit-flags (see <tt>SYS_*</tt> in <tt>sbbsdefs.js</tt> for bit definitions)")},
	{   "login_settings",           SYS_PROP_LOGIN,     JSPROP_ENUMERATE,   32000
		, JSDOCSTR("Login control settings bit-flags (see <tt>LOGIN_*</tt> in <tt>sbbsdefs.js</tt> for bit definitions)")},
	{   "inetaddr",                 SYS_PROP_INETADDR,  JSPROP_READONLY,    310  }, /* alias */
	{   "inet_addr",                SYS_PROP_INETADDR,  SYSOBJ_FLAGS,       311
		, JSDOCSTR("Internet address (host or domain name)")},
	{   "location",                 SYS_PROP_LOCATION,  SYSOBJ_FLAGS,       310
		, JSDOCSTR("Location (city, state)")},
	{   "timezone",                 SYS_PROP_TIMEZONE,  SYSOBJ_FLAGS,       310
		, JSDOCSTR("Local timezone in SMB format (use <i>system.zonestr()</i> to get string representation)")},
	{   "tz_offset",                SYS_PROP_TZ_OFFSET, SYSOBJ_FLAGS,       320
		, JSDOCSTR("Local timezone offset, in minutes, from UTC (negative values represent zones <i>west</i> of UTC, positive values represent zones <i>east</i> of UTC)")},
	{   "date_format",              SYS_PROP_DATE_FMT,  SYSOBJ_FLAGS,       32002
		, JSDOCSTR("Date representation (0=Month first, 1=Day first, 2=Year first")},
	{   "date_separator",           SYS_PROP_DATE_SEP,  SYSOBJ_FLAGS,       32002
		, JSDOCSTR("Short (8 character) date field-separator")},
	{   "date_verbal",              SYS_PROP_DATE_VERBAL, SYSOBJ_FLAGS,     32002
		, JSDOCSTR("Short date month-name displayed verbally instead of numerically")},
	{   "birthdate_format",         SYS_PROP_BIRTHDATE_FMT, SYSOBJ_FLAGS,   32002
		, JSDOCSTR("User birth date input and display format (MM=Month number, DD=Day of month, YYYY=Year)")},
	{   "birthdate_template",       SYS_PROP_BIRTHDATE_TEMPLATE, SYSOBJ_FLAGS, 32002
		, JSDOCSTR("User birth date input template")},
	{   "pwdays",                   SYS_PROP_PWDAYS,    SYSOBJ_FLAGS,       310
		, JSDOCSTR("Days between forced user password changes (<tt>0</tt>=<i>never</i>)")},
	{   "min_password_length",      SYS_PROP_MINPWLEN,  SYSOBJ_FLAGS,       31702
		, JSDOCSTR("Minimum number of characters in user passwords")},
	{   "max_password_length",      SYS_PROP_MAXPWLEN,  SYSOBJ_FLAGS,       31702
		, JSDOCSTR("Maximum number of characters in user passwords")},
	{   "deldays",                  SYS_PROP_DELDAYS,   SYSOBJ_FLAGS,       310
		, JSDOCSTR("Days to preserve deleted user records, record will not be reused/overwritten during this period")},
	{   "autodel",                  SYS_PROP_AUTODEL,   SYSOBJ_FLAGS,       31702
		, JSDOCSTR("Days of user inactivity before auto-deletion (<tt>0</tt>=<i>disabled</i>), N/A to P-exempt users")},

	{   "last_user",                SYS_PROP_LASTUSER, SYSOBJ_FLAGS,  311
		, JSDOCSTR("Last user record number in user database (includes deleted and inactive user records)")},
	{   "lastuser",                 SYS_PROP_LASTUSER, JSPROP_READONLY,   311  },   /* alias */
	{   "last_useron",              SYS_PROP_LASTUSERON, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Name of last user to logoff")},
	{   "lastuseron",               SYS_PROP_LASTUSERON, JSPROP_READONLY,   310  }, /* alias */
	{   "freediskspace",            SYS_PROP_FREEDISKSPACE, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Amount of free disk space (in bytes)")},
	{   "freediskspacek",           SYS_PROP_FREEDISKSPACEK, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Amount of free disk space (in kibibytes)")},
	{   "nodes",                    SYS_PROP_NODES,     SYSOBJ_FLAGS,       310
		, JSDOCSTR("Total number of Terminal Server nodes")},
	{   "last_node",                SYS_PROP_LASTNODE,  SYSOBJ_FLAGS,       310
		, JSDOCSTR("Last displayable node number")},
	{   "lastnode",                 SYS_PROP_LASTNODE,  JSPROP_READONLY,    310  }, /* alias */

	{   "mqtt_enabled",             SYS_PROP_MQTT_ENABLED,  SYSOBJ_FLAGS,   320
		, JSDOCSTR("MQTT support (connection to MQTT broker) is enabled")},

	{   "newuser_password",         SYS_PROP_NEW_PASS, SYSOBJ_FLAGS,  310
		, JSDOCSTR("New user password (NUP, optional)")},
	{   "newuser_magic_word",       SYS_PROP_NEW_MAGIC, SYSOBJ_FLAGS,  310
		, JSDOCSTR("New user magic word (optional)")},
	{   "newuser_level",            SYS_PROP_NEW_LEVEL, SYSOBJ_FLAGS,  310
		, JSDOCSTR("New user security level")},
	{   "newuser_flags1",           SYS_PROP_NEW_FLAGS1, SYSOBJ_FLAGS,  310
		, JSDOCSTR("New user flag set #1")},
	{   "newuser_flags2",           SYS_PROP_NEW_FLAGS2, SYSOBJ_FLAGS,  310
		, JSDOCSTR("New user flag set #2")},
	{   "newuser_flags3",           SYS_PROP_NEW_FLAGS3, SYSOBJ_FLAGS,  310
		, JSDOCSTR("New user flag set #3")},
	{   "newuser_flags4",           SYS_PROP_NEW_FLAGS4, SYSOBJ_FLAGS,  310
		, JSDOCSTR("New user flag set #4")},
	{   "newuser_restrictions",     SYS_PROP_NEW_REST, SYSOBJ_FLAGS,  310
		, JSDOCSTR("New user restriction flags")},
	{   "newuser_exemptions",       SYS_PROP_NEW_EXEMPT, SYSOBJ_FLAGS,  310
		, JSDOCSTR("New user exemption flags")},
	{   "newuser_credits",          SYS_PROP_NEW_CDT, SYSOBJ_FLAGS,  310
		, JSDOCSTR("New user credits")},
	{   "newuser_minutes",          SYS_PROP_NEW_MIN, SYSOBJ_FLAGS,  310
		, JSDOCSTR("New user extra minutes")},
	{   "newuser_command_shell",    SYS_PROP_NEW_SHELL, SYSOBJ_FLAGS,  310
		, JSDOCSTR("New user default command shell")},
	{   "newuser_editor",           SYS_PROP_NEW_XEDIT, SYSOBJ_FLAGS,  310
		, JSDOCSTR("New user default external editor")},
	{   "newuser_settings",         SYS_PROP_NEW_MISC, SYSOBJ_FLAGS,  310
		, JSDOCSTR("New user default settings")},
	{   "newuser_download_protocol", SYS_PROP_NEW_PROT, SYSOBJ_FLAGS,  310
		, JSDOCSTR("New user default file transfer protocol (command key)")},
	{   "newuser_expiration_days",  SYS_PROP_NEW_EXPIRE, SYSOBJ_FLAGS,  310
		, JSDOCSTR("New user expiration days")},
	{   "newuser_questions",        SYS_PROP_NEW_UQ, SYSOBJ_FLAGS,  310
		, JSDOCSTR("New user questions/prompts (see <tt>UQ_*</tt> in <tt>sbbsdefs.js</tt> for bit definitions)")},

	{   "expired_level",            SYS_PROP_EXPIRED_LEVEL, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Expired user security level")},
	{   "expired_flags1",           SYS_PROP_EXPIRED_FLAGS1, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Expired user flag set #1")},
	{   "expired_flags2",           SYS_PROP_EXPIRED_FLAGS2, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Expired user flag set #2")},
	{   "expired_flags3",           SYS_PROP_EXPIRED_FLAGS3, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Expired user flag set #3")},
	{   "expired_flags4",           SYS_PROP_EXPIRED_FLAGS4, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Expired user flag set #4")},
	{   "expired_restrictions",     SYS_PROP_EXPIRED_REST, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Expired user restriction flags")},
	{   "expired_exemptions",       SYS_PROP_EXPIRED_EXEMPT, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Expired user exemption flags")},
	{   "node_dir",                 SYS_PROP_NODE_DIR, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Current node directory")},
	{   "ctrl_dir",                 SYS_PROP_CTRL_DIR, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Control file directory")},
	{   "data_dir",                 SYS_PROP_DATA_DIR, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Data file directory")},
	{   "text_dir",                 SYS_PROP_TEXT_DIR, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Text file directory")},
	{   "temp_dir",                 SYS_PROP_TEMP_DIR, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Temporary file directory")},
	{   "exec_dir",                 SYS_PROP_EXEC_DIR, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Executable file directory")},
	{   "mods_dir",                 SYS_PROP_MODS_DIR, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Modified modules directory (optional)")},
	{   "logs_dir",                 SYS_PROP_LOGS_DIR, SYSOBJ_FLAGS,  310
		, JSDOCSTR("Log file directory")},
	{   "devnull",                  SYS_PROP_DEVNULL, SYSOBJ_FLAGS,  311
		, JSDOCSTR("Platform-specific \"null\" device filename")},
	{   "temp_path",                SYS_PROP_TEMP_PATH, SYSOBJ_FLAGS,  312
		, JSDOCSTR("Platform-specific temporary file directory")},
	{   "cmd_shell",                SYS_PROP_CMD_SHELL, SYSOBJ_FLAGS,  314
		, JSDOCSTR("Platform-specific command processor/shell")},
	{   "clock_ticks",              SYS_PROP_CLOCK, SYSOBJ_FLAGS,  311
		, JSDOCSTR("Amount of elapsed time in clock 'ticks'")},
	{   "clock_ticks_per_second",   SYS_PROP_CLOCK_PER_SEC, SYSOBJ_FLAGS,  311
		, JSDOCSTR("Number of clock ticks per second")},
	{   "timer",                    SYS_PROP_TIMER, SYSOBJ_FLAGS,  314
		, JSDOCSTR("High-resolution timer, in seconds (fractional seconds supported)")},

	{   "local_host_name",          SYS_PROP_LOCAL_HOSTNAME, SYSOBJ_FLAGS,  311
		, JSDOCSTR("Private host name that uniquely identifies this system on the local network")},
	{   "name_servers",             SYS_PROP_NAME_SERVERS, SYSOBJ_FLAGS,  31802
		, JSDOCSTR("Array of nameservers in use by the system")},
Deucе's avatar
Deucе committed
	/* last */
static const char* sys_prop_desc[] = {
	/* Manually created (non-tabled) properties */
	"Public host name that uniquely identifies this system on the Internet (usually the same as <i>system.inet_addr</i>)"
	, "Socket library version information"
	, "Time/date system was brought online (in time_t format)"
	, "Synchronet full version information (e.g. '3.10k Beta Debug')"
	, "Date and time compiled"
	, "Synchronet version number (e.g. '3.10')"
	, "Synchronet revision letter (e.g. 'k')"
	, "Synchronet alpha/beta designation (e.g. ' beta')"
	, "Synchronet version notice (includes version and platform)"
	, "Synchronet version number in decimal (e.g. 31301 for v3.13b)"
	, "Synchronet version number in hexadecimal (e.g. 0x31301 for v3.13b)"
	, "Synchronet Git repository branch name"
	, "Synchronet Git repository commit hash"
	, "Synchronet Git repository commit date/time"
	, "Synchronet Git repository commit date/time (seconds since Unix epoch)"
	, "Platform description (e.g. 'Win32', 'Linux', 'FreeBSD')"
	, "Architecture description (e.g. 'i386', 'i686', 'x86_64')"
	, "Message base library version information"
	, "Compiler used to build Synchronet"
	, "Synchronet copyright display"
	, "JavaScript engine version information"
	, "Operating system version information"
	, "Array of FidoNet Technology Network (FTN) addresses associated with this system"
	, NULL
/* System Stats Propertiess */
enum {
	SYSSTAT_PROP_LOGONS
	, SYSSTAT_PROP_LTODAY
	, SYSSTAT_PROP_TIMEON
	, SYSSTAT_PROP_TTODAY
	, SYSSTAT_PROP_ULS
	, SYSSTAT_PROP_ULB
	, SYSSTAT_PROP_DLS
	, SYSSTAT_PROP_DLB
	, SYSSTAT_PROP_PTODAY
	, SYSSTAT_PROP_ETODAY
	, SYSSTAT_PROP_FTODAY
	, SYSSTAT_PROP_NUSERS

	, SYSSTAT_PROP_TOTALUSERS
	, SYSSTAT_PROP_TOTALFILES
	, SYSSTAT_PROP_TOTALMSGS
	, SYSSTAT_PROP_TOTALMAIL
	, SYSSTAT_PROP_FEEDBACK

	, SYSSTAT_PROP_NODE_GETS
static JSBool js_sysstats_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
	jsval                idval;
	jsint                tiny;
	stats_t              stats;
	int                  i;
	ulong                l;
	jsrefcount           rc;
	if ((sys = (js_system_private_t*)JS_GetPrivate(cx, obj)) == NULL) {
		JS_ReportError(cx, "JS_GetPrivate failure in %s", __FUNCTION__);
	JS_IdToValue(cx, id, &idval);
	tiny = JSVAL_TO_INT(idval);
	if (tiny < SYSSTAT_PROP_TOTALUSERS) {
		rc = JS_SUSPENDREQUEST(cx);
		if (!getstats(cfg, 0, &stats)) {
			JS_RESUMEREQUEST(cx, rc);
			JS_ReportError(cx, "getstats failure in %s", __FUNCTION__);
			return JS_FALSE;
		}
		case SYSSTAT_PROP_LOGONS:
			*vp = UINT_TO_JSVAL(stats.logons);
			break;
		case SYSSTAT_PROP_LTODAY:
			*vp = UINT_TO_JSVAL(stats.ltoday);
			break;
		case SYSSTAT_PROP_TIMEON:
			*vp = UINT_TO_JSVAL(stats.timeon);
			break;
		case SYSSTAT_PROP_TTODAY:
			*vp = UINT_TO_JSVAL(stats.ttoday);
			break;
		case SYSSTAT_PROP_ULS:
			*vp = UINT_TO_JSVAL(stats.uls);
			break;
		case SYSSTAT_PROP_ULB:
			*vp = DOUBLE_TO_JSVAL((double)stats.ulb);
			break;
		case SYSSTAT_PROP_DLS:
			*vp = UINT_TO_JSVAL(stats.dls);
			break;
		case SYSSTAT_PROP_DLB:
			*vp = DOUBLE_TO_JSVAL((double)stats.dlb);
			break;
		case SYSSTAT_PROP_PTODAY:
			*vp = UINT_TO_JSVAL(stats.ptoday);
			break;
		case SYSSTAT_PROP_ETODAY:
			*vp = UINT_TO_JSVAL(stats.etoday);
			break;
		case SYSSTAT_PROP_FTODAY:
			*vp = UINT_TO_JSVAL(stats.ftoday);
			break;
		case SYSSTAT_PROP_NUSERS:
			*vp = UINT_TO_JSVAL(stats.nusers);
			break;

		case SYSSTAT_PROP_TOTALUSERS:
			rc = JS_SUSPENDREQUEST(cx);
			*vp = INT_TO_JSVAL(total_users(cfg));
			break;
		case SYSSTAT_PROP_TOTALMSGS:
			l = 0;
			rc = JS_SUSPENDREQUEST(cx);
			for (i = 0; i < cfg->total_subs; i++)
				l += getposts(cfg, i);
			*vp = DOUBLE_TO_JSVAL((double)l);
			break;
		case SYSSTAT_PROP_TOTALFILES:
			l = 0;
			rc = JS_SUSPENDREQUEST(cx);
			for (i = 0; i < cfg->total_dirs; i++)
				l += getfiles(cfg, i);
			*vp = DOUBLE_TO_JSVAL((double)l);
			break;
		case SYSSTAT_PROP_TOTALMAIL:
			rc = JS_SUSPENDREQUEST(cx);
			*vp = INT_TO_JSVAL(getmail(cfg, /* user: */ 0, /* Sent: */ FALSE, /* SPAM: */ FALSE));
			break;
		case SYSSTAT_PROP_FEEDBACK:
			rc = JS_SUSPENDREQUEST(cx);
			*vp = INT_TO_JSVAL(getmail(cfg, /* user: */ 1, /* Sent: */ FALSE, /* SPAM: */ FALSE));

		case SYSSTAT_PROP_NODE_GETS:
			*vp = INT_TO_JSVAL(sys->nodegets);
			break;
#define SYSSTAT_FLAGS JSPROP_ENUMERATE | JSPROP_READONLY
static jsSyncPropertySpec js_sysstats_properties[] = {
/*		 name,						tinyid,						flags,			ver	*/

	{   "total_logons",             SYSSTAT_PROP_LOGONS,        SYSSTAT_FLAGS,  310 },
	{   "logons_today",             SYSSTAT_PROP_LTODAY,        SYSSTAT_FLAGS,  310 },
	{   "total_timeon",             SYSSTAT_PROP_TIMEON,        SYSSTAT_FLAGS,  310 },
	{   "timeon_today",             SYSSTAT_PROP_TTODAY,        SYSSTAT_FLAGS,  310 },
	{   "total_files",              SYSSTAT_PROP_TOTALFILES,    SYSSTAT_FLAGS,  310 },
	{   "files_uploaded_today",     SYSSTAT_PROP_ULS,           SYSSTAT_FLAGS,  310 },
	{   "bytes_uploaded_today",     SYSSTAT_PROP_ULB,           SYSSTAT_FLAGS,  310 },
	{   "files_downloaded_today",   SYSSTAT_PROP_DLS,           SYSSTAT_FLAGS,  310 },
	{   "bytes_downloaded_today",   SYSSTAT_PROP_DLB,           SYSSTAT_FLAGS,  310 },
	{   "total_messages",           SYSSTAT_PROP_TOTALMSGS,     SYSSTAT_FLAGS,  310 },
	{   "messages_posted_today",    SYSSTAT_PROP_PTODAY,        SYSSTAT_FLAGS,  310 },
	{   "total_email",              SYSSTAT_PROP_TOTALMAIL,     SYSSTAT_FLAGS,  310 },
	{   "email_sent_today",         SYSSTAT_PROP_ETODAY,        SYSSTAT_FLAGS,  310 },
	{   "total_feedback",           SYSSTAT_PROP_FEEDBACK,      SYSSTAT_FLAGS,  310 },
	{   "feedback_sent_today",      SYSSTAT_PROP_FTODAY,        SYSSTAT_FLAGS,  310 },
	{   "total_users",              SYSSTAT_PROP_TOTALUSERS,    SYSSTAT_FLAGS,  310 },
	{   "new_users_today",          SYSSTAT_PROP_NUSERS,        SYSSTAT_FLAGS,  310 },
	{   "node_gets",                SYSSTAT_PROP_NODE_GETS,     JSPROP_READONLY, 31702 },
#if !defined(JSDOOR) && defined(BUILD_JSDOCS)
static const char* sysstat_prop_desc[] = {
	"Total logons"
	, "Logons today"
	, "Total time used"
	, "Time used today"
	, "Total files in file bases"
	, "Files uploaded today"
	, "Bytes uploaded today"
	, "Files downloaded today"
	, "Bytes downloaded today"
	, "Total messages in message bases"
	, "Messages posted today"
	, "Total messages in mail base"
	, "Email sent today"
	, "Total feedback messages waiting"
	, "Feedback sent today"
	, "Total user records (does not include deleted or inactive user records)"
	, "New users today"
	, NULL
static JSBool js_sysstats_resolve(JSContext *cx, JSObject *obj, jsid id)
	char*  name = NULL;
	JSBool ret;
	if (id != JSID_VOID && id != JSID_EMPTY) {
deuce's avatar
deuce committed
		jsval idval;
deuce's avatar
deuce committed
		JS_IdToValue(cx, id, &idval);
		if (JSVAL_IS_STRING(idval)) {
deuce's avatar
deuce committed
			JSSTRING_TO_MSTRING(cx, JSVAL_TO_STRING(idval), name, NULL);
			HANDLE_PENDING(cx, name);
deuce's avatar
deuce committed
	}
	ret = js_SyncResolve(cx, obj, name, js_sysstats_properties, NULL, NULL, 0);
	if (name)
deuce's avatar
deuce committed
		free(name);
	return ret;
deuce's avatar
deuce committed
}

static JSBool js_sysstats_enumerate(JSContext *cx, JSObject *obj)
{
	return js_sysstats_resolve(cx, obj, JSID_VOID);
static JSClass js_sysstats_class = {
	"Stats"                 /* name			*/
	, JSCLASS_HAS_PRIVATE    /* flags		*/
	, JS_PropertyStub        /* addProperty	*/
	, JS_PropertyStub        /* delProperty	*/
	, js_sysstats_get        /* getProperty	*/
	, JS_StrictPropertyStub  /* setProperty	*/
	, js_sysstats_enumerate  /* enumerate	*/
	, js_sysstats_resolve    /* resolve		*/
	, JS_ConvertStub         /* convert		*/
	, JS_FinalizeStub        /* finalize		*/
js_alias(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *           obj = JS_THIS_OBJECT(cx, arglist);
	jsval *              argv = JS_ARGV(cx, arglist);
	char*                p;
	char                 buf[128];
	JSString*            js_str;
	jsrefcount           rc;
	if (js_argcIsInsufficient(cx, argc, 1))
		return JS_FALSE;
	if (js_argvIsNullOrVoid(cx, argv, 0))
		return JS_FALSE;
	if ((sys = (js_system_private_t*)js_GetClassPrivate(cx, obj, &js_system_class)) == NULL)
	if ((js_str = JS_ValueToString(cx, argv[0])) == NULL) {
		JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(0));
deuce's avatar
deuce committed
	JSSTRING_TO_ASTRING(cx, js_str, p, 128, NULL);
		JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(0));
	rc = JS_SUSPENDREQUEST(cx);
	p = alias(sys->cfg, p, buf);
	if ((js_str = JS_NewStringCopyZ(cx, p)) == NULL)
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
js_username(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *           obj = JS_THIS_OBJECT(cx, arglist);
	jsval *              argv = JS_ARGV(cx, arglist);
	int32                val;
	char                 buf[128];
	JSString*            js_str;
	char*                cstr;
	jsrefcount           rc;
	if (js_argcIsInsufficient(cx, argc, 1))
		return JS_FALSE;
	if (JSVAL_NULL_OR_VOID(argv[0])) {
		JS_SET_RVAL(cx, arglist, JS_GetEmptyStringValue(cx));
		return JS_TRUE;
	}
	if ((sys = (js_system_private_t*)js_GetClassPrivate(cx, obj, &js_system_class)) == NULL)
	val = 0;
	JS_ValueToInt32(cx, argv[0], &val);
	rc = JS_SUSPENDREQUEST(cx);
	cstr = username(sys->cfg, val, buf);
	if ((js_str = JS_NewStringCopyZ(cx, cstr)) == NULL)
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
static JSBool
js_matchuser(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *           obj = JS_THIS_OBJECT(cx, arglist);
	jsval *              argv = JS_ARGV(cx, arglist);
	char*                p;
	JSString*            js_str;
	BOOL                 sysop_alias = TRUE;
	jsrefcount           rc;
	if (js_argcIsInsufficient(cx, argc, 1))
		return JS_FALSE;
	if (JSVAL_NULL_OR_VOID(argv[0])) {
		JS_SET_RVAL(cx, arglist, JSVAL_ZERO);
		return JS_TRUE;
	}
	if ((sys = (js_system_private_t*)js_GetClassPrivate(cx, obj, &js_system_class)) == NULL)
	if ((js_str = JS_ValueToString(cx, argv[0])) == NULL)
		return JS_FALSE;
	if (argc > 1)
		JS_ValueToBoolean(cx, argv[1], &sysop_alias);
	JSSTRING_TO_ASTRING(cx, js_str, p, (LEN_ALIAS > LEN_NAME) ? LEN_ALIAS + 2:LEN_NAME + 2, NULL);
	if (p == NULL)
		return JS_FALSE;
	rc = JS_SUSPENDREQUEST(cx);
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(matchuser(sys->cfg, p, sysop_alias)));
js_matchuserdata(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *           obj = JS_THIS_OBJECT(cx, arglist);
	jsval *              argv = JS_ARGV(cx, arglist);
	char*                p;
	JSString*            js_str;
	int32                field = 0;
	int32                usernumber = 0;
	int                  len;
	jsrefcount           rc;
	BOOL                 match_del = FALSE;
	BOOL                 match_next = FALSE;
Rob Swindell's avatar
Rob Swindell committed
	uintN                argnum = 2;
	if (js_argcIsInsufficient(cx, argc, 2))
		return JS_FALSE;
	if (js_argvIsNullOrVoid(cx, argv, 0))
		return JS_FALSE;
	if (JSVAL_NULL_OR_VOID(argv[1])) {
		JS_SET_RVAL(cx, arglist, JSVAL_ZERO);
		return JS_TRUE;
	}
	if ((sys = (js_system_private_t*)js_GetClassPrivate(cx, obj, &js_system_class)) == NULL)
	JS_ValueToInt32(cx, argv[0], &field);
	rc = JS_SUSPENDREQUEST(cx);
	len = user_field_len(field);
	if (len < 1) {
		JS_ReportError(cx, "Invalid user field: %d", field);
	if ((js_str = JS_ValueToString(cx, argv[1])) == NULL)
		return JS_FALSE;
	if (argnum < argc && JSVAL_IS_BOOLEAN(argv[argnum]))
		JS_ValueToBoolean(cx, argv[argnum++], &match_del);
	if (argnum < argc && JSVAL_IS_NUMBER(argv[argnum]))
		JS_ValueToInt32(cx, argv[argnum++], &usernumber);