From 1223da7d1010c9a322f7e9600104598b14f9cb9d Mon Sep 17 00:00:00 2001
From: rswindell <>
Date: Sat, 27 Aug 2011 21:22:07 +0000
Subject: [PATCH] request_telnet_opt() can now (optionally) block with timeout
 for the ack. telnet_gate() now enables the telnet command pass-through after
 negotiating necessary options. This doesn't quite fix the problem reported
 with telgating to nethack.alt.org, but it's a step in the right direction.

---
 src/sbbs3/main.cpp    | 24 ++++++++++++++++++------
 src/sbbs3/sbbs.h      |  4 +++-
 src/sbbs3/telgate.cpp | 14 +++++++-------
 3 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/src/sbbs3/main.cpp b/src/sbbs3/main.cpp
index 93e689ba13..99433cddd6 100644
--- a/src/sbbs3/main.cpp
+++ b/src/sbbs3/main.cpp
@@ -1311,13 +1311,16 @@ static BYTE* telnet_interpret(sbbs_t* sbbs, BYTE* inbuf, int inlen,
 
 				if(!(sbbs->telnet_mode&TELNET_MODE_GATE)) {
 					if(command==TELNET_DO || command==TELNET_DONT) {	/* local options */
-						if(sbbs->telnet_local_option[option]!=command) {
+						if(sbbs->telnet_local_option[option]==command) 
+							SetEvent(sbbs->telnet_ack_event);
+						else {
 							sbbs->telnet_local_option[option]=command;
 							sbbs->send_telnet_cmd(telnet_opt_ack(command),option);
 						}
 					} else { /* WILL/WONT (remote options) */ 
-						if(sbbs->telnet_remote_option[option]!=command) {	
-						
+						if(sbbs->telnet_remote_option[option]==command)	
+							SetEvent(sbbs->telnet_ack_event);
+						else {
 							switch(option) {
 								case TELNET_BINARY_TX:
 								case TELNET_ECHO:
@@ -1413,18 +1416,23 @@ void sbbs_t::send_telnet_cmd(uchar cmd, uchar opt)
 	}
 }
 
-void sbbs_t::request_telnet_opt(uchar cmd, uchar opt)
+bool sbbs_t::request_telnet_opt(uchar cmd, uchar opt, unsigned waitforack)
 {
 	if(cmd==TELNET_DO || cmd==TELNET_DONT) {	/* remote option */
 		if(telnet_remote_option[opt]==telnet_opt_ack(cmd))
-			return;	/* already set in this mode, do nothing */
+			return true;	/* already set in this mode, do nothing */
 		telnet_remote_option[opt]=telnet_opt_ack(cmd);
 	} else {	/* local option */
 		if(telnet_local_option[opt]==telnet_opt_ack(cmd))
-			return;	/* already set in this mode, do nothing */
+			return true;	/* already set in this mode, do nothing */
 		telnet_local_option[opt]=telnet_opt_ack(cmd);
 	}
+	if(waitforack)
+		ResetEvent(telnet_ack_event);
 	send_telnet_cmd(cmd,opt);
+	if(waitforack)
+		return WaitForEvent(telnet_ack_event, waitforack)==WAIT_OBJECT_0;
+	return true;
 }
 
 void input_thread(void *arg)
@@ -2880,6 +2888,7 @@ sbbs_t::sbbs_t(ushort node_num, DWORD addr, const char* name, SOCKET sd,
     telnet_cmdlen=0;
 	telnet_mode=0;
 	telnet_last_rxch=0;
+	telnet_ack_event=CreateEvent(NULL, /* Manual Reset: */FALSE,/* InitialState */FALSE,NULL);
 
 	sys_status=lncntr=tos=criterrs=slcnt=0L;
 	column=0;
@@ -3267,6 +3276,9 @@ sbbs_t::~sbbs_t()
 	if(!output_thread_running)
 		RingBufDispose(&outbuf);
 
+	if(telnet_ack_event!=NULL)
+		CloseEvent(telnet_ack_event);
+
 	/* Close all open files */
 	if(nodefile!=-1) {
 		close(nodefile);
diff --git a/src/sbbs3/sbbs.h b/src/sbbs3/sbbs.h
index 1d5a92ee73..6afa8aeefd 100644
--- a/src/sbbs3/sbbs.h
+++ b/src/sbbs3/sbbs.h
@@ -135,6 +135,7 @@ extern int	thread_suid_broken;			/* NPTL is no longer broken */
 #include "filewrap.h"
 #include "datewrap.h"
 #include "sockwrap.h"
+#include "eventwrap.h"
 #include "link_list.h"
 #include "msg_queue.h"
 #include "xpdatetime.h"
@@ -209,7 +210,7 @@ public:
 	uchar	telnet_local_option[0x100];
 	uchar	telnet_remote_option[0x100];
 	void	send_telnet_cmd(uchar cmd, uchar opt);
-	void	request_telnet_opt(uchar cmd, uchar opt);
+	bool	request_telnet_opt(uchar cmd, uchar opt, unsigned waitforack=0);
 
     uchar	telnet_cmd[64];
     uint	telnet_cmdlen;
@@ -217,6 +218,7 @@ public:
 	uchar	telnet_last_rxch;
 	char	telnet_location[128];
 	char	terminal[TELNET_TERM_MAXLEN+1];
+	xpevent_t	telnet_ack_event;
 
 	time_t	event_time;				// Time of next exclusive event
 	char*	event_code;				// Internal code of next exclusive event
diff --git a/src/sbbs3/telgate.cpp b/src/sbbs3/telgate.cpp
index 09d7f1a758..e427ae57d6 100644
--- a/src/sbbs3/telgate.cpp
+++ b/src/sbbs3/telgate.cpp
@@ -8,7 +8,7 @@
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
  *																			*
- * Copyright 2009 Rob Swindell - http://www.synchro.net/copyright.html		*
+ * Copyright 2011 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				*
@@ -115,9 +115,6 @@ void sbbs_t::telnet_gate(char* destaddr, ulong mode)
 		,mode&TG_RLOGIN ? "RLogin" : "Telnet"
 		,destaddr,port,remote_socket);
 
-	if(mode&(TG_PASSTHRU|TG_RLOGIN))
-		telnet_mode|=TELNET_MODE_GATE;	// Pass-through telnet commands
-
 	if(!(mode&TG_CTRLKEYS))
 		console|=CON_RAW_IN;
 
@@ -136,10 +133,13 @@ void sbbs_t::telnet_gate(char* destaddr, ulong mode)
 
 	/* This is required for gating to Unix telnetd */
 	if(mode&TG_NOTERMTYPE)
-		request_telnet_opt(TELNET_DONT,TELNET_TERM_TYPE);	// Re-negotiation of terminal type
+		request_telnet_opt(TELNET_DONT,TELNET_TERM_TYPE, 3000);	// Re-negotiation of terminal type
 
 	/* Text/NVT mode by default */
-	request_telnet_opt(TELNET_DONT,TELNET_BINARY_TX);
+	request_telnet_opt(TELNET_DONT,TELNET_BINARY_TX, 3000);
+
+	if(mode&(TG_PASSTHRU|TG_RLOGIN))
+		telnet_mode|=TELNET_MODE_GATE;	// Pass-through telnet commands
 
 	while(online) {
 		if(!(mode&TG_NOCHKTIME))
@@ -250,7 +250,7 @@ void sbbs_t::telnet_gate(char* destaddr, ulong mode)
 			p=dump;
 			for(int i=0;i<rd;i++)
 				p+=sprintf(p,"%u ",buf[i]);
-			lprintf(LOG_DEBUG,"Node %d Telnet cmd from remote: %s", cfg.node_num, dump);
+			lprintf(LOG_DEBUG,"Node %d Telnet cmd from server: %s", cfg.node_num, dump);
 		}
 #endif
 		RingBufWrite(&outbuf,buf,rd);
-- 
GitLab