Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

js_server.c 7.42 KB
Newer Older
1 2 3 4
/* js_server.c */

/* Synchronet JavaScript "server" Object */

5
/* $Id: js_server.c,v 1.19 2018/02/20 11:56:27 rswindell Exp $ */
6 7 8 9 10

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
11
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
 *																			*
 * 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										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "sbbs.h"

/* System Object Properites */
enum {
	 SERVER_PROP_VER
	,SERVER_PROP_VER_DETAIL
44
	,SERVER_PROP_INTERFACE
45 46 47 48
	,SERVER_PROP_OPTIONS
	,SERVER_PROP_CLIENTS
};

49
static JSBool js_server_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
50
{
51 52
	jsval				idval;
    jsint				tiny;
53
	js_server_props_t*	p;
54 55 56
	char * *			interface;
	char *				ipv4;
	char *				colon;
57 58 59 60

	if((p=(js_server_props_t*)JS_GetPrivate(cx,obj))==NULL)
		return(JS_FALSE);

61 62
    JS_IdToValue(cx, id, &idval);
    tiny = JSVAL_TO_INT(idval);
63 64 65

	switch(tiny) {
		case SERVER_PROP_VER:
deuce's avatar
deuce committed
66
			*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,p->version));
67 68 69 70 71
			break;
		case SERVER_PROP_VER_DETAIL:
			if(p->version_detail!=NULL)
				*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,p->version_detail));
			break;
72 73 74 75 76 77 78 79 80 81 82 83 84
		case SERVER_PROP_INTERFACE:
			for (interface = *p->interfaces; *interface; interface++) {
				if (strchr(*interface, '.')) {
					ipv4 = strdup(*interface);
					if ((colon = strchr(ipv4, ':')))
						*colon = 0;
					*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,ipv4));
					free(ipv4);
					return JS_TRUE;
				}
			}
			*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,"255.255.255.255"));
			break;
85 86
		case SERVER_PROP_OPTIONS:
			if(p->options!=NULL)
87
				*vp=UINT_TO_JSVAL(*p->options);
88 89 90
			break;
		case SERVER_PROP_CLIENTS:
			if(p->clients!=NULL)
91
				*vp=UINT_TO_JSVAL(protected_uint32_value(*p->clients));
92 93 94 95 96 97
			break;
	}

	return(JS_TRUE);
}

98
static JSBool js_server_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
99
{
100
	jsval idval;
101 102 103 104 105 106
    jsint				tiny;
	js_server_props_t*	p;

	if((p=(js_server_props_t*)JS_GetPrivate(cx,obj))==NULL)
		return(JS_FALSE);

107 108
    JS_IdToValue(cx, id, &idval);
    tiny = JSVAL_TO_INT(idval);
109 110 111

	switch(tiny) {
		case SERVER_PROP_OPTIONS:
112 113 114 115
			if(p->options!=NULL) {
				if(!JS_ValueToInt32(cx, *vp, (int32*)p->options))
					return JS_FALSE;
			}
116 117 118 119 120 121 122 123 124 125 126 127 128 129
			break;
	}

	return(TRUE);
}


#define PROP_FLAGS JSPROP_ENUMERATE|JSPROP_READONLY

static jsSyncPropertySpec js_server_properties[] = {
/*		 name,						tinyid,					flags,			ver	*/

	{	"version",					SERVER_PROP_VER,		PROP_FLAGS,			310 },
	{	"version_detail",			SERVER_PROP_VER_DETAIL,	PROP_FLAGS,			310 },
130
	{	"interface_ip_address",		SERVER_PROP_INTERFACE,	PROP_FLAGS,			311 },
131 132 133 134 135
	{	"options",					SERVER_PROP_OPTIONS,	JSPROP_ENUMERATE,	311 },
	{	"clients",					SERVER_PROP_CLIENTS,	PROP_FLAGS,			311 },
	{0}
};

136
#ifdef BUILD_JSDOCS
137 138 139 140
static char* server_prop_desc[] = {

	 "server name and version number"
	,"detailed version/build information"
141
	,"First bound IPv4 address (<tt>0.0.0.0</tt> = <i>ANY</i>) (obsolete since 3.17, see interface_ip_addr_list)"
142 143
	,"bit-field of server-specific startup options"
	,"number of active clients (if available)"
144
	,"Array of IP addresses of bound network interface (<tt>0.0.0.0</tt> = <i>ANY</i>)"
145 146 147 148
	,NULL
};
#endif

149 150 151 152
static void remove_port_part(char *host)
{
	char *p=strchr(host, 0)-1;

153
	if (IS_DIGIT(*p)) {
154 155 156 157 158 159 160 161 162 163 164 165 166
		/*
		 * If the first and last : are not the same, and it doesn't
		 * start with '[', there's no port part.
		 */
		if (host[0] != '[') {
			if (strchr(host, ':') != strrchr(host, ':'))
				return;
		}
		for(; p >= host; p--) {
			if (*p == ':') {
				*p = 0;
				break;
			}
167
			if (!IS_DIGIT(*p))
168
				break;
169
		}
170 171 172 173 174 175 176
	}
	// Now, remove []s...
	if (host[0] == '[') {
		memmove(host, host+1, strlen(host));
		p=strchr(host, ']');
		if (p)
			*p = 0;
177 178 179
	}
}

180
static JSBool js_server_resolve(JSContext *cx, JSObject *obj, jsid id)
deuce's avatar
deuce committed
181 182
{
	char*			name=NULL;
deuce's avatar
deuce committed
183
	JSBool			ret;
184 185 186 187 188
	jsval			val;
	char			*str;
	JSObject*		newobj;
	uint			i;
	js_server_props_t*	props;
deuce's avatar
deuce committed
189

deuce's avatar
deuce committed
190 191 192 193
	if(id != JSID_VOID && id != JSID_EMPTY) {
		jsval idval;
		
		JS_IdToValue(cx, id, &idval);
deuce's avatar
deuce committed
194 195
		if(JSVAL_IS_STRING(idval)) {
			JSSTRING_TO_MSTRING(cx, JSVAL_TO_STRING(idval), name, NULL);
196
			HANDLE_PENDING(cx, name);
deuce's avatar
deuce committed
197
		}
deuce's avatar
deuce committed
198
	}
deuce's avatar
deuce committed
199

200
	/* interface_ip_address property */
201
	if(name==NULL || strcmp(name, "interface_ip_addr_list")==0) {
202 203 204 205 206 207 208 209 210 211 212
		if(name) free(name);

		if((props=(js_server_props_t*)JS_GetPrivate(cx,obj))==NULL)
			return(JS_FALSE);

		if((newobj=JS_NewArrayObject(cx, 0, NULL))==NULL)
			return(JS_FALSE);

		if(!JS_SetParent(cx, newobj, obj))
			return(JS_FALSE);

213
		if(!JS_DefineProperty(cx, obj, "interface_ip_addr_list", OBJECT_TO_JSVAL(newobj)
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
				, NULL, NULL, JSPROP_ENUMERATE))
			return(JS_FALSE);

		for (i=0; (*props->interfaces)[i]; i++) {
			str = strdup((*props->interfaces)[i]);
			if (str == NULL)
				return JS_FALSE;
			remove_port_part(str);
			val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,str));
			free(str);
			JS_SetElement(cx, newobj, i, &val);
		}
		JS_DeepFreezeObject(cx, newobj);
		if(name) return(JS_TRUE);
	}

deuce's avatar
deuce committed
230 231 232 233
	ret = js_SyncResolve(cx, obj, name, js_server_properties, NULL, NULL, 0);
	if(name)
		free(name);
	return ret;
deuce's avatar
deuce committed
234 235 236 237
}

static JSBool js_server_enumerate(JSContext *cx, JSObject *obj)
{
deuce's avatar
deuce committed
238
	return(js_server_resolve(cx, obj, JSID_VOID));
deuce's avatar
deuce committed
239
}
240 241 242 243 244 245 246 247

static JSClass js_server_class = {
     "Server"				/* name			*/
    ,JSCLASS_HAS_PRIVATE	/* flags		*/
	,JS_PropertyStub		/* addProperty	*/
	,JS_PropertyStub		/* delProperty	*/
	,js_server_get			/* getProperty	*/
	,js_server_set			/* setProperty	*/
deuce's avatar
deuce committed
248 249
	,js_server_enumerate	/* enumerate	*/
	,js_server_resolve		/* resolve		*/
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
	,JS_ConvertStub			/* convert		*/
	,JS_FinalizeStub		/* finalize		*/
};

JSObject* DLLCALL js_CreateServerObject(JSContext* cx, JSObject* parent
										,js_server_props_t* props)
{
	JSObject*	obj;

	if((obj = JS_DefineObject(cx, parent, "server", &js_server_class, NULL
		,JSPROP_ENUMERATE|JSPROP_READONLY))==NULL)
		return(NULL);

	if(!JS_SetPrivate(cx, obj, props))
		return(NULL);

266
#ifdef BUILD_JSDOCS
267 268 269 270 271 272 273
	js_DescribeSyncObject(cx,obj,"Server-specifc properties",310);
	js_CreateArrayOfStrings(cx,obj,"_property_desc_list", server_prop_desc, JSPROP_READONLY);
#endif

	return(obj);
}