From d988d15101bed3ddb9061d9ccb46bf08cc1c7a7e Mon Sep 17 00:00:00 2001
From: rswindell <>
Date: Sun, 26 Oct 2003 22:56:50 +0000
Subject: [PATCH] Create unified "server" object (js_server.c) with new
 properties: clients, options, and interface_addr.

---
 src/sbbs3/ftpsrvr.c   |  24 +++++-
 src/sbbs3/js_server.c | 169 ++++++++++++++++++++++++++++++++++++++++++
 src/sbbs3/main.cpp    |  49 ++++++++----
 src/sbbs3/objects.mk  |   1 +
 src/sbbs3/sbbs.dsp    |   4 +
 src/sbbs3/sbbs.h      |  13 +++-
 src/sbbs3/services.c  |  47 +++++++++---
 src/sbbs3/websrvr.c   |  21 +++++-
 8 files changed, 291 insertions(+), 37 deletions(-)
 create mode 100644 src/sbbs3/js_server.c

diff --git a/src/sbbs3/ftpsrvr.c b/src/sbbs3/ftpsrvr.c
index cbe5bb0fb2..cba05c3112 100644
--- a/src/sbbs3/ftpsrvr.c
+++ b/src/sbbs3/ftpsrvr.c
@@ -378,6 +378,8 @@ int getdir(char* p, user_t* user)
 /*********************************/
 #ifdef JAVASCRIPT
 
+js_server_props_t js_server_props;
+
 static JSBool
 js_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
@@ -465,12 +467,8 @@ js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
 static JSContext* 
 js_initcx(JSRuntime* runtime, SOCKET sock, JSObject** glob, JSObject** ftp)
 {
-	char		ver[256];
 	JSContext*	js_cx;
 	JSObject*	js_glob;
-	JSObject*	server;
-	JSString*	js_str;
-	jsval		val;
 	BOOL		success=FALSE;
 
 	lprintf(LOG_DEBUG,"%04d JavaScript: Initializing context (stack: %lu bytes)"
@@ -500,6 +498,12 @@ js_initcx(JSRuntime* runtime, SOCKET sock, JSObject** glob, JSObject** ftp)
 			,NULL,JSPROP_ENUMERATE|JSPROP_READONLY))==NULL)
 			break;
 
+#if 0
+		char		ver[256];
+		JSObject*	server;
+		JSString*	js_str;
+		jsval		val;
+
 		if((server=JS_DefineObject(js_cx, js_glob, "server", NULL
 			,NULL,JSPROP_ENUMERATE|JSPROP_READONLY))==NULL)
 			break;
@@ -517,6 +521,11 @@ js_initcx(JSRuntime* runtime, SOCKET sock, JSObject** glob, JSObject** ftp)
 		if(!JS_SetProperty(js_cx, server, "version_detail", &val))
 			break;
 
+#else
+		if(js_CreateServerObject(js_cx,js_glob,&js_server_props)==NULL)
+			break;
+#endif
+
 		if(glob!=NULL)
 			*glob=js_glob;
 
@@ -4523,8 +4532,15 @@ void DLLCALL ftp_server(void* arg)
 #ifdef JAVASCRIPT
 	if(startup->js_max_bytes==0)			startup->js_max_bytes=JAVASCRIPT_MAX_BYTES;
 	if(startup->js_cx_stack==0)				startup->js_cx_stack=JAVASCRIPT_CONTEXT_STACK;
+
+	sprintf(js_server_props.version,"%s %s",FTP_SERVER,revision);
+	js_server_props.version_detail=ftp_ver();
+	js_server_props.clients=&active_clients;
+	js_server_props.options=&startup->options;
+	js_server_props.interface_addr=&startup->interface_addr;
 #endif
 
+
 	uptime=0;
 	served=0;
 	startup->recycle_now=FALSE;
diff --git a/src/sbbs3/js_server.c b/src/sbbs3/js_server.c
new file mode 100644
index 0000000000..7fad554981
--- /dev/null
+++ b/src/sbbs3/js_server.c
@@ -0,0 +1,169 @@
+/* js_server.c */
+
+/* Synchronet JavaScript "server" Object */
+
+/* $Id$ */
+
+/****************************************************************************
+ * @format.tab-size 4		(Plain Text/Source Code File Header)			*
+ * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
+ *																			*
+ * Copyright 2003 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										*
+ *																			*
+ * 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
+	,SERVER_PROP_INTERFACE
+	,SERVER_PROP_OPTIONS
+	,SERVER_PROP_CLIENTS
+};
+
+static JSBool js_server_get(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+    jsint       tiny;
+	struct in_addr in_addr;
+	js_server_props_t*	p;
+
+	if((p=(js_server_props_t*)JS_GetPrivate(cx,obj))==NULL)
+		return(JS_FALSE);
+
+    tiny = JSVAL_TO_INT(id);
+
+	switch(tiny) {
+		case SERVER_PROP_VER:
+			*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,p->version));
+			break;
+		case SERVER_PROP_VER_DETAIL:
+			if(p->version_detail!=NULL)
+				*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,p->version_detail));
+			break;
+		case SERVER_PROP_INTERFACE:
+			if(p->interface_addr!=NULL) {
+				in_addr.s_addr=*(p->interface_addr);
+				*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,inet_ntoa(in_addr)));
+			}
+			break;
+		case SERVER_PROP_OPTIONS:
+			if(p->options!=NULL)
+				JS_NewNumberValue(cx,*p->options,vp);
+			break;
+		case SERVER_PROP_CLIENTS:
+			if(p->clients!=NULL)
+				JS_NewNumberValue(cx,*p->clients,vp);
+			break;
+	}
+
+	return(JS_TRUE);
+}
+
+static JSBool js_server_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+    jsint				tiny;
+	js_server_props_t*	p;
+
+	if((p=(js_server_props_t*)JS_GetPrivate(cx,obj))==NULL)
+		return(JS_FALSE);
+
+    tiny = JSVAL_TO_INT(id);
+
+	switch(tiny) {
+		case SERVER_PROP_OPTIONS:
+			if(p->options!=NULL)
+				JS_ValueToInt32(cx, *vp, (int32*)p->options);
+			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 },
+	{	"interface_ip_address",		SERVER_PROP_INTERFACE,	PROP_FLAGS,			311 },
+	{	"options",					SERVER_PROP_OPTIONS,	JSPROP_ENUMERATE,	311 },
+	{	"clients",					SERVER_PROP_CLIENTS,	PROP_FLAGS,			311 },
+	{0}
+};
+
+#ifdef _DEBUG
+static char* server_prop_desc[] = {
+
+	 "server name and version number"
+	,"detailed version/build information"
+	,"IP address of bound network interface (<tt>0.0.0.0</tt> = <i>ANY</i>)"
+	,"bit-field of server-specific startup options"
+	,"number of active clients (if available)"
+	,NULL
+};
+#endif
+
+
+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	*/
+	,JS_EnumerateStub		/* enumerate	*/
+	,JS_ResolveStub			/* resolve		*/
+	,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);
+
+	if(!js_DefineSyncProperties(cx, obj, js_server_properties))
+		return(NULL);
+
+#ifdef _DEBUG
+	js_DescribeSyncObject(cx,obj,"Server-specifc properties",310);
+	js_CreateArrayOfStrings(cx,obj,"_property_desc_list", server_prop_desc, JSPROP_READONLY);
+#endif
+
+	return(obj);
+}
+
diff --git a/src/sbbs3/main.cpp b/src/sbbs3/main.cpp
index d513439fa8..6d7818f714 100644
--- a/src/sbbs3/main.cpp
+++ b/src/sbbs3/main.cpp
@@ -70,8 +70,8 @@ uint riobp;
 time_t	uptime=0;
 DWORD	served=0;
 
-static	uint node_threads_running=0;
-static	uint thread_count=0;
+static	ulong node_threads_running=0;
+static	ulong thread_count=0;
 		
 char 	lastuseron[LEN_ALIAS+1];  /* Name of user last online */
 RingBuf* node_inbuf[MAX_NODES];
@@ -235,6 +235,8 @@ u_long resolve_ip(char *addr)
 
 #ifdef JAVASCRIPT
 
+static js_server_props_t js_server_props;
+
 JSBool	
 DLLCALL js_CreateArrayOfStrings(JSContext* cx, JSObject* parent, const char* name, char* str[],uintN flags)
 {
@@ -816,10 +818,6 @@ js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
 bool sbbs_t::js_init()
 {
 	char		node[128];
-	char		ver[256];
-	jsval		val;
-	JSObject*	server;
-	JSString*	js_str;
 
     if(cfg.node_num)
     	sprintf(node,"Node %d",cfg.node_num);
@@ -901,6 +899,12 @@ bool sbbs_t::js_init()
 		if(!js_CreateUserObjects(js_cx, js_glob, &scfg, NULL, NULL, NULL)) 
 			break;
 
+#if 0
+		char		ver[256];
+		jsval		val;
+		JSObject*	server;
+		JSString*	js_str;
+
 		/* Server Object */
 		if((server=JS_DefineObject(js_cx, js_glob, "server", NULL
 			,NULL,JSPROP_ENUMERATE|JSPROP_READONLY))==NULL)
@@ -923,6 +927,12 @@ bool sbbs_t::js_init()
 		js_DescribeSyncObject(js_cx,server,"Server-specifc properties",310);
 		js_CreateArrayOfStrings(js_cx, server, "_property_desc_list", server_prop_desc, JSPROP_READONLY);
 #endif
+
+#else
+		if(js_CreateServerObject(js_cx,js_glob,&js_server_props)==NULL)
+			break;
+#endif
+
 		success=true;
 
 	} while(0);
@@ -3479,20 +3489,21 @@ const char* DLLCALL bbs_ver(void)
 	static char ver[256];
 	char compiler[32];
 
-	DESCRIBE_COMPILER(compiler);
+	if(ver[0]==0) {	/* uninitialized */
+		DESCRIBE_COMPILER(compiler);
 
-	sprintf(ver,"%s %s%c%s  SMBLIB %s  Compiled %s %s with %s"
-		,TELNET_SERVER
-		,VERSION, REVISION
+		sprintf(ver,"%s %s%c%s  SMBLIB %s  Compiled %s %s with %s"
+			,TELNET_SERVER
+			,VERSION, REVISION
 #ifdef _DEBUG
-		," Debug"
+			," Debug"
 #else
-		,""
+			,""
 #endif
-		,smb_lib_ver()
-		,__DATE__, __TIME__, compiler
-		);
-
+			,smb_lib_ver()
+			,__DATE__, __TIME__, compiler
+			);
+	}
 	return(ver);
 }
 
@@ -3631,6 +3642,12 @@ void DLLCALL bbs_thread(void* arg)
 	if(startup->sem_chk_freq==0)			startup->sem_chk_freq=5;
 	if(startup->temp_dir[0])				backslash(startup->temp_dir);
 
+	sprintf(js_server_props.version,"%s %s%c",TELNET_SERVER,VERSION,REVISION);
+	js_server_props.version_detail=bbs_ver();
+	js_server_props.clients=&node_threads_running;
+	js_server_props.options=&startup->options;
+	js_server_props.interface_addr=&startup->telnet_interface;
+
 	uptime=0;
 	served=0;
 	startup->recycle_now=FALSE;
diff --git a/src/sbbs3/objects.mk b/src/sbbs3/objects.mk
index ffa58be53b..8b7566e06b 100644
--- a/src/sbbs3/objects.mk
+++ b/src/sbbs3/objects.mk
@@ -52,6 +52,7 @@ OBJS	=	$(LIBODIR)$(SLASH)ansiterm.$(OFILE)\
 			$(LIBODIR)$(SLASH)js_internal.$(OFILE)\
 			$(LIBODIR)$(SLASH)js_msg_area.$(OFILE)\
 			$(LIBODIR)$(SLASH)js_msgbase.$(OFILE)\
+			$(LIBODIR)$(SLASH)js_server.$(OFILE)\
 			$(LIBODIR)$(SLASH)js_socket.$(OFILE)\
 			$(LIBODIR)$(SLASH)js_system.$(OFILE)\
 			$(LIBODIR)$(SLASH)js_user.$(OFILE)\
diff --git a/src/sbbs3/sbbs.dsp b/src/sbbs3/sbbs.dsp
index 99a2ec2295..18b82ebf66 100644
--- a/src/sbbs3/sbbs.dsp
+++ b/src/sbbs3/sbbs.dsp
@@ -286,6 +286,10 @@ SOURCE=.\js_msgbase.c
 # End Source File
 # Begin Source File
 
+SOURCE=.\js_server.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\js_socket.c
 # End Source File
 # Begin Source File
diff --git a/src/sbbs3/sbbs.h b/src/sbbs3/sbbs.h
index 1a9969f4aa..1f0934e76c 100644
--- a/src/sbbs3/sbbs.h
+++ b/src/sbbs3/sbbs.h
@@ -887,12 +887,19 @@ extern "C" {
 		int				ver;		/* version added/modified */
 	} jsSyncPropertySpec;
 
-
 	typedef struct {
 		const char*		name;
 		int				val;
 	} jsConstIntSpec;
 
+	typedef struct {
+		char		version[128];
+		const char*	version_detail;
+		DWORD*		interface_addr;
+		DWORD*		options;
+		DWORD*		clients;
+	} js_server_props_t;
+
 	#define JSTYPE_ARRAY JSTYPE_LIMIT
 	#define JSTYPE_ALIAS JSTYPE_LIMIT+1
 
@@ -911,6 +918,10 @@ extern "C" {
 	DLLEXPORT JSBool	DLLCALL js_CreateArrayOfStrings(JSContext* cx, JSObject* parent
 														,const char* name, char* str[], uintN flags);
 
+	/* js_server.c */
+	DLLEXPORT JSObject* DLLCALL js_CreateServerObject(JSContext* cx, JSObject* parent
+										,js_server_props_t* props);
+
 	/* js_global.c */
 	DLLEXPORT JSObject* DLLCALL js_CreateGlobalObject(JSContext* cx, scfg_t* cfg, jsSyncMethodSpec* methods);
 
diff --git a/src/sbbs3/services.c b/src/sbbs3/services.c
index 2661cdfafb..1b9fc60908 100644
--- a/src/sbbs3/services.c
+++ b/src/sbbs3/services.c
@@ -97,6 +97,7 @@ typedef struct {
 	DWORD	js_branch_limit;
 	DWORD	js_yield_interval;
 	DWORD	js_gc_interval;
+	js_server_props_t js_server_props;
 	/* These are run-time state and stat vars */
 	DWORD	clients;
 	DWORD	served;
@@ -757,12 +758,9 @@ js_client_remove(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *r
 static JSContext* 
 js_initcx(JSRuntime* js_runtime, SOCKET sock, service_client_t* service_client, JSObject** glob)
 {
-	char		ver[256];
 	JSContext*	js_cx;
 	JSObject*	js_glob;
 	JSObject*	server;
-	JSString*	js_str;
-	jsval		val;
 	BOOL		success=FALSE;
 
     if((js_cx = JS_NewContext(js_runtime, service_client->service->js_cx_stack))==NULL)
@@ -811,7 +809,11 @@ js_initcx(JSRuntime* js_runtime, SOCKET sock, service_client_t* service_client,
 
 		if(js_CreateSystemObject(js_cx, js_glob, &scfg, uptime, startup->host_name)==NULL) 
 			break;
-		
+#if 0		
+		char		ver[256];
+		JSString*	js_str;
+		jsval		val;
+
 		/* server object */
 		if((server=JS_DefineObject(js_cx, js_glob, "server", &js_server_class
 			,NULL,JSPROP_ENUMERATE|JSPROP_READONLY))==NULL)
@@ -820,14 +822,6 @@ js_initcx(JSRuntime* js_runtime, SOCKET sock, service_client_t* service_client,
 		if(!JS_DefineProperties(js_cx, server, js_server_properties))
 			break;
 
-		if(service_client->client==NULL)	/* static service */
-			if(js_CreateSocketObject(js_cx, server, "socket", service_client->socket)==NULL)
-				break;
-
-		JS_DefineFunction(js_cx, server, "client_add"	, js_client_add,	1, 0);
-		JS_DefineFunction(js_cx, server, "client_update", js_client_update,	1, 0);
-		JS_DefineFunction(js_cx, server, "client_remove", js_client_remove, 1, 0);
-
 		sprintf(ver,"Synchronet Services %s",revision);
 		if((js_str=JS_NewStringCopyZ(js_cx, ver))==NULL)
 			break;
@@ -841,6 +835,35 @@ js_initcx(JSRuntime* js_runtime, SOCKET sock, service_client_t* service_client,
 		if(!JS_SetProperty(js_cx, server, "version_detail", &val))
 			break;
 
+#else
+
+		if(service_client->service->js_server_props.version[0]==0) {
+			sprintf(service_client->service->js_server_props.version
+				,"Synchronet Services %s",revision);
+			service_client->service->js_server_props.version_detail=
+				services_ver();
+			service_client->service->js_server_props.clients=
+				&service_client->service->clients;
+			service_client->service->js_server_props.interface_addr=
+				&startup->interface_addr;
+			service_client->service->js_server_props.options=
+				&service_client->service->options;
+		}
+
+		if((server=js_CreateServerObject(js_cx,js_glob
+			,&service_client->service->js_server_props))==NULL)
+			break;
+#endif
+
+		if(service_client->client==NULL)	/* static service */
+			if(js_CreateSocketObject(js_cx, server, "socket", service_client->socket)==NULL)
+				break;
+
+		JS_DefineFunction(js_cx, server, "client_add"	, js_client_add,	1, 0);
+		JS_DefineFunction(js_cx, server, "client_update", js_client_update,	1, 0);
+		JS_DefineFunction(js_cx, server, "client_remove", js_client_remove, 1, 0);
+
+
 		if(glob!=NULL)
 			*glob=js_glob;
 
diff --git a/src/sbbs3/websrvr.c b/src/sbbs3/websrvr.c
index d237d541f3..e222c57e3e 100644
--- a/src/sbbs3/websrvr.c
+++ b/src/sbbs3/websrvr.c
@@ -102,6 +102,7 @@ static char		cgi_dir[MAX_PATH+1];
 static time_t	uptime=0;
 static DWORD	served=0;
 static web_startup_t* startup=NULL;
+static js_server_props_t js_server_props;
 
 typedef struct  {
 	char	*val;
@@ -2074,12 +2075,8 @@ static JSFunctionSpec js_global_functions[] = {
 static JSContext* 
 js_initcx(JSRuntime* runtime, SOCKET sock, JSObject** glob, http_session_t *session)
 {
-	char		ver[256];
 	JSContext*	js_cx;
 	JSObject*	js_glob;
-	JSObject*	server;
-	JSString*	js_str;
-	jsval		val;
 	BOOL		success=FALSE;
 
 	lprintf(LOG_INFO,"%04d JavaScript: Initializing context (stack: %lu bytes)"
@@ -2105,6 +2102,12 @@ js_initcx(JSRuntime* runtime, SOCKET sock, JSObject** glob, http_session_t *sess
 		if(js_CreateSystemObject(js_cx, js_glob, &scfg, uptime, startup->host_name)==NULL) 
 			break;
 
+#if 0
+		char		ver[256];
+		JSObject*	server;
+		JSString*	js_str;
+		jsval		val;
+
 		if((server=JS_DefineObject(js_cx, js_glob, "server", NULL,NULL
 			,JSPROP_ENUMERATE|JSPROP_READONLY))==NULL)
 			break;
@@ -2121,6 +2124,10 @@ js_initcx(JSRuntime* runtime, SOCKET sock, JSObject** glob, http_session_t *sess
 		val = STRING_TO_JSVAL(js_str);
 		if(!JS_SetProperty(js_cx, server, "version_detail", &val))
 			break;
+#else
+		if(js_CreateServerObject(js_cx,js_glob,&js_server_props)==NULL)
+			break;
+#endif
 
 		if(glob!=NULL)
 			*glob=js_glob;
@@ -2528,6 +2535,12 @@ void DLLCALL web_server(void* arg)
 	if(startup->js_cx_stack==0)				startup->js_cx_stack=JAVASCRIPT_CONTEXT_STACK;
 	if(startup->ssjs_ext[0]==0)				SAFECOPY(startup->ssjs_ext,"ssjs");
 
+	sprintf(js_server_props.version,"%s %s",server_name,revision);
+	js_server_props.version_detail=web_ver();
+	js_server_props.clients=&active_clients;
+	js_server_props.options=&startup->options;
+	js_server_props.interface_addr=&startup->interface_addr;
+
 	/* Copy html directories */
 	SAFECOPY(root_dir,startup->root_dir);
 	SAFECOPY(error_dir,startup->error_dir);
-- 
GitLab