1 #include "NativeFeatureIncludes.h"
2 #if _RAKNET_SUPPORT_TelnetTransport==1
3 
4 #include "TelnetTransport.h"
5 #include "TCPInterface.h"
6 #include <stdio.h>
7 #include <string.h>
8 #include <stdarg.h>
9 #include "LinuxStrings.h"
10 
11 // #define _PRINTF_DEBUG
12 
13 #define ECHO_INPUT
14 
15 #ifdef _MSC_VER
16 #pragma warning( push )
17 #endif
18 
TelnetTransport()19 TelnetTransport::TelnetTransport()
20 {
21 	tcpInterface=0;
22 	sendSuffix=0;
23 	sendPrefix=0;
24 }
~TelnetTransport()25 TelnetTransport::~TelnetTransport()
26 {
27 	Stop();
28 	if (sendSuffix)
29 		rakFree_Ex(sendSuffix, __FILE__, __LINE__ );
30 	if (sendPrefix)
31 		rakFree_Ex(sendPrefix, __FILE__, __LINE__ );
32 }
Start(unsigned short port,bool serverMode)33 bool TelnetTransport::Start(unsigned short port, bool serverMode)
34 {
35 	(void) serverMode;
36     AutoAllocate();
37 	RakAssert(serverMode);
38 	return tcpInterface->Start(port, 64);
39 }
Stop(void)40 void TelnetTransport::Stop(void)
41 {
42 	if (tcpInterface==0) return;
43 	tcpInterface->Stop();
44 	unsigned i;
45 	for (i=0; i < remoteClients.Size(); i++)
46 		RakNet::OP_DELETE(remoteClients[i], __FILE__, __LINE__);
47 	remoteClients.Clear(false, __FILE__, __LINE__);
48 	RakNet::OP_DELETE(tcpInterface, __FILE__, __LINE__);
49 	tcpInterface=0;
50 }
Send(SystemAddress systemAddress,const char * data,...)51 void TelnetTransport::Send(  SystemAddress systemAddress, const char *data,... )
52 {
53 	if (tcpInterface==0) return;
54 
55 	if (data==0 || data[0]==0)
56 		return;
57 
58 	char text[REMOTE_MAX_TEXT_INPUT];
59 	size_t prefixLength;
60 	if (sendPrefix)
61 	{
62 		strcpy(text, sendPrefix);
63 		prefixLength = strlen(sendPrefix);
64 	}
65 	else
66 	{
67 		text[0]=0;
68 		prefixLength=0;
69 	}
70 	va_list ap;
71 	va_start(ap, data);
72 	_vsnprintf(text+prefixLength, REMOTE_MAX_TEXT_INPUT-prefixLength, data, ap);
73 	va_end(ap);
74 	text[REMOTE_MAX_TEXT_INPUT-1]=0;
75 
76 	if (sendSuffix)
77 	{
78 		size_t length = strlen(text);
79 		size_t availableChars = REMOTE_MAX_TEXT_INPUT-length-1;
80 		strncat(text, sendSuffix, availableChars);
81 	}
82 
83 	tcpInterface->Send(text, (unsigned int) strlen(text), systemAddress, false);
84 }
CloseConnection(SystemAddress systemAddress)85 void TelnetTransport::CloseConnection( SystemAddress systemAddress )
86 {
87 	tcpInterface->CloseConnection(systemAddress);
88 }
Receive(void)89 Packet* TelnetTransport::Receive( void )
90 {
91 	if (tcpInterface==0) return 0;
92 	Packet *p = tcpInterface->Receive();
93 	if (p==0)
94 		return 0;
95 
96 	/*
97 	if (p->data[0]==255)
98 	{
99 		unsigned i;
100 		for (i=0; i < p->length; i++)
101 		{
102 			RAKNET_DEBUG_PRINTF("%i ", p->data[i]);
103 		}
104 		RAKNET_DEBUG_PRINTF("\n");
105 		tcpInterface->DeallocatePacket(p);
106 		return 0;
107 	}
108 	*/
109 
110 	// Get this guy's cursor buffer.  This is real bullcrap that I have to do this.
111 	unsigned i;
112 	TelnetClient *remoteClient=0;
113 	for (i=0; i < remoteClients.Size(); i++)
114 	{
115 		if (remoteClients[i]->systemAddress==p->systemAddress)
116 			remoteClient=remoteClients[i];
117 	}
118 	//RakAssert(remoteClient);
119 	if (remoteClient==0)
120 	{
121 		tcpInterface->DeallocatePacket(p);
122 		return 0;
123 	}
124 
125 
126 	if (p->length==3 && p->data[0]==27 && p->data[1]==91 && p->data[2]==65)
127 	{
128 		if (remoteClient->lastSentTextInput[0])
129 		{
130 			// Up arrow, return last string
131 			for (int i=0; remoteClient->textInput[i]; i++)
132 				remoteClient->textInput[i]=8;
133 			strcat(remoteClient->textInput, remoteClient->lastSentTextInput);
134 			tcpInterface->Send((const char *)remoteClient->textInput, strlen(remoteClient->textInput), p->systemAddress, false);
135 			strcpy(remoteClient->textInput,remoteClient->lastSentTextInput);
136 			remoteClient->cursorPosition=strlen(remoteClient->textInput);
137 		}
138 
139 		return 0;
140 	}
141 
142 
143 	// 127 is delete - ignore that
144 	// 9 is tab
145 	// 27 is escape
146 	if (p->data[0]>=127 || p->data[0]==9 || p->data[0]==27)
147 	{
148 		tcpInterface->DeallocatePacket(p);
149 		return 0;
150 	}
151 
152 	// Hack - I don't know what the hell this is about but cursor keys send 3 characters at a time.  I can block these
153 	//Up=27,91,65
154 	//Down=27,91,66
155 	//Right=27,91,67
156 	//Left=27,91,68
157 	if (p->length==3 && p->data[0]==27 && p->data[1]==91 && p->data[2]>=65 && p->data[2]<=68)
158 	{
159 		tcpInterface->DeallocatePacket(p);
160 		return 0;
161 	}
162 
163 
164 
165 	// Echo
166 #ifdef ECHO_INPUT
167 	tcpInterface->Send((const char *)p->data, p->length, p->systemAddress, false);
168 #endif
169 
170 	bool gotLine;
171 	// Process each character in turn
172 	for (i=0; i < p->length; i++)
173 	{
174 
175 #ifdef ECHO_INPUT
176 		if (p->data[i]==8)
177 		{
178 			char spaceThenBack[2];
179 			spaceThenBack[0]=' ';
180 			spaceThenBack[1]=8;
181 			tcpInterface->Send((const char *)spaceThenBack, 2, p->systemAddress, false);
182 		}
183 #endif
184 
185 		gotLine=ReassembleLine(remoteClient, p->data[i]);
186 		if (gotLine && remoteClient->textInput[0])
187 		{
188 
189 			Packet *reassembledLine = (Packet*) rakMalloc_Ex(sizeof(Packet), __FILE__, __LINE__);
190 			reassembledLine->length=(unsigned int) strlen(remoteClient->textInput);
191 			memcpy(remoteClient->lastSentTextInput, remoteClient->textInput, reassembledLine->length+1);
192 			RakAssert(reassembledLine->length < REMOTE_MAX_TEXT_INPUT);
193 			reassembledLine->data= (unsigned char*) rakMalloc_Ex( reassembledLine->length+1, __FILE__, __LINE__ );
194 			memcpy(reassembledLine->data, remoteClient->textInput, reassembledLine->length);
195 #ifdef _PRINTF_DEBUG
196 			memset(remoteClient->textInput, 0, REMOTE_MAX_TEXT_INPUT);
197 #endif
198 			reassembledLine->data[reassembledLine->length]=0;
199 			reassembledLine->systemAddress=p->systemAddress;
200 			tcpInterface->DeallocatePacket(p);
201 			return reassembledLine;
202 		}
203 	}
204 
205 	tcpInterface->DeallocatePacket(p);
206 	return 0;
207 }
DeallocatePacket(Packet * packet)208 void TelnetTransport::DeallocatePacket( Packet *packet )
209 {
210 	if (tcpInterface==0) return;
211 	rakFree_Ex(packet->data, __FILE__, __LINE__ );
212 	rakFree_Ex(packet, __FILE__, __LINE__ );
213 }
HasNewIncomingConnection(void)214 SystemAddress TelnetTransport::HasNewIncomingConnection(void)
215 {
216 	unsigned i;
217 	SystemAddress newConnection;
218 	newConnection = tcpInterface->HasNewIncomingConnection();
219 	// 03/16/06 Can't force the stupid windows telnet to use line mode or local echo so now I have to track all the remote players and their
220 	// input buffer
221 	if (newConnection != UNASSIGNED_SYSTEM_ADDRESS)
222 	{
223 		unsigned char command[10];
224 		// http://www.pcmicro.com/netfoss/RFC857.html
225 		// IAC WON'T ECHO
226 		command[0]=255; // IAC
227 		//command[1]=253; // WON'T
228 		command[1]=251; // WILL
229 		command[2]=1; // ECHO
230 		tcpInterface->Send((const char*)command, 3, newConnection, false);
231 
232 		/*
233 		// Tell the other side to use line mode
234 		// http://www.faqs.org/rfcs/rfc1184.html
235 		// IAC DO LINEMODE
236 	//	command[0]=255; // IAC
237 	//	command[1]=252; // DO
238 	//	command[2]=34; // LINEMODE
239 	//	tcpInterface->Send((const char*)command, 3, newConnection);
240 
241 	*/
242 
243 		TelnetClient *remoteClient=0;
244 		for (i=0; i < remoteClients.Size(); i++)
245 		{
246 			if (remoteClients[i]->systemAddress==newConnection)
247 			{
248 				remoteClient=remoteClients[i];
249 				remoteClient->cursorPosition=0;
250 			}
251 		}
252 
253 		if (remoteClient==0)
254 		{
255 			remoteClient=new TelnetClient;
256 			remoteClient->lastSentTextInput[0]=0;
257 			remoteClient->cursorPosition=0;
258 			remoteClient->systemAddress=newConnection;
259 #ifdef _PRINTF_DEBUG
260 			memset(remoteClient->textInput, 0, REMOTE_MAX_TEXT_INPUT);
261 #endif
262 		}
263 
264 		remoteClients.Insert(remoteClient, __FILE__, __LINE__);
265 	}
266 	return newConnection;
267 }
HasLostConnection(void)268 SystemAddress TelnetTransport::HasLostConnection(void)
269 {
270 	SystemAddress systemAddress;
271 	unsigned i;
272 	systemAddress=tcpInterface->HasLostConnection();
273 	if (systemAddress!=UNASSIGNED_SYSTEM_ADDRESS)
274 	{
275 		for (i=0; i < remoteClients.Size(); i++)
276 		{
277 			if (remoteClients[i]->systemAddress==systemAddress)
278 			{
279 				RakNet::OP_DELETE(remoteClients[i], __FILE__, __LINE__);
280 				remoteClients[i]=remoteClients[remoteClients.Size()-1];
281 				remoteClients.RemoveFromEnd();
282 			}
283 		}
284 	}
285 	return systemAddress;
286 }
GetCommandParser(void)287 CommandParserInterface* TelnetTransport::GetCommandParser(void)
288 {
289 	return 0;
290 }
SetSendSuffix(const char * suffix)291 void TelnetTransport::SetSendSuffix(const char *suffix)
292 {
293 	if (sendSuffix)
294 	{
295 		rakFree_Ex(sendSuffix, __FILE__, __LINE__ );
296 		sendSuffix=0;
297 	}
298 	if (suffix)
299 	{
300 		sendSuffix = (char*) rakMalloc_Ex(strlen(suffix)+1, __FILE__, __LINE__);
301 		strcpy(sendSuffix, suffix);
302 	}
303 }
SetSendPrefix(const char * prefix)304 void TelnetTransport::SetSendPrefix(const char *prefix)
305 {
306 	if (sendPrefix)
307 	{
308 		rakFree_Ex(sendPrefix, __FILE__, __LINE__ );
309 		sendPrefix=0;
310 	}
311 	if (prefix)
312 	{
313 		sendPrefix = (char*) rakMalloc_Ex(strlen(prefix)+1, __FILE__, __LINE__);
314 		strcpy(sendPrefix, prefix);
315 	}
316 }
AutoAllocate(void)317 void TelnetTransport::AutoAllocate(void)
318 {
319 	if (tcpInterface==0)
320 		tcpInterface=new TCPInterface;
321 }
ReassembleLine(TelnetTransport::TelnetClient * remoteClient,unsigned char c)322 bool TelnetTransport::ReassembleLine(TelnetTransport::TelnetClient* remoteClient, unsigned char c)
323 {
324 	if (c=='\n')
325 	{
326 		remoteClient->textInput[remoteClient->cursorPosition]=0;
327 		remoteClient->cursorPosition=0;
328 #ifdef _PRINTF_DEBUG
329 		RAKNET_DEBUG_PRINTF("[Done] %s\n", remoteClient->textInput);
330 #endif
331 		return true;
332 	}
333 	else if (c==8) // backspace
334 	{
335 		if (remoteClient->cursorPosition>0)
336 		{
337 			remoteClient->textInput[--remoteClient->cursorPosition]=0;
338 #ifdef _PRINTF_DEBUG
339 			RAKNET_DEBUG_PRINTF("[Back] %s\n", remoteClient->textInput);
340 #endif
341 		}
342 	}
343 	else if (c>=32 && c <127)
344 	{
345 		if (remoteClient->cursorPosition < REMOTE_MAX_TEXT_INPUT)
346 		{
347 			remoteClient->textInput[remoteClient->cursorPosition++]=c;
348 #ifdef _PRINTF_DEBUG
349 			RAKNET_DEBUG_PRINTF("[Norm] %s\n", remoteClient->textInput);
350 #endif
351 		}
352 	}
353 	return false;
354 }
355 
356 #ifdef _MSC_VER
357 #pragma warning( pop )
358 #endif
359 
360 #endif // _RAKNET_SUPPORT_*
361