ReactOS  0.4.12-dev-75-g00dd17e
ttelhndl.cpp
Go to the documentation of this file.
1 //Telnet Win32 : an ANSI telnet client.
3 //Copyright (C) 1998 Paul Brannan
4 //Copyright (C) 1998 I.Ioannou
5 //Copyright (C) 1997 Brad Johnson
6 //
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.
11 //
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.
16 //
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.
20 //
21 //I.Ioannou
22 //roryt@hol.gr
23 //
25 
27 //
28 // Module: ttelhndl.cpp
29 //
30 // Contents: Telnet Handler
31 //
32 // Product: telnet
33 //
34 // Revisions: August 30, 1998 Paul Brannan <pbranna@clemson.edu>
35 // June 15, 1998 pbranna@clemson.edu (Paul Brannan)
36 //
37 // This is code originally from tnnet.cpp and ansiprsr.cpp
38 //
40 
41 #include "precomp.h"
42 
43 #include "telnet.h"
44 
45 int naws_string(char *buf, int width, int height);
46 
47 // This helps make the code more readable (Paul Brannan 1/1/99)
48 #ifdef DEBUG_TELOPT
49 #define TELOPT_PRINTD(x) printit(x);
50 #define TELOPT_PRINTD2(x,n) { \
51  static char buf[20]; \
52  printit(s); \
53  printit(" "); \
54  itoa(d, buf, 10); \
55  printit(buf); \
56  printit("\n"); \
57 }
58 #else
59 #define TELOPT_PRINTD(x) ;
60 #define TELOPT_PRINTD2(x,n) ;
61 #endif
62 
63 // A new print function for debugging (Paul Brannan 5/15/98)
64 #ifdef DEBUG_TELOPT
65 void TTelnetHandler::print_telopt(const char *s, int d) {
66  static char buf[20];
67  printit(s);
68  printit(" ");
69  itoa(d, buf, 10);
70  printit(buf);
71  printit("\n");
72 }
73 #endif
74 
76  TParser &RefParser):
77 Network(RefNetwork), Console(RefConsole), Parser(RefParser) {
78  init();
79 
80  // Paul Brannan 9/13/98
82  szBuffer = new char [dwBuffer];
84 }
85 
87  iTermSet = 0;
88  bInBinaryRx = 0;
89  bInBinaryTx = 0;
90  bInEchoTx = 0;
91  bInEchoRx = 0;
93 }
94 
96  delete[] szBuffer;
97 }
98 
100  // The size of buffer must be greater than 2 * length to ensure no memory
101  // out of bounds errors. The 0xff is escaped into 0xff 0xff.
102  char * temp;
103  temp = new char [length * 2];
104  int current=0;
105  for (int x=0; x < length; x++){
106  if (buf[x] == (signed char)IAC)
107  temp[current++]=(char)IAC;
108  temp[current++]=buf[x];
109  }
110  memcpy( buf, temp, current);
111  delete [] temp;
112  return current;
113 }
114 
115 // This lets us get rid of all the printf's (Paul Brannan 5/15/98)
117  static char buf[2] = {IAC};
118  buf[1] = c;
119  Network.WriteString(buf, 2);
120 }
121 void TTelnetHandler::SendIAC(char c1, char c2) {
122  static char buf[3] = {IAC};
123  buf[1] = c1; buf[2] = c2;
124  Network.WriteString(buf, 3);
125 }
127  static char buf[2];
128  buf[0] = c;
129  static int length = escapeIAC(buf, 1);
130  Network.WriteString(buf, length);
131 }
132 void TTelnetHandler::SendIACParams(char c1, char c2) {
133  static char buf[4];
134  buf[0] = c1; buf[1] = c2;
135  static int length = escapeIAC(buf, 2);
136  Network.WriteString(buf, length);
137 }
138 
139 int naws_string(char *b, int width, int height) {
140  int l = 0;
141  unsigned char *buf = (unsigned char *)b;
142 
143  union {
144  char szResponse[2];
145  int n;
146  };
147 
148  buf[l++] = IAC;
149  buf[l++] = SB;
150  buf[l++] = TELOPT_NAWS;
151 
152  n = width;
153  buf[l] = szResponse[1];
154  if(buf[l-1] == IAC) buf[l++] = IAC;
155  buf[l++] = szResponse[0];
156  if(buf[l-1] == IAC) buf[l++] = IAC;
157 
158  n = height;
159  buf[l++] = szResponse[1];
160  if(buf[l-1] == IAC) buf[l++] = IAC;
161  buf[l++] = szResponse[0];
162  if(buf[l-1] == IAC) buf[l++] = IAC;
163 
164  buf[l++] = IAC;
165  buf[l++] = SE;
166 
167  return l;
168 }
169 
170 // Ioannou 29 May 1998 : Something strange happens with
171 // Borland compiler at this point when it passes the arguments
172 // to SendIACParams. It always sends 80 lines to the server !!!
173 // There seems to be a bug with optimization (the disassemble shows
174 // that it uses an address plus 0xa than the right one).
175 // This turns them off for this point.
176 #ifdef __BORLANDC__
177 #pragma -O-
178 #endif
179 
180 // Removed old printf code that was commented out to clean this function
181 // up a bit (Paul brannan 6/15/98)
182 char* TTelnetHandler::ParseIAC(char* pszBuffer, char* pszBufferEnd)
183 {
184  // int n,l;
185  // char szResponse[40];
186  // Ioannou 29 May 1998 : I prefer the union redefinitions
187  // than the typecasting (used with them from Pascal and Cobol :-) )
188  // FIX ME !!!! Shall we use the winsock routines instead ?
189 
190  union {
191  char szResponse[2];
192  int n;
193  };
194 
195  // Added support for user-defined term name (Paul Brannan 5/13/98)
196 #define LASTTERM 4
197  const char *pszTerms[] = {ini.get_term(), "ANSI","DEC-VT100","DEC-VT52","UNKNOWN"};
198  if(!iTermSet && (pszTerms[0] == 0 || *pszTerms[0] == 0)) iTermSet++;
199 
200  if (pszBuffer + 2 < pszBufferEnd) {
201  switch ((unsigned char)pszBuffer[1]) {
202 
204  case DO:
205  {
206  switch (pszBuffer[2]){
207  case TELOPT_BINARY:
208  TELOPT_PRINTD("RCVD DO TELOPT_BINARY\n");
209  if (!bInBinaryRx){
211  bInBinaryRx = 1;
212  TELOPT_PRINTD("SENT WILL TELOPT_BINARY\n");
213  }
214  break;
215  case TELOPT_ECHO:
216  // we shouldn't echo for the server! (Paul Brannan 5/30/98)
217  TELOPT_PRINTD2("RCVD DO TELOPT_ECHO", pszBuffer[2]);
219  TELOPT_PRINTD("SENT WONT TELOPT_ECHO\n");
220  break;
221  case TELOPT_TTYPE:
222  TELOPT_PRINTD("RCVD DO TELOPT_TTYPE\n");
224  TELOPT_PRINTD("SENT WILL TELOPT_TTYPE\n");
225  break;
226  case TELOPT_NAWS:
227  TELOPT_PRINTD("RCVD DO TELOPT_NAWS\n");
230 
232 
233  n = Console.GetWidth();
234  SendIACParams(szResponse[1],szResponse [0]);
235 
236  n = Console.GetHeight();
237  SendIACParams(szResponse[1],szResponse[0]);
238 
239  SendIAC(SE);
240  TELOPT_PRINTD("SENT WILL TELOPT_NAWS\n");
241  break;
242  case TELOPT_XDISPLOC:
243  TELOPT_PRINTD("RCVD DO TELOPT_XDISPLOC\n");
245  TELOPT_PRINTD("SENT WILL TELOPT_XDISPLOC\n");
246  printit("Retrieving IP...");
247  break;
248  default:
249  TELOPT_PRINTD2("RCVD DO", pszBuffer[2]);
250  SendIAC(WONT, pszBuffer[2]);
251  TELOPT_PRINTD2("SENT WONT", pszBuffer[2]);
252  break;
253  }
254  if (pszBuffer + 2 < pszBufferEnd)
255  pszBuffer += 3;
256  break;
257  }
258 
260  case WILL:
261  {
262  switch ((unsigned char)pszBuffer[2]){
263  case TELOPT_BINARY:
264  TELOPT_PRINTD("RCVD WILL TELOPT_BINARY\n");
265  if (!bInBinaryTx){
267  bInBinaryTx = 1;
268  TELOPT_PRINTD("SENT DO TELOPT_BINARY\n");
269  }
270  break;
271  case TELOPT_ECHO:
272  TELOPT_PRINTD2("RCVD WILL TELOPT_ECHO", pszBuffer[2]);
273  if(!bInEchoRx) {
275  bInEchoRx = 1;
276  Network.set_local_echo(0); // Paul Brannan 8/25/98
278  TELOPT_PRINTD2("SENT DO TELOPT_ECHO", pszBuffer[2]);
280  }
281  break;
282 
283  // Suppress Go Ahead (Paul Brannan 12/31/98)
284  case TELOPT_SGA:
285  TELOPT_PRINTD("RCVD WILL TELOPT_SGA\n");
286  if(!iWillSGA) {
289  iWillSGA = 1;
290  TELOPT_PRINTD("SENT DO TELOPT_SGA\n");
291  }
292  break;
293 
295  default:
296  TELOPT_PRINTD2("RCVD WILL", pszBuffer[2]);
297  SendIAC(DONT, pszBuffer[2]);
298  TELOPT_PRINTD2("SENT DONT", pszBuffer[2]);
299  break;
301  }
302  if (pszBuffer + 2 < pszBufferEnd)
303  pszBuffer += 3;
304  break;
305  }
306 
308  case WONT:
309  {
310  switch ((unsigned char)pszBuffer[2]){
311  case TELOPT_ECHO:
312  TELOPT_PRINTD("RCVD WONT TELOPT_ECHO\n");
313  if (bInEchoRx){
315  // bInBinaryRx = 0;
316  bInEchoRx = 0; // Paul Brannan 8/25/98
319  TELOPT_PRINTD("SENT DONT TELOPT_ECHO\n");
320  }
321  break;
322 
323  // Suppress Go Ahead (Paul Brannan 12/31/98)
324  case TELOPT_SGA:
325  TELOPT_PRINTD("RCVD WONT TELOPT_SGA\n");
326  if(iWillSGA) {
329  iWillSGA = 0;
330  TELOPT_PRINTD("SENT DONT TELOPT_SGA\n");
331  }
332  break;
333 
334  default:
335  TELOPT_PRINTD2("RCVD WONT", pszBuffer[2]);
336  break;
337  }
338  if (pszBuffer + 2 < pszBufferEnd)
339  pszBuffer += 3;
340  break;
341  }
342 
344  case DONT:
345  {
346  switch ((unsigned char)pszBuffer[2]){
347  case TELOPT_ECHO:
348  TELOPT_PRINTD("RCVD DONT TELOPT_ECHO\n");
349  if (bInEchoTx){
351  bInEchoTx = 0;
352  TELOPT_PRINTD("SENT WONT TELOPT_ECHO\n");
353  }
354  break;
355  case TELOPT_NAWS:
356  TELOPT_PRINTD("RCVD DONT TELOPT_NAWS\n");
359  TELOPT_PRINTD("SENT WONT TELOPT_NAWS\n");
360  break;
361  default:
362  TELOPT_PRINTD2("RCVD DONT", pszBuffer[2]);
363  break;
364  }
365  if (pszBuffer + 2 < pszBufferEnd)
366  pszBuffer += 3;
367  break;
368  }
369 
371  case SB:
372  {
373  switch ((unsigned char)pszBuffer[2]){
374  case TELOPT_TTYPE:
375  if (pszBuffer + 5 < pszBufferEnd) {
376  TELOPT_PRINTD("RCVD SB TELOPT_TTYPE\n");
377  if (pszBuffer[3] == 1){
378  TELOPT_PRINTD("SENT SB TT");
379  TELOPT_PRINTD(pszTerms[iTermSet]);
380  TELOPT_PRINTD("\n");
382  SendIACParams(0);
383  Network.WriteString(pszTerms[iTermSet], strlen(pszTerms[iTermSet]));
384  SendIAC(SE);
385 
386  if (iTermSet < LASTTERM )
387  iTermSet+=1;
388  }
389  if (pszBuffer + 5 < pszBufferEnd)
390  pszBuffer += 6;
391  }
392  break;
393  case TELOPT_XDISPLOC:
394  if(pszBuffer + 5 < pszBufferEnd) {
395  TELOPT_PRINTD("RCVD SB XDISPLOC\n");
397  TELOPT_PRINTD("SENT SB XDISPLOC");
398  SendIACParams(0);
402  TELOPT_PRINTD("\n");
403  SendIAC(SE);
404  if (pszBuffer + 5 < pszBufferEnd)
405  pszBuffer += 6;
406  }
407  break;
408  default: break;
409  }
410  break;
411  }
412  default:
413  pszBuffer += 2;
414  break;
415  }
416  }
417  return pszBuffer;
418 }
419 
420 #ifdef __BORLANDC__
421 // bring bug optimazations
422 #pragma -O.
423 #endif
424 
425 // This is the code from TANSIParser::ParseBuffer. It parses out IACs, and
426 // then calls TParser::ParseBuffer to do the terminal emulation.
427 // (Paul Brannan 6/15/98)
428 // Hopefully eliminating the unnecessary copying should speed things up a
429 // little. (Paul Brannan 6/28/98)
430 char* TTelnetHandler::ParseBuffer(char* pszBuffer, char* pszBufferEnd){
431  char *pszResult;
432  char *pszHead = pszBuffer;
433 
435  while (pszBuffer < pszBufferEnd) {
436  // if IAC then parse IAC
437  if((unsigned char) *pszBuffer == IAC) {
438 
439  // check for escaped IAC
440  if((pszBufferEnd >= pszBuffer + 1) &&
441  (unsigned char)*(pszBuffer + 1) == IAC) {
442  // we move data at the front of the buffer to the end so
443  // that if we only have IACs we won't return pszBuffer
444  // even though we did parse something. Returning
445  // pszBuffer is an error condition.
446  memmove(pszHead + 1, pszHead, pszBuffer - pszHead);
447  pszBuffer+=2;
448  pszHead++;
449  }
450  // parse the IAC
451  else {
452  pszResult = ParseIAC(pszBuffer, pszBufferEnd);
453  if(pszBuffer == pszResult) return pszBuffer;
454  // see above regarding moving from front to end.
455  memmove(pszHead + (pszResult - pszBuffer), pszHead,
456  pszBuffer - pszHead);
457  pszHead += (pszResult - pszBuffer);
458  pszBuffer = pszResult;
459  }
460  }
461  // else copy char over to ANSI buffer
462  else {
463  pszBuffer++;
464  }
465  }
466 
467  // Not a socket connection, so don't parse out IACs.
468  // (Paul Brannan 3/19/99)
469  } else {
470  pszBuffer = pszBufferEnd;
471  }
472 
473  return(Parser.ParseBuffer(pszHead, pszBuffer));
474 }
475 
476 // telProcessNetwork calls the member function TTelnetHandler::Go, since
477 // TTelnetHandler::Go is not a static function, and cannot be called with
478 // CreateThread(). (Paul Brannan 6/15/98)
480  TelThreadParams *pParams = (TelThreadParams *)lpParameter;
481  return pParams->TelHandler.Go(&pParams->p);
482 }
483 
484 // This function is what used to be telProcessNetwork (Paul Brannan 6/15/98)
486 {
487  NetParams *pParams = (NetParams *)pvParams;
488 
489  // No longer a need to copy pParams-> socket and create an instance
490  // of TANSIParser (Paul Brannan 6/15/98)
491 
492  Console.sync(); // Sync with the parser so the cursor is positioned
493 
494  Parser.Init(); // Reset the parser (Paul Brannan 9/19/98)
495  init(); // Turn on local echo (Paul Brannan 9/19/98)
496 
497  *pParams->bNetFinished = 0;
498  char* pszHead = szBuffer;
499  char* pszTail = szBuffer;
500  while (!*pParams->bNetFinish) {
501  // Get data from Socket
502  *pParams->bNetPaused = 1; //Pause
503  int Result = Network.ReadString(pszTail, (szBuffer + dwBuffer) - pszTail);
504 
505  // Speed up mouse by not going into loop (Paul Brannan 8/10/98)
506  // while(*pParams->bNetPause && !*pParams->bNetFinish) *pParams->bNetPaused = 1; //Pause
507  if(WaitForSingleObject(pParams->hPause, 0) == WAIT_OBJECT_0)
509 
510  *pParams->bNetPaused = 0; //UnPause
511 
512  if (Result <= 0 || Result > dwBuffer ){
513  break;
514  }
515  pszTail += Result;
516 
517  // Process the buffer
518  char* pszNewHead = pszHead;
519  do {
520  // Speed up mouse by not going into loop (Paul Brannan 8/10/98)
521  if(WaitForSingleObject(pParams->hPause, 0) == WAIT_OBJECT_0) {
522  *pParams->bNetPaused = 1;
524  *pParams->bNetPaused = 0;
525  }
526 
527  pszHead = pszNewHead;
528  pszNewHead = ParseBuffer(pszHead, pszTail); // Parse buffer
529  } while ((pszNewHead != pszHead) && (pszNewHead < pszTail) && !*pParams->bNetFinish);
530  pszHead = pszNewHead;
531 
532  // When we reach the end of the buffer, move contents to the
533  // beginning of the buffer to get free space at the end.
534  if (pszTail == (szBuffer + dwBuffer)) {
535  memmove(szBuffer, pszHead, pszTail - pszHead);
536  pszTail = szBuffer + (pszTail - pszHead);
537  pszHead = szBuffer;
538  }
539  }
540  SetEvent(pParams->hExit);
541 
543  *pParams->bNetPaused = 1; //Pause
544  *pParams->bNetFinished = 1;
545  return 0;
546 }
TTelnetHandler & TelHandler
Definition: tparams.h:20
DWORD Go(LPVOID pvParams)
Definition: ttelhndl.cpp:485
#define LASTTERM
GLint GLint GLsizei width
Definition: gl.h:1546
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
TConsole & Console
Definition: ttelhndl.h:27
int get_buffer_size() const
Definition: tnconfig.h:62
HANDLE hUnPause
Definition: tparams.h:7
void SendIAC(char c)
Definition: ttelhndl.cpp:116
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
const char * get_term() const
Definition: tnconfig.h:37
#define DONT
Definition: ftp_var.h:14
void sync()
Definition: tconsole.cpp:109
int bInBinaryTx
Definition: ttelhndl.h:11
void set_local_echo(BOOL b)
Definition: tnetwork.h:41
const char * GetLocalAddress()
Definition: tnetwork.h:33
#define TELOPT_ECHO
Definition: telnet.h:71
TParser & Parser
Definition: ttelhndl.h:28
void SetNawsFunc(Naws_func_t func)
Definition: tnetwork.h:31
#define WILL
Definition: ftp_var.h:17
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:679
virtual char * ParseBuffer(char *pszBuffer, char *pszBufferEnd)=0
int escapeIAC(char *buf, int length)
Definition: ttelhndl.cpp:99
void SendIACParams(char c)
Definition: ttelhndl.cpp:126
TNetwork & Network
Definition: ttelhndl.h:26
DWORD WINAPI telProcessNetwork(LPVOID lpParameter)
Definition: ttelhndl.cpp:479
#define TELOPT_PRINTD2(x, n)
Definition: ttelhndl.cpp:60
NetParams p
Definition: tparams.h:19
volatile int * bNetPaused
Definition: tparams.h:8
#define DO
Definition: ftp_var.h:15
GLuint n
Definition: s_context.h:57
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
BOOL get_local_echo()
Definition: tnetwork.h:40
smooth NULL
Definition: ftsmooth.c:416
unsigned char
Definition: typeof.h:27
TTelnetHandler(TNetwork &RefNetwork, TConsole &RefConsole, TParser &RefParser)
Definition: ttelhndl.cpp:75
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:426
int bInBinaryRx
Definition: ttelhndl.h:11
char * ParseBuffer(char *pszBuffer, char *pszBufferEnd)
Definition: ttelhndl.cpp:430
#define MSG_TERMBYREM
Definition: resource.h:15
char * ParseIAC(char *pszBuffer, char *pszBufferEnd)
Definition: ttelhndl.cpp:182
r l[0]
Definition: byte_order.h:167
TConfig ini
Definition: tnconfig.cpp:45
_CRTIMP char *__cdecl itoa(_In_ int _Val, _Pre_notnull_ _Post_z_ char *_DstBuf, _In_ int _Radix)
virtual void Init()=0
#define TELOPT_TTYPE
Definition: telnet.h:94
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
int WriteString(const char *str, const int length)
Definition: tnetwork.cpp:53
#define WAIT_OBJECT_0
Definition: winbase.h:387
#define d
Definition: ke_i.h:81
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
#define TELOPT_SGA
Definition: telnet.h:73
#define TELOPT_XDISPLOC
Definition: telnet.h:105
const GLubyte * c
Definition: glext.h:8905
unsigned long DWORD
Definition: ntddk_ex.h:95
int printit(const char *it)
Definition: tnerror.cpp:58
NetworkType get_net_type()
Definition: tnetwork.h:35
#define SB
Definition: ftp_var.h:18
int ReadString(char *str, const int length)
Definition: tnetwork.cpp:67
int GetWidth()
Definition: tconsole.h:81
LPVOID lpParameter
Definition: kernel32.h:232
#define TELOPT_BINARY
Definition: telnet.h:70
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLdouble s
Definition: gl.h:2039
int printm(LPTSTR szModule, BOOL fSystem, DWORD dwMessageId,...)
Definition: tnerror.cpp:84
static stack_node_t temp
Definition: rpn.c:18
#define WINAPI
Definition: msvc.h:20
#define SE
Definition: ftp_var.h:28
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
char * szBuffer
Definition: ttelhndl.h:34
INT x
Definition: msvc.h:62
int naws_string(char *buf, int width, int height)
Definition: ttelhndl.cpp:139
HANDLE hExit
Definition: tparams.h:6
HANDLE hPause
Definition: tparams.h:7
#define IAC
Definition: ftp_var.h:13
#define TELOPT_PRINTD(x)
Definition: ttelhndl.cpp:59
#define c
Definition: ke_i.h:80
volatile int * bNetFinished
Definition: tparams.h:9
volatile int * bNetFinish
Definition: tparams.h:10
#define WONT
Definition: ftp_var.h:16
#define INFINITE
Definition: serial.h:102
void set_line_mode(BOOL b)
Definition: tnetwork.h:44
#define TELOPT_NAWS
Definition: telnet.h:101
void print_telopt(const char *s, int d)
struct task_struct * current
Definition: linux.c:32
int GetHeight()
Definition: tconsole.h:82