Skip to content
Snippets Groups Projects
js_system.c 75.4 KiB
Newer Older

static JSBool
js_chkfname(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject *obj = JS_THIS_OBJECT(cx, arglist);
	jsval *argv = JS_ARGV(cx, arglist);
	char*		fname = NULL;
	jsrefcount	rc;

	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

	if(argc < 1 || !JSVAL_IS_STRING(argv[0]))
		return JS_TRUE;

	js_system_private_t* sys;
	if((sys = (js_system_private_t*)js_GetClassPrivate(cx,obj,&js_system_class))==NULL)
		return JS_FALSE;

	JSVALUE_TO_MSTRING(cx, argv[0], fname, NULL);
	if(fname == NULL)
		return JS_FALSE;

	rc=JS_SUSPENDREQUEST(cx);
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(!illegal_filename(fname)
		&& allowed_filename(sys->cfg, fname)
		&& !trashcan(sys->cfg, fname, "file")));
	JS_RESUMEREQUEST(cx, rc);
	free(fname);

	return JS_TRUE;
}

static JSBool
js_safest_fname(JSContext *cx, uintN argc, jsval *arglist)
{
	jsval *argv = JS_ARGV(cx, arglist);
	char*		fname = NULL;
	jsrefcount	rc;

	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

	if(argc < 1 || !JSVAL_IS_STRING(argv[0]))
		return JS_TRUE;

	JSVALUE_TO_MSTRING(cx, argv[0], fname, NULL);
	if(fname == NULL)
		return JS_FALSE;

	rc=JS_SUSPENDREQUEST(cx);
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(safest_filename(fname)));
	JS_RESUMEREQUEST(cx, rc);
	free(fname);

	return JS_TRUE;
}

static JSBool
js_illegal_fname(JSContext *cx, uintN argc, jsval *arglist)
{
	jsval *argv = JS_ARGV(cx, arglist);
	char*		fname = NULL;
	jsrefcount	rc;

	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

	if(argc < 1 || !JSVAL_IS_STRING(argv[0]))
		return JS_TRUE;

	JSVALUE_TO_MSTRING(cx, argv[0], fname, NULL);
	if(fname == NULL)
		return JS_FALSE;

	rc=JS_SUSPENDREQUEST(cx);
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(illegal_filename(fname)));
	JS_RESUMEREQUEST(cx, rc);
	free(fname);

	return JS_TRUE;
}

static JSBool
js_allowed_fname(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject *obj = JS_THIS_OBJECT(cx, arglist);
	jsval *argv = JS_ARGV(cx, arglist);
	char*		fname = NULL;
	jsrefcount	rc;

	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

	if(argc < 1 || !JSVAL_IS_STRING(argv[0]))
		return JS_TRUE;

	js_system_private_t* sys;
	if((sys = (js_system_private_t*)js_GetClassPrivate(cx,obj,&js_system_class))==NULL)
		return JS_FALSE;

	JSVALUE_TO_MSTRING(cx, argv[0], fname, NULL);
	if(fname == NULL)
		return JS_FALSE;

	rc=JS_SUSPENDREQUEST(cx);
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(allowed_filename(sys->cfg, fname)));
	JS_RESUMEREQUEST(cx, rc);
	free(fname);

	return JS_TRUE;
}

js_chkpid(JSContext *cx, uintN argc, jsval *arglist)
	jsval *argv=JS_ARGV(cx, arglist);
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
 	if(!js_argc(cx, argc, 1))
		return JS_FALSE;
	if(JSVAL_NULL_OR_VOID(argv[0])) {
		JS_ReportError(cx, "Invalid argument");
		return JS_FALSE;
	}
	JS_ValueToInt32(cx,argv[0],&pid);

	rc=JS_SUSPENDREQUEST(cx);
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(check_pid(pid)));
js_killpid(JSContext *cx, uintN argc, jsval *arglist)
	jsval *argv=JS_ARGV(cx, arglist);
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
 	if(!js_argc(cx, argc, 1))
		return JS_FALSE;
	if(JSVAL_NULL_OR_VOID(argv[0])) {
		JS_ReportError(cx, "Invalid argument");
		return JS_FALSE;
	}
	JS_ValueToInt32(cx,argv[0],&pid);

	rc=JS_SUSPENDREQUEST(cx);
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(terminate_pid(pid)));
static JSBool
js_text(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject* obj=JS_THIS_OBJECT(cx, arglist);
	jsval* argv=JS_ARGV(cx, arglist);
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);

 	if(!js_argc(cx, argc, 1))
		return JS_FALSE;

	if(JSVAL_NULL_OR_VOID(argv[0])) {
		JS_ReportError(cx, "Invalid argument");
		return JS_FALSE;
	}
	js_system_private_t* sys;
	if((sys = (js_system_private_t*)js_GetClassPrivate(cx,obj,&js_system_class)) == NULL)
		return JS_FALSE;

	if(sys->cfg == NULL || sys->cfg->text == NULL)
		return JS_TRUE;

	if(!JS_ValueToECMAUint32(cx, argv[0], &i))
		return JS_FALSE;

	if(i > 0  && i <= TOTAL_TEXT) {
		JSString* js_str = JS_NewStringCopyZ(cx, sys->cfg->text[i - 1]);
		if(js_str==NULL)
			return JS_FALSE;
		JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
	}
	return JS_TRUE;
}
static jsSyncMethodSpec js_system_functions[] = {
	{"username",		js_username,		1,	JSTYPE_STRING,	JSDOCSTR("user_number")
	,JSDOCSTR("Return name of user in specified user record <i>number</i>, or empty string if not found")
rswindell's avatar
rswindell committed
	{"alias",			js_alias,			1,	JSTYPE_STRING,	JSDOCSTR("alias")
	,JSDOCSTR("Return name of user that matches alias (if found in <tt>ctrl/alias.cfg</tt>)")
	{"find_login_id",	js_find_login_id,	1,	JSTYPE_NUMBER,	JSDOCSTR("user-id")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Find a user's login ID (alias, real name, or number), returns matching user record number or 0 if not found")
	{"matchuser",		js_matchuser,		1,	JSTYPE_NUMBER,	JSDOCSTR("username [,sysop_alias=true]")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Exact user name matching, returns number of user whose name/alias matches <i>username</i> "
		" or 0 if not found, matches well-known sysop aliases by default")
	{"matchuserdata",	js_matchuserdata,	2,	JSTYPE_NUMBER,	JSDOCSTR("field, data [,<i>bool</i> match_del=false] [,<i>number</i> usernumber, <i>bool</i> match_next=false]")
	,JSDOCSTR("Search user database for data in a specific field (see <tt>U_*</tt> in <tt>sbbsdefs.js</tt>).<br>"
		"If <i>match_del</i> is <tt>true</tt>, deleted user records are searched, "
		"returns first matching user record number, optional <i>usernumber</i> specifies user record to skip, "
		"or record at which to begin searching if optional <i>match_next</i> is <tt>true</tt>.")
	{"trashcan",		js_trashcan,		2,	JSTYPE_BOOLEAN,	JSDOCSTR("basename, find_string")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Search <tt>text/<i>basename</i>.can</tt> for pseudo-regexp")
	{"findstr",			js_findstr,			2,	JSTYPE_BOOLEAN,	JSDOCSTR("path/filename or <i>array</i> of strings, find_string")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Search any trashcan/filter file or array of pattern strings (in <tt>*.can</tt> format) for <i>find_string</i>")
rswindell's avatar
rswindell committed
	{"zonestr",			js_zonestr,			0,	JSTYPE_STRING,	JSDOCSTR("[timezone=<i>local</i>]")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Convert time zone integer to string, defaults to system timezone if <i>timezone</i> not specified")
rswindell's avatar
rswindell committed
	{"timestr",			js_timestr,			0,	JSTYPE_STRING,	JSDOCSTR("[time=<i>current</i>]")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Convert time_t integer into a time string, "
		"defaults to current time if <i>time</i> not specified")
rswindell's avatar
rswindell committed
	{"datestr",			js_datestr,			0,	JSTYPE_STRING,	JSDOCSTR("[time=<i>current</i>]")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Convert time_t integer into a date string (in either <tt>MM/DD/YY</tt> or <tt>DD/MM/YY</tt> format), "
		"defaults to current date if <i>time</i> not specified. "
		"If <i>time</i> is a string in the appropriate format, returns the time_t.")
	{"secondstr",		js_secondstr,		0,	JSTYPE_STRING,	JSDOCSTR("seconds")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Convert elapsed time in seconds into a string in <tt>hh:mm:ss</tt> format")
	{"spamlog",			js_spamlog,			6,	JSTYPE_BOOLEAN,	JSDOCSTR("[protocol, action, reason, host, ip, to, from]")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Log a suspected SPAM attempt")
	{"hacklog",			js_hacklog,			5,	JSTYPE_BOOLEAN,	JSDOCSTR("[protocol, user, text, host, ip, port]")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Log a suspected hack attempt")
	{"filter_ip",		js_filter_ip,		4,	JSTYPE_BOOLEAN,	JSDOCSTR("[protocol, reason, host, ip, username, filename] [<i>number</i> duration-in-seconds]")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Add an IP address (with comment) to an IP filter file. If filename is not specified, the ip.can file is used")
	},
	{"get_node",		js_get_node,		1,	JSTYPE_OBJECT,	JSDOCSTR("node_number")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Read a node data record all at once (and leaving the record unlocked) "
		"returning an object matching the elements of <tt>system.node_list</tt>")
	,31702
	},
rswindell's avatar
rswindell committed
	{"get_node_message",js_get_node_message,0,	JSTYPE_STRING,	JSDOCSTR("node_number")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Read any messages waiting for the specified node and return in a single string")
rswindell's avatar
rswindell committed
	{"put_node_message",js_put_node_message,2,	JSTYPE_BOOLEAN,	JSDOCSTR("node_number, message_text")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Send a node a short text message, delivered immediately")
rswindell's avatar
rswindell committed
	{"get_telegram",	js_get_telegram,	1,	JSTYPE_STRING,	JSDOCSTR("user_number")
	,JSDOCSTR("Return any short text messages waiting for the specified user")
rswindell's avatar
rswindell committed
	{"put_telegram",	js_put_telegram,	2,	JSTYPE_BOOLEAN,	JSDOCSTR("user_number, message_text")
	,JSDOCSTR("Send a user a short text message, delivered immediately or during next logon")
	{"notify",			js_notify,			2,	JSTYPE_BOOLEAN,	JSDOCSTR("user_number, subject [,message_text]")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Notify a user or operator via both email and a short text message about an important event")
	{"newuser",			js_new_user,		1,	JSTYPE_ALIAS },
	{"new_user",		js_new_user,		1,	JSTYPE_OBJECT,	JSDOCSTR("name/alias [,client object]")
	,JSDOCSTR("Create a new user record, returns a new <a href=#User>User</a> object representing the new user account, on success.<br>"
	"returns an numeric error code on failure")
	{"del_user",		js_del_user,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("user_number")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Delete the specified user account")
	{"exec",			js_sys_exec,		0,	JSTYPE_NUMBER,	JSDOCSTR("command-line")
	,JSDOCSTR("Execute a native system/shell command-line, returns <i>0</i> on success")
	},
	{"popen",			js_popen,			0,	JSTYPE_ARRAY,	JSDOCSTR("command-line")
	,JSDOCSTR("Execute a native system/shell command-line, returns array of captured output lines on success "
		"(<b>only functional on UNIX systems</b>)")
rswindell's avatar
rswindell committed
	{"check_syspass",	js_chksyspass,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("password")
	,JSDOCSTR("Compare the supplied <i>password</i> against the system password and returns <tt>true</tt> if it matches")
	{"check_name",		js_chkname,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("name/alias")
	,JSDOCSTR("Check that the provided name/alias string is suitable for a new user account, "
		"returns <tt>true</tt> if it is valid")
	{"check_filename",	js_chkfname,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("filename")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Verify that the specified <i>filename</i> string is legal and allowed for upload by users "
		"(based on system configuration and filter files), returns <tt>true</tt> if the filename is allowed")
	,31902
	},
	{"allowed_filename", js_allowed_fname,	1,	JSTYPE_BOOLEAN,	JSDOCSTR("filename")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Verify that the specified <i>filename</i> string is allowed for upload by users "
		"(based on system configuration), returns <tt>true</tt> if the filename is allowed")
	,31902
	},
	{"safest_filename",	js_safest_fname,	1,	JSTYPE_BOOLEAN,	JSDOCSTR("filename")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Verify that the specified <i>filename</i> string contains only the safest subset of characters")
	,31902
	},
	{"illegal_filename", js_illegal_fname,	1,	JSTYPE_BOOLEAN,	JSDOCSTR("filename")
Rob Swindell's avatar
Rob Swindell committed
	,JSDOCSTR("Check if the specified <i>filename</i> string contains illegal characters or sequences, "
		"returns <tt>true</tt> if it is an illegal filename")
	{"check_pid",		js_chkpid,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("process-ID")
	,JSDOCSTR("Check that the provided process ID is a valid executing process on the system, "
		"returns <tt>true</tt> if it is valid")
	,315
	},
	{"terminate_pid",	js_killpid,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("process-ID")
	,JSDOCSTR("Terminate executing process on the system with the specified process ID, "
		"returns <tt>true</tt> on success")
	{"text",			js_text,			1,	JSTYPE_STRING,	JSDOCSTR("index_number")
	,JSDOCSTR("Return specified text string (see <tt>bbs.text()</tt> for details)")
/* node properties */
enum {
	/* raw node_t fields */
	 NODE_PROP_STATUS
	,NODE_PROP_ERRORS
	,NODE_PROP_ACTION
	,NODE_PROP_USERON
	,NODE_PROP_CONNECTION
	,NODE_PROP_MISC
	,NODE_PROP_AUX
	,NODE_PROP_EXTAUX
static char* node_prop_desc[] = {
Rob Swindell's avatar
Rob Swindell committed
	 "Status (see <tt>nodedefs.js</tt> for valid values)"
	,"Error counter"
	,"Current user action (see <tt>nodedefs.js</tt>)"
	,"Current user number"
	,"Connection speed (<tt>0xffff</tt> = Telnet or RLogin)"
	,"Miscellaneous bit-flags (see <tt>nodedefs.js</tt>)"
	,"Auxiliary value"
	,"Extended auxiliary value"
Rob Swindell's avatar
Rob Swindell committed
	,"Node directory"
static JSBool js_node_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
	uint		node_num;
    jsint       tiny;
	node_t		node;
	JSObject*	sysobj;
	JSObject*	node_list;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_IdToValue(cx, id, &idval);
	tiny = JSVAL_TO_INT(idval);

	if((node_list=JS_GetParent(cx, obj))==NULL)
		return(JS_FALSE);

	if((sysobj=JS_GetParent(cx, node_list))==NULL)
		return(JS_FALSE);

	js_system_private_t* sys;
	if((sys = (js_system_private_t*)js_GetClassPrivate(cx,sysobj,&js_system_class))==NULL)
		return JS_FALSE;
	node_num=(uintptr_t)JS_GetPrivate(cx,obj)>>1;
	memset(&node,0,sizeof(node));
	if(getnodedat(sys->cfg, node_num, &node, /* lockit: */FALSE, &sys->nodefile)) {
		return(JS_TRUE);
    switch(tiny) {
		case NODE_PROP_STATUS:
			*vp = INT_TO_JSVAL((int)node.status);
			break;
			*vp = INT_TO_JSVAL((int)node.errors);
			break;
			*vp = INT_TO_JSVAL((int)node.action);
			break;
			*vp = INT_TO_JSVAL((int)node.useron);
			break;
		case NODE_PROP_CONNECTION:
			*vp = INT_TO_JSVAL((int)node.connection);
			break;
			*vp = INT_TO_JSVAL((int)node.misc);
			break;
			*vp = INT_TO_JSVAL((int)node.aux);
			break;
			*vp=UINT_TO_JSVAL(node.extaux);
			if((js_str=JS_NewStringCopyZ(cx, sys->cfg->node_path[node_num-1]))==NULL)
				return(JS_FALSE);
			*vp = STRING_TO_JSVAL(js_str);
			break;
static JSBool js_node_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
	uint		node_num;
	jsint		val=0;
    jsint       tiny;
	node_t		node;
	JSObject*	sysobj;
	JSObject*	node_list;
deuce's avatar
deuce committed
	jsrefcount	rc;

	if((node_list=JS_GetParent(cx, obj))==NULL)
		return(JS_FALSE);

	if((sysobj=JS_GetParent(cx, node_list))==NULL)
		return(JS_FALSE);

	js_system_private_t* sys;
	if((sys = (js_system_private_t*)js_GetClassPrivate(cx,sysobj,&js_system_class))==NULL)
		return JS_FALSE;
	node_num=(uintptr_t)JS_GetPrivate(cx,obj)>>1;
	memset(&node,0,sizeof(node));
	if(getnodedat(sys->cfg, node_num, &node, /* lockit: */TRUE, &sys->nodefile)) {
		return(JS_TRUE);
		JS_ValueToInt32(cx, *vp, &val);
	JS_IdToValue(cx, id, &idval);
	tiny = JSVAL_TO_INT(idval);
    switch(tiny) {
		case NODE_PROP_STATUS:
			break;
		case NODE_PROP_CONNECTION:
			node.extaux=val;
			break;
	}
	putnodedat(sys->cfg,node_num,&node, /* closeit: */FALSE, sys->nodefile);
	mqtt_putnodedat(sys->mqtt, node_num, &node);
static jsSyncPropertySpec js_node_properties[] = {
/*		 name,						tinyid,					flags,				ver	*/

/* raw node_t fields */
	{	"status",					NODE_PROP_STATUS,		JSPROP_ENUMERATE,	310 },
	{	"errors",					NODE_PROP_ERRORS,		JSPROP_ENUMERATE,	310 },
	{	"action",					NODE_PROP_ACTION,		JSPROP_ENUMERATE,	310 },
	{	"useron",					NODE_PROP_USERON,		JSPROP_ENUMERATE,	310 },
	{	"connection",				NODE_PROP_CONNECTION,	JSPROP_ENUMERATE,	310 },
	{	"misc",						NODE_PROP_MISC,			JSPROP_ENUMERATE,	310 },
	{	"aux",						NODE_PROP_AUX,			JSPROP_ENUMERATE,	310 },
	{	"extaux",					NODE_PROP_EXTAUX,		JSPROP_ENUMERATE,	310 },
	{	"dir",						NODE_PROP_DIR,			JSPROP_ENUMERATE|JSPROP_READONLY,	315 },
static JSBool js_node_resolve(JSContext *cx, JSObject *obj, jsid id)
deuce's avatar
deuce committed
{
	char*			name=NULL;
deuce's avatar
deuce committed
	JSBool			ret;
deuce's avatar
deuce committed
	if(id != JSID_VOID && id != JSID_EMPTY) {
		jsval idval;
deuce's avatar
deuce committed
		JS_IdToValue(cx, id, &idval);
deuce's avatar
deuce committed
		if(JSVAL_IS_STRING(idval)) {
			JSSTRING_TO_MSTRING(cx, JSVAL_TO_STRING(idval), name, NULL);
			HANDLE_PENDING(cx, name);
deuce's avatar
deuce committed
	}
deuce's avatar
deuce committed
	ret=js_SyncResolve(cx, obj, name, js_node_properties, NULL, NULL, 0);
	if(name)
		free(name);
	return(ret);
deuce's avatar
deuce committed
}

static JSBool js_node_enumerate(JSContext *cx, JSObject *obj)
{
deuce's avatar
deuce committed
	return(js_node_resolve(cx, obj, JSID_VOID));
static JSClass js_node_class = {
     "Node"					/* name			*/
    ,JSCLASS_HAS_PRIVATE	/* flags		*/
	,JS_PropertyStub		/* addProperty	*/
	,JS_PropertyStub		/* delProperty	*/
	,js_node_get			/* getProperty	*/
	,js_node_set			/* setProperty	*/
deuce's avatar
deuce committed
	,js_node_enumerate		/* enumerate	*/
	,js_node_resolve		/* resolve		*/
	,JS_ConvertStub			/* convert		*/
	,JS_FinalizeStub		/* finalize		*/
};

deuce's avatar
deuce committed
#define LAZY_INTEGER(PropName, PropValue) \
	if(name==NULL || strcmp(name, (PropName))==0) { \
		val=UINT_TO_JSVAL((PropValue)); \
deuce's avatar
deuce committed
		JS_DefineProperty(cx, obj, (PropName), val, NULL,NULL,JSPROP_ENUMERATE); \
deuce's avatar
deuce committed
		if(name) { \
			free(name); \
			return(JS_TRUE); \
		} \
deuce's avatar
deuce committed
#define LAZY_STRING(PropName, PropValue) \
	if(name==NULL || strcmp(name, (PropName))==0) { \
		if((js_str=JS_NewStringCopyZ(cx, (PropValue)))!=NULL) { \
			JS_DefineProperty(cx, obj, PropName, STRING_TO_JSVAL(js_str), NULL, NULL, JSPROP_ENUMERATE); \
deuce's avatar
deuce committed
			if(name) { \
				free(name); \
				return(JS_TRUE); \
			} \
		} \
		else if(name) { \
			free(name); \
			return(JS_TRUE); \
deuce's avatar
deuce committed
#define LAZY_STRFUNC(PropName, Function, PropValue) \
	if(name==NULL || strcmp(name, (PropName))==0) { \
		Function; \
		if((js_str=JS_NewStringCopyZ(cx, (PropValue)))!=NULL) { \
			JS_DefineProperty(cx, obj, PropName, STRING_TO_JSVAL(js_str), NULL, NULL, JSPROP_ENUMERATE); \
deuce's avatar
deuce committed
			if(name) { \
				free(name); \
				return(JS_TRUE); \
			} \
		} \
		else if(name) { \
			free(name); \
			return(JS_TRUE); \
deuce's avatar
deuce committed
#define LAZY_STRFUNC_TRUNCSP(PropName, Function, PropValue) \
	if(name==NULL || strcmp(name, (PropName))==0) { \
		Function; \
		if((js_str=JS_NewStringCopyZ(cx, truncsp(PropValue)))!=NULL) { \
			JS_DefineProperty(cx, obj, PropName, STRING_TO_JSVAL(js_str), NULL, NULL, JSPROP_ENUMERATE); \
deuce's avatar
deuce committed
			if(name) { \
				free(name); \
				return(JS_TRUE); \
			} \
		} \
		else if(name) { \
			free(name); \
			return(JS_TRUE); \
static JSBool js_system_resolve(JSContext *cx, JSObject *obj, jsid id)
deuce's avatar
deuce committed
{
	char*		name=NULL;
	jsval		val;
	char		str[256];
	JSString*	js_str;
deuce's avatar
deuce committed
	JSObject*	newobj;
	JSObject*	nodeobj;
deuce's avatar
deuce committed
	if(id != JSID_VOID && id != JSID_EMPTY) {
		jsval idval;
deuce's avatar
deuce committed
		JS_IdToValue(cx, id, &idval);
deuce's avatar
deuce committed
		if(JSVAL_IS_STRING(idval)) {
			JSSTRING_TO_MSTRING(cx, JSVAL_TO_STRING(idval), name, NULL);
			HANDLE_PENDING(cx, name);
deuce's avatar
deuce committed
	}
	/****************************/
	/* static string properties */
deuce's avatar
deuce committed
	LAZY_STRING("version", VERSION);
	LAZY_STRFUNC("revision", sprintf(str,"%c",REVISION), str);
	LAZY_STRFUNC_TRUNCSP("beta_version", SAFECOPY(str, beta_version), str);
deuce's avatar
deuce committed
	if(name==NULL || strcmp(name, "full_version")==0) {
		sprintf(str,"%s%c%s",VERSION,REVISION,beta_version);
		truncsp(str);
#if defined(_DEBUG)
deuce's avatar
deuce committed
		strcat(str," Debug");
deuce's avatar
deuce committed
		if(name) free(name);
deuce's avatar
deuce committed
		if((js_str=JS_NewStringCopyZ(cx, str))!=NULL) {
			val = STRING_TO_JSVAL(js_str);
			JS_SetProperty(cx, obj, "full_version", &val);
			if(name) return(JS_TRUE);
		}
		else if(name) return(JS_TRUE);
	}
deuce's avatar
deuce committed
	LAZY_STRING("version_notice", VERSION_NOTICE);
deuce's avatar
deuce committed
	LAZY_INTEGER("version_num", VERSION_NUM);
	LAZY_INTEGER("version_hex", VERSION_HEX);
	/* Git repo details */
	LAZY_STRING("git_branch", git_branch);
	LAZY_STRING("git_hash", git_hash);

deuce's avatar
deuce committed
	LAZY_STRING("platform", PLATFORM_DESC);
	LAZY_STRING("architecture", ARCHITECTURE_DESC);
deuce's avatar
deuce committed
	LAZY_STRFUNC("msgbase_lib", sprintf(str,"SMBLIB %s",smb_lib_ver()), str);
	LAZY_STRFUNC("compiled_with", DESCRIBE_COMPILER(str), str);
	LAZY_STRFUNC("compiled_when", sprintf(str,"%s %.5s",__DATE__,__TIME__), str);
	LAZY_STRING("copyright", COPYRIGHT_NOTICE);
	LAZY_STRING("js_version", (char *)JS_GetImplementationVersion());
	LAZY_STRING("os_version", os_version(str, sizeof(str)));
deuce's avatar
deuce committed
	/* fido_addr_list property */
	if(name==NULL || strcmp(name, "fido_addr_list")==0) {
deuce's avatar
deuce committed
		if(name) free(name);

		js_system_private_t* sys;
		if((sys = (js_system_private_t*)js_GetClassPrivate(cx,obj,&js_system_class))==NULL)
			return JS_FALSE;
deuce's avatar
deuce committed
		if((newobj=JS_NewArrayObject(cx, 0, NULL))==NULL)
			return(JS_FALSE);
		if(!JS_SetParent(cx, newobj, obj))
			return(JS_FALSE);

deuce's avatar
deuce committed
		if(!JS_DefineProperty(cx, obj, "fido_addr_list", OBJECT_TO_JSVAL(newobj)
			, NULL, NULL, JSPROP_ENUMERATE))
			return(JS_FALSE);
		for(i=0;i<sys->cfg->total_faddrs;i++) {
			val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,smb_faddrtoa(&sys->cfg->faddr[i],str)));
deuce's avatar
deuce committed
			JS_SetElement(cx, newobj, i, &val);
		}
		if(name) return(JS_TRUE);
	}
deuce's avatar
deuce committed
	if(name==NULL || strcmp(name, "stats")==0) {
deuce's avatar
deuce committed
		if(name) free(name);

		js_system_private_t* sys;
		if((sys = (js_system_private_t*)js_GetClassPrivate(cx,obj,&js_system_class))==NULL)
			return JS_FALSE;
deuce's avatar
deuce committed
		newobj = JS_DefineObject(cx, obj, "stats", &js_sysstats_class, NULL
			,JSPROP_ENUMERATE|JSPROP_READONLY);
deuce's avatar
deuce committed
		if(newobj==NULL)
			return(JS_FALSE);
#ifdef BUILD_JSDOCS
		js_DescribeSyncObject(cx,newobj,"System statistics",310);
		js_CreateArrayOfStrings(cx, newobj, "_property_desc_list", sysstat_prop_desc, JSPROP_READONLY);
#endif
deuce's avatar
deuce committed
		if(name) return JS_TRUE;
deuce's avatar
deuce committed
	/* node_list property */
	if(name==NULL || strcmp(name, "node_list")==0) {
deuce's avatar
deuce committed
		if(name) free(name);

		js_system_private_t* sys;
		if((sys = (js_system_private_t*)js_GetClassPrivate(cx,obj,&js_system_class))==NULL)
			return JS_FALSE;
		if((newobj=JS_NewArrayObject(cx, 0, NULL))==NULL)
deuce's avatar
deuce committed
			return(JS_FALSE);
		if(!JS_SetParent(cx, newobj, obj))
			return(JS_FALSE);

deuce's avatar
deuce committed
		if(!JS_DefineProperty(cx, obj, "node_list", OBJECT_TO_JSVAL(newobj)
			, NULL, NULL, JSPROP_ENUMERATE))
			return(JS_FALSE);
		for(i=0;i<sys->cfg->sys_nodes && i<sys->cfg->sys_lastnode;i++) {
deuce's avatar
deuce committed
			nodeobj = JS_NewObject(cx, &js_node_class, NULL, newobj);

			if(nodeobj==NULL)
				return(JS_FALSE);

			/* Store node number */
			/* We have to shift it to make it look like a pointer to JS. :-( */
			if(!JS_SetPrivate(cx, nodeobj, (char*)(((uintptr_t)i+1)<<1)))
deuce's avatar
deuce committed
				return(JS_FALSE);
deuce's avatar
deuce committed
	#ifdef BUILD_JSDOCS
			if(i==0) {
				js_DescribeSyncObject(cx,nodeobj,"Terminal Server node listing",310);
deuce's avatar
deuce committed
				js_CreateArrayOfStrings(cx, nodeobj, "_property_desc_list", node_prop_desc, JSPROP_READONLY);
			}
	#endif

			val=OBJECT_TO_JSVAL(nodeobj);
			if(!JS_SetElement(cx, newobj, i, &val))
				return(JS_FALSE);
		}
		if(name) return(JS_TRUE);
deuce's avatar
deuce committed
	ret = js_SyncResolve(cx, obj, name, js_system_properties, js_system_functions, NULL, 0);
	if(name) free(name);
	return ret;
deuce's avatar
deuce committed
static JSBool js_system_enumerate(JSContext *cx, JSObject *obj)
{
	return(js_system_resolve(cx, obj, JSID_VOID));
static void js_system_finalize(JSContext *cx, JSObject *obj)
{
	js_system_private_t* sys;
	if((sys = (js_system_private_t*)JS_GetPrivate(cx, obj)) == NULL)
	CLOSE_OPEN_FILE(sys->nodefile);
	free(sys);
	JS_SetPrivate(cx, obj, NULL);
JSBool js_CreateTextProperties(JSContext* cx, JSObject* parent)
{
	jsval val;

	if (!JS_GetProperty(cx, parent, "text", &val))
		return JS_FALSE;

	JSObject* text = JSVAL_TO_OBJECT(val);
	for (int i = 0; i < TOTAL_TEXT; ++i) {
		val = INT_TO_JSVAL(i + 1);
		if(!JS_SetProperty(cx, text, text_id[i], &val))
			return JS_FALSE;
	}
	return JS_TRUE;
}

deuce's avatar
deuce committed
     "System"				/* name			*/
    ,JSCLASS_HAS_PRIVATE	/* flags		*/
	,JS_PropertyStub		/* addProperty	*/
	,JS_PropertyStub		/* delProperty	*/
	,js_system_get			/* getProperty	*/
	,js_system_set			/* setProperty	*/
	,js_system_enumerate	/* enumerate	*/
	,js_system_resolve		/* resolve		*/
	,JS_ConvertStub			/* convert		*/
	,js_system_finalize		/* finalize		*/
JSObject* js_CreateSystemObject(JSContext* cx, JSObject* parent
										,scfg_t* cfg, time_t uptime, char* host_name, char* socklib_desc, struct mqtt* mqtt)
deuce's avatar
deuce committed
{
	jsval		val;
	JSObject*	sysobj;
	JSString*	js_str;
	char		str[256];
deuce's avatar
deuce committed
	sysobj = JS_DefineObject(cx, parent, "system", &js_system_class, NULL
		,JSPROP_ENUMERATE|JSPROP_READONLY);
	if(sysobj==NULL)
	js_system_private_t* sys;
	if((sys = calloc(sizeof(*sys), 1)) == NULL)
		return NULL;

	sys->cfg = cfg;
deuce's avatar
deuce committed
	/****************************/
	/* static string properties */
deuce's avatar
deuce committed
	if((js_str=JS_NewStringCopyZ(cx, host_name))==NULL)
		return(NULL);
	val = STRING_TO_JSVAL(js_str);
	if(!JS_SetProperty(cx, sysobj, "host_name", &val))
		return(NULL);
deuce's avatar
deuce committed
	if((js_str=JS_NewStringCopyZ(cx, socklib_version(str, socklib_desc)))==NULL)
		return(NULL);
	val = STRING_TO_JSVAL(js_str);
	if(!JS_SetProperty(cx, sysobj, "socket_lib", &val))
		return(NULL);
deuce's avatar
deuce committed
	/***********************/
	val=DOUBLE_TO_JSVAL((double)uptime);
deuce's avatar
deuce committed
	if(!JS_SetProperty(cx, sysobj, "uptime", &val))
		return(NULL);
deuce's avatar
deuce committed
	js_DescribeSyncObject(cx,sysobj,"Global system-related properties and methods",310);
	js_CreateArrayOfStrings(cx, sysobj, "_property_desc_list", sys_prop_desc, JSPROP_READONLY);
#endif	/* JAVSCRIPT */