cdbb1f7acea232bd46731e21347fa93ea433f7cf
1 ///////////////////////////////////////////////////////////////////////////////
2 //Telnet Win32 : an ANSI telnet client.
3 //Copyright (C) 1998 Paul Brannan
4 //Copyright (C) 1998 I.Ioannou
5 //Copyright (C) 1997 Brad Johnson
7 //This program is free software; you can redistribute it and/or
8 //modify it under the terms of the GNU General Public License
9 //as published by the Free Software Foundation; either version 2
10 //of the License, or (at your option) any later version.
12 //This program is distributed in the hope that it will be useful,
13 //but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 //GNU General Public License for more details.
17 //You should have received a copy of the GNU General Public License
18 //along with this program; if not, write to the Free Software
19 //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 ///////////////////////////////////////////////////////////////////////////
26 ///////////////////////////////////////////////////////////////////////////////
28 // Module: ttelhndl.cpp
30 // Contents: Telnet Handler
34 // Revisions: August 30, 1998 Paul Brannan <pbranna@clemson.edu>
35 // June 15, 1998 pbranna@clemson.edu (Paul Brannan)
37 // This is code originally from tnnet.cpp and ansiprsr.cpp
39 ///////////////////////////////////////////////////////////////////////////////
47 int naws_string(char *buf
, int width
, int height
);
49 // This helps make the code more readable (Paul Brannan 1/1/99)
51 #define TELOPT_PRINTD(x) printit(x);
52 #define TELOPT_PRINTD2(x,n) { \
53 static char buf[20]; \
61 #define TELOPT_PRINTD(x) ;
62 #define TELOPT_PRINTD2(x,n) ;
65 // A new print function for debugging (Paul Brannan 5/15/98)
67 void TTelnetHandler::print_telopt(const char *s
, int d
) {
77 TTelnetHandler::TTelnetHandler(TNetwork
&RefNetwork
, TConsole
&RefConsole
,
79 Network(RefNetwork
), Console(RefConsole
), Parser(RefParser
) {
82 // Paul Brannan 9/13/98
83 dwBuffer
= ini
.get_buffer_size();
84 szBuffer
= new char [dwBuffer
];
85 Network
.SetNawsFunc(NULL
);
88 void TTelnetHandler::init() {
94 Network
.set_local_echo(1);
97 TTelnetHandler::~TTelnetHandler() {
101 int TTelnetHandler::escapeIAC(char *buf
, int length
){
102 // The size of buffer must be greater than 2 * length to ensure no memory
103 // out of bounds errors. The 0xff is escaped into 0xff 0xff.
105 temp
= new char [length
* 2];
107 for (int x
=0; x
< length
; x
++){
108 if (buf
[x
] == (signed char)IAC
)
109 temp
[current
++]=(char)IAC
;
110 temp
[current
++]=buf
[x
];
112 memcpy( buf
, temp
, current
);
117 // This lets us get rid of all the printf's (Paul Brannan 5/15/98)
118 void TTelnetHandler::SendIAC(char c
) {
119 static char buf
[2] = {IAC
};
121 Network
.WriteString(buf
, 2);
123 void TTelnetHandler::SendIAC(char c1
, char c2
) {
124 static char buf
[3] = {IAC
};
125 buf
[1] = c1
; buf
[2] = c2
;
126 Network
.WriteString(buf
, 3);
128 void TTelnetHandler::SendIACParams(char c
) {
131 static int length
= escapeIAC(buf
, 1);
132 Network
.WriteString(buf
, length
);
134 void TTelnetHandler::SendIACParams(char c1
, char c2
) {
136 buf
[0] = c1
; buf
[1] = c2
;
137 static int length
= escapeIAC(buf
, 2);
138 Network
.WriteString(buf
, length
);
141 int naws_string(char *b
, int width
, int height
) {
143 unsigned char *buf
= (unsigned char *)b
;
152 buf
[l
++] = TELOPT_NAWS
;
155 buf
[l
] = szResponse
[1];
156 if(buf
[l
-1] == IAC
) buf
[l
++] = IAC
;
157 buf
[l
++] = szResponse
[0];
158 if(buf
[l
-1] == IAC
) buf
[l
++] = IAC
;
161 buf
[l
++] = szResponse
[1];
162 if(buf
[l
-1] == IAC
) buf
[l
++] = IAC
;
163 buf
[l
++] = szResponse
[0];
164 if(buf
[l
-1] == IAC
) buf
[l
++] = IAC
;
172 // Ioannou 29 May 1998 : Something strange happens with
173 // Borland compiler at this point when it passes the arguments
174 // to SendIACParams. It always sends 80 lines to the server !!!
175 // There seems to be a bug with optimization (the disassemble shows
176 // that it uses an address plus 0xa than the right one).
177 // This turns them off for this point.
182 // Removed old printf code that was commented out to clean this function
183 // up a bit (Paul brannan 6/15/98)
184 char* TTelnetHandler::ParseIAC(char* pszBuffer
, char* pszBufferEnd
)
187 // char szResponse[40];
188 // Ioannou 29 May 1998 : I prefer the union redefinitions
189 // than the typecasting (used with them from Pascal and Cobol :-) )
190 // FIX ME !!!! Shall we use the winsock routines instead ?
197 // Added support for user-defined term name (Paul Brannan 5/13/98)
199 const char *pszTerms
[] = {ini
.get_term(), "ANSI","DEC-VT100","DEC-VT52","UNKNOWN"};
200 if(!iTermSet
&& (pszTerms
[0] == 0 || *pszTerms
[0] == 0)) iTermSet
++;
202 if (pszBuffer
+ 2 < pszBufferEnd
) {
203 switch ((unsigned char)pszBuffer
[1]) {
205 ///////////////// DO ////////////////////
208 switch (pszBuffer
[2]){
210 TELOPT_PRINTD("RCVD DO TELOPT_BINARY\n");
212 SendIAC(WILL
, TELOPT_BINARY
);
214 TELOPT_PRINTD("SENT WILL TELOPT_BINARY\n");
218 // we shouldn't echo for the server! (Paul Brannan 5/30/98)
219 TELOPT_PRINTD2("RCVD DO TELOPT_ECHO", pszBuffer
[2]);
220 SendIAC(WONT
, TELOPT_ECHO
);
221 TELOPT_PRINTD("SENT WONT TELOPT_ECHO\n");
224 TELOPT_PRINTD("RCVD DO TELOPT_TTYPE\n");
225 SendIAC(WILL
, TELOPT_TTYPE
);
226 TELOPT_PRINTD("SENT WILL TELOPT_TTYPE\n");
229 TELOPT_PRINTD("RCVD DO TELOPT_NAWS\n");
230 SendIAC(WILL
, TELOPT_NAWS
);
231 SendIAC(SB
, TELOPT_NAWS
);
233 Network
.SetNawsFunc(naws_string
);
235 n
= Console
.GetWidth();
236 SendIACParams(szResponse
[1],szResponse
[0]);
238 n
= Console
.GetHeight();
239 SendIACParams(szResponse
[1],szResponse
[0]);
242 TELOPT_PRINTD("SENT WILL TELOPT_NAWS\n");
244 case TELOPT_XDISPLOC
:
245 TELOPT_PRINTD("RCVD DO TELOPT_XDISPLOC\n");
246 SendIAC(WILL
, TELOPT_XDISPLOC
);
247 TELOPT_PRINTD("SENT WILL TELOPT_XDISPLOC\n");
248 printit("Retrieving IP...");
251 TELOPT_PRINTD2("RCVD DO", pszBuffer
[2]);
252 SendIAC(WONT
, pszBuffer
[2]);
253 TELOPT_PRINTD2("SENT WONT", pszBuffer
[2]);
256 if (pszBuffer
+ 2 < pszBufferEnd
)
261 ///////////////// WILL ////////////////////
264 switch ((unsigned char)pszBuffer
[2]){
266 TELOPT_PRINTD("RCVD WILL TELOPT_BINARY\n");
268 SendIAC(DO
, TELOPT_BINARY
);
270 TELOPT_PRINTD("SENT DO TELOPT_BINARY\n");
274 TELOPT_PRINTD2("RCVD WILL TELOPT_ECHO", pszBuffer
[2]);
276 SendIAC(DO
, TELOPT_ECHO
);
278 Network
.set_local_echo(0); // Paul Brannan 8/25/98
279 if(iWillSGA
) Network
.set_line_mode(0);
280 TELOPT_PRINTD2("SENT DO TELOPT_ECHO", pszBuffer
[2]);
281 if(Network
.get_local_echo()) Network
.set_line_mode(0);
285 // Suppress Go Ahead (Paul Brannan 12/31/98)
287 TELOPT_PRINTD("RCVD WILL TELOPT_SGA\n");
289 SendIAC(DO
, TELOPT_SGA
);
290 if(bInEchoRx
) Network
.set_line_mode(0);
292 TELOPT_PRINTD("SENT DO TELOPT_SGA\n");
298 TELOPT_PRINTD2("RCVD WILL", pszBuffer
[2]);
299 SendIAC(DONT
, pszBuffer
[2]);
300 TELOPT_PRINTD2("SENT DONT", pszBuffer
[2]);
304 if (pszBuffer
+ 2 < pszBufferEnd
)
309 ///////////////// WONT ////////////////////
312 switch ((unsigned char)pszBuffer
[2]){
314 TELOPT_PRINTD("RCVD WONT TELOPT_ECHO\n");
316 SendIAC(DONT
, TELOPT_ECHO
);
318 bInEchoRx
= 0; // Paul Brannan 8/25/98
319 Network
.set_local_echo(1);
320 Network
.set_line_mode(0);
321 TELOPT_PRINTD("SENT DONT TELOPT_ECHO\n");
325 // Suppress Go Ahead (Paul Brannan 12/31/98)
327 TELOPT_PRINTD("RCVD WONT TELOPT_SGA\n");
329 SendIAC(DONT
, TELOPT_SGA
);
330 Network
.set_line_mode(0);
332 TELOPT_PRINTD("SENT DONT TELOPT_SGA\n");
337 TELOPT_PRINTD2("RCVD WONT", pszBuffer
[2]);
340 if (pszBuffer
+ 2 < pszBufferEnd
)
345 ///////////////// DONT ////////////////////
348 switch ((unsigned char)pszBuffer
[2]){
350 TELOPT_PRINTD("RCVD DONT TELOPT_ECHO\n");
352 SendIAC(WONT
, TELOPT_ECHO
);
354 TELOPT_PRINTD("SENT WONT TELOPT_ECHO\n");
358 TELOPT_PRINTD("RCVD DONT TELOPT_NAWS\n");
359 SendIAC(WONT
, TELOPT_NAWS
);
360 Network
.SetNawsFunc(naws_string
);
361 TELOPT_PRINTD("SENT WONT TELOPT_NAWS\n");
364 TELOPT_PRINTD2("RCVD DONT", pszBuffer
[2]);
367 if (pszBuffer
+ 2 < pszBufferEnd
)
372 ///////////////// SB ////////////////////
375 switch ((unsigned char)pszBuffer
[2]){
377 if (pszBuffer
+ 5 < pszBufferEnd
) {
378 TELOPT_PRINTD("RCVD SB TELOPT_TTYPE\n");
379 if (pszBuffer
[3] == 1){
380 TELOPT_PRINTD("SENT SB TT");
381 TELOPT_PRINTD(pszTerms
[iTermSet
]);
383 SendIAC(SB
, TELOPT_TTYPE
);
385 Network
.WriteString(pszTerms
[iTermSet
], strlen(pszTerms
[iTermSet
]));
388 if (iTermSet
< LASTTERM
)
391 if (pszBuffer
+ 5 < pszBufferEnd
)
395 case TELOPT_XDISPLOC
:
396 if(pszBuffer
+ 5 < pszBufferEnd
) {
397 TELOPT_PRINTD("RCVD SB XDISPLOC\n");
398 SendIAC(SB
, TELOPT_XDISPLOC
);
399 TELOPT_PRINTD("SENT SB XDISPLOC");
401 if(Network
.GetLocalAddress()) Network
.WriteString(Network
.GetLocalAddress(),
402 strlen(Network
.GetLocalAddress()));
403 TELOPT_PRINTD(Network
.GetLocalAddress());
406 if (pszBuffer
+ 5 < pszBufferEnd
)
423 // bring bug optimazations
427 // This is the code from TANSIParser::ParseBuffer. It parses out IACs, and
428 // then calls TParser::ParseBuffer to do the terminal emulation.
429 // (Paul Brannan 6/15/98)
430 // Hopefully eliminating the unnecessary copying should speed things up a
431 // little. (Paul Brannan 6/28/98)
432 char* TTelnetHandler::ParseBuffer(char* pszBuffer
, char* pszBufferEnd
){
434 char *pszHead
= pszBuffer
;
436 if(Network
.get_net_type() == TN_NETSOCKET
) {
437 while (pszBuffer
< pszBufferEnd
) {
438 // if IAC then parse IAC
439 if((unsigned char) *pszBuffer
== IAC
) {
441 // check for escaped IAC
442 if((pszBufferEnd
>= pszBuffer
+ 1) &&
443 (unsigned char)*(pszBuffer
+ 1) == IAC
) {
444 // we move data at the front of the buffer to the end so
445 // that if we only have IACs we won't return pszBuffer
446 // even though we did parse something. Returning
447 // pszBuffer is an error condition.
448 memmove(pszHead
+ 1, pszHead
, pszBuffer
- pszHead
);
454 pszResult
= ParseIAC(pszBuffer
, pszBufferEnd
);
455 if(pszBuffer
== pszResult
) return pszBuffer
;
456 // see above regarding moving from front to end.
457 memmove(pszHead
+ (pszResult
- pszBuffer
), pszHead
,
458 pszBuffer
- pszHead
);
459 pszHead
+= (pszResult
- pszBuffer
);
460 pszBuffer
= pszResult
;
463 // else copy char over to ANSI buffer
469 // Not a socket connection, so don't parse out IACs.
470 // (Paul Brannan 3/19/99)
472 pszBuffer
= pszBufferEnd
;
475 return(Parser
.ParseBuffer(pszHead
, pszBuffer
));
478 // telProcessNetwork calls the member function TTelnetHandler::Go, since
479 // TTelnetHandler::Go is not a static function, and cannot be called with
480 // CreateThread(). (Paul Brannan 6/15/98)
481 DWORD
telProcessNetwork(LPVOID pvParams
) {
482 TelThreadParams
*pParams
= (TelThreadParams
*)pvParams
;
483 return pParams
->TelHandler
.Go(&pParams
->p
);
486 // This function is what used to be telProcessNetwork (Paul Brannan 6/15/98)
487 DWORD
TTelnetHandler::Go(LPVOID pvParams
)
489 NetParams
*pParams
= (NetParams
*)pvParams
;
491 // No longer a need to copy pParams-> socket and create an instance
492 // of TANSIParser (Paul Brannan 6/15/98)
494 Console
.sync(); // Sync with the parser so the cursor is positioned
496 Parser
.Init(); // Reset the parser (Paul Brannan 9/19/98)
497 init(); // Turn on local echo (Paul Brannan 9/19/98)
499 *pParams
->bNetFinished
= 0;
500 char* pszHead
= szBuffer
;
501 char* pszTail
= szBuffer
;
502 while (!*pParams
->bNetFinish
) {
503 // Get data from Socket
504 *pParams
->bNetPaused
= 1; //Pause
505 int Result
= Network
.ReadString(pszTail
, (szBuffer
+ dwBuffer
) - pszTail
);
507 // Speed up mouse by not going into loop (Paul Brannan 8/10/98)
508 // while(*pParams->bNetPause && !*pParams->bNetFinish) *pParams->bNetPaused = 1; //Pause
509 if(WaitForSingleObject(pParams
->hPause
, 0) == WAIT_OBJECT_0
)
510 WaitForSingleObject(pParams
->hUnPause
, INFINITE
);
512 *pParams
->bNetPaused
= 0; //UnPause
514 if (Result
<= 0 || Result
> dwBuffer
){
519 // Process the buffer
520 char* pszNewHead
= pszHead
;
522 // Speed up mouse by not going into loop (Paul Brannan 8/10/98)
523 if(WaitForSingleObject(pParams
->hPause
, 0) == WAIT_OBJECT_0
) {
524 *pParams
->bNetPaused
= 1;
525 WaitForSingleObject(pParams
->hUnPause
, INFINITE
);
526 *pParams
->bNetPaused
= 0;
529 pszHead
= pszNewHead
;
530 pszNewHead
= ParseBuffer(pszHead
, pszTail
); // Parse buffer
531 } while ((pszNewHead
!= pszHead
) && (pszNewHead
< pszTail
) && !*pParams
->bNetFinish
);
532 pszHead
= pszNewHead
;
534 // When we reach the end of the buffer, move contents to the
535 // beginning of the buffer to get free space at the end.
536 if (pszTail
== (szBuffer
+ dwBuffer
)) {
537 memmove(szBuffer
, pszHead
, pszTail
- pszHead
);
538 pszTail
= szBuffer
+ (pszTail
- pszHead
);
542 SetEvent(pParams
->hExit
);
544 printm(0, FALSE
, MSG_TERMBYREM
);
545 *pParams
->bNetPaused
= 1; //Pause
546 *pParams
->bNetFinished
= 1;