From 564b10b6c344def702d0f218f01fdbbb66bd31e6 Mon Sep 17 00:00:00 2001
From: "Rob Swindell (on Windows 11)" <rob@synchro.net>
Date: Fri, 9 Aug 2024 21:19:38 -0700
Subject: [PATCH] Add optional array argument to bbs.telnet_gate() and
 bbs.rlogin_gate()

If an array argument is passed to these methods, the stringified contents of
each array element value will be sent to the remote server after connecting.

This is to support Nelgin's request of sending some strings to a server after
connecting. There's no way to insert pauses between the sent strings or wait
for certain output from the remote - that's beyond this scope/capability.
---
 src/sbbs3/js_bbs.cpp  | 60 +++++++++++++++++++++++++++++++++++++------
 src/sbbs3/sbbs.h      |  3 ++-
 src/sbbs3/telgate.cpp |  7 ++++-
 3 files changed, 60 insertions(+), 10 deletions(-)

diff --git a/src/sbbs3/js_bbs.cpp b/src/sbbs3/js_bbs.cpp
index 84aeff05f1..974d0faf65 100644
--- a/src/sbbs3/js_bbs.cpp
+++ b/src/sbbs3/js_bbs.cpp
@@ -2989,11 +2989,13 @@ static JSBool
 js_telnet_gate(JSContext *cx, uintN argc, jsval *arglist)
 {
 	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((sbbs=js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist)))==NULL)
@@ -3009,22 +3011,45 @@ js_telnet_gate(JSContext *cx, uintN argc, jsval *arglist)
 	if(addr==NULL)
 		return(JS_FALSE);
 
-	if(argc>1 && JSVAL_IS_NUMBER(argv[1])) {
-		if(!JS_ValueToECMAUint32(cx,argv[1],&mode)) {
+	argn = 1;
+	if(argc > argn && JSVAL_IS_NUMBER(argv[argn])) {
+		if(!JS_ValueToECMAUint32(cx,argv[argn],&mode)) {
 			free(addr);
 			return JS_FALSE;
 		}
+		++argn;
 	}
-	if(argc>2 && JSVAL_IS_NUMBER(argv[2])) {
-		if(!JS_ValueToECMAUint32(cx,argv[2],&timeout)) {
+	if(argc > argn && JSVAL_IS_NUMBER(argv[argn])) {
+		if(!JS_ValueToECMAUint32(cx,argv[argn],&timeout)) {
 			free(addr);
 			return JS_FALSE;
 		}
+		++argn;
+	}
+	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)) {
+			send_strings = strListInit();
+			char* tmp = NULL;
+			size_t tmplen = 0;
+			for(jsuint i = 0; i < count; ++i) {
+				jsval val;
+				if(!JS_GetElement(cx, array, i, &val))
+					break;
+				JSVALUE_TO_RASTRING(cx, val, tmp, &tmplen, NULL);
+				HANDLE_PENDING(cx, tmp);
+				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)));
+	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(sbbs->telnet_gate(addr, mode, timeout, send_strings)));
 	free(addr);
+	strListFree(&send_strings);
 	JS_RESUMEREQUEST(cx, rc);
 
 	return(JS_TRUE);
@@ -3045,6 +3070,7 @@ js_rlogin_gate(JSContext *cx, uintN argc, jsval *arglist)
 	uint32		timeout = 10;
 	JSString*	js_str;
 	sbbs_t*		sbbs;
+	str_list_t	send_strings = NULL;
 	jsrefcount	rc;
 
 	if((sbbs=js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist)))==NULL)
@@ -3086,6 +3112,23 @@ js_rlogin_gate(JSContext *cx, uintN argc, jsval *arglist)
 					break;
 				}
 			}
+		} 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)) {
+				send_strings = strListInit();
+				char* tmp = NULL;
+				size_t tmplen = 0;
+				for(jsuint i = 0; i < count; ++i) {
+					jsval val;
+					if(!JS_GetElement(cx, array, i, &val))
+						break;
+					JSVALUE_TO_RASTRING(cx, val, tmp, &tmplen, NULL);
+					HANDLE_PENDING(cx, tmp);
+					strListPush(&send_strings, tmp);
+				}
+				free(tmp);
+			}
 		}
 	}
 	if(!fail) {
@@ -3093,13 +3136,14 @@ js_rlogin_gate(JSContext *cx, uintN argc, jsval *arglist)
 			mode = 0;
 		rc=JS_SUSPENDREQUEST(cx);
 		JS_SET_RVAL(cx, arglist
-			,BOOLEAN_TO_JSVAL(sbbs->telnet_gate(addr,mode|TG_RLOGIN,timeout,client_user_name,server_user_name,term_type)));
+			,BOOLEAN_TO_JSVAL(sbbs->telnet_gate(addr, mode|TG_RLOGIN, timeout, send_strings, client_user_name, server_user_name, term_type)));
 		JS_RESUMEREQUEST(cx, rc);
 	}
 	FREE_AND_NULL(addr);
 	FREE_AND_NULL(client_user_name);
 	FREE_AND_NULL(server_user_name);
 	FREE_AND_NULL(term_type);
+	strListFree(&send_strings);
 
 	return(fail ? JS_FALSE : JS_TRUE);
 }
@@ -4765,12 +4809,12 @@ static jsSyncMethodSpec js_bbs_functions[] = {
 	"(see <tt>EVENT_*</tt> in <tt>sbbsdefs.js</tt> for valid values)")
 	,310
 	},
-	{"telnet_gate",		js_telnet_gate,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("address[:port] [,<i>number</i> mode=TG_NONE] [,<i>number</i> timeout=10]")
+	{"telnet_gate",		js_telnet_gate,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("address[:port] [,<i>number</i> mode=TG_NONE] [,<i>number</i> timeout=10] [,<i>array<i> send_strings]")
 	,JSDOCSTR("External Telnet gateway (see <tt>TG_*</tt> in <tt>sbbsdefs.js</tt> for valid <i>mode</i> flags).")
 	,310
 	},
 	{"rlogin_gate",		js_rlogin_gate,		1,	JSTYPE_BOOLEAN
-	,JSDOCSTR("address[:port] [,<i>string</i> client-user-name=<i>user.alias</i>, <i>string</i> server-user-name=<i>user.name</i>, <i>string</i> terminal=<i>console.terminal</i>] [,<i>number</i> mode=TG_NONE]  [,<i>number</i> timeout=10]")
+	,JSDOCSTR("address[:port] [,<i>string</i> client-user-name=<i>user.alias</i>, <i>string</i> server-user-name=<i>user.name</i>, <i>string</i> terminal=<i>console.terminal</i>] [,<i>number</i> mode=TG_NONE]  [,<i>number</i> timeout=10]  [,<i>array<i> send_strings]")
 	,JSDOCSTR("External RLogin gateway (see <tt>TG_*</tt> in <tt>sbbsdefs.js</tt> for valid <i>mode</i> flags).")
 	,316
 	},
diff --git a/src/sbbs3/sbbs.h b/src/sbbs3/sbbs.h
index cc409019c9..6082e80fd6 100644
--- a/src/sbbs3/sbbs.h
+++ b/src/sbbs3/sbbs.h
@@ -1337,7 +1337,8 @@ public:
 	void	catsyslog(int crash);
 
 	/* telgate.cpp */
-	bool	telnet_gate(char* addr, uint mode, unsigned timeout=10, char* client_user_name=NULL, char* server_user_name=NULL, char* term_type=NULL);	// See TG_* for mode bits
+	bool	telnet_gate(char* addr, uint mode, unsigned timeout=10 	// See TG_* for mode bits
+		,str_list_t send_strings=NULL, char* client_user_name=NULL, char* server_user_name=NULL, char* term_type=NULL);
 
 	/* sftp.cpp */
 	bool init_sftp(int channel_id);
diff --git a/src/sbbs3/telgate.cpp b/src/sbbs3/telgate.cpp
index 109b454c95..33cdbb8104 100644
--- a/src/sbbs3/telgate.cpp
+++ b/src/sbbs3/telgate.cpp
@@ -216,7 +216,7 @@ struct TelnetProxy
 }; // struct TelnetProxy
 
 
-bool sbbs_t::telnet_gate(char* destaddr, uint mode, unsigned timeout, char* client_user_name, char* server_user_name, char* term_type)
+bool sbbs_t::telnet_gate(char* destaddr, uint mode, unsigned timeout, str_list_t send_strings, char* client_user_name, char* server_user_name, char* term_type)
 {
 	char*	p;
 	uchar	buf[512];
@@ -331,6 +331,11 @@ bool sbbs_t::telnet_gate(char* destaddr, uint mode, unsigned timeout, char* clie
 	if(!(telnet_mode&TELNET_MODE_OFF) && (mode&TG_PASSTHRU))
 		telnet_mode|=TELNET_MODE_GATE;	// Pass-through telnet commands
 
+	if(send_strings != NULL) {
+		for(i = 0; send_strings[i] != NULL; ++i)
+			sendsocket(remote_socket, send_strings[i], strlen(send_strings[i]));
+	}
+
 	while(online) {
 		if(!(mode&TG_NOCHKTIME))
 			gettimeleft();
-- 
GitLab