Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547/////////////////////////////////////////////////////////////////////////////////Telnet Win32 : an ANSI telnet client.//Copyright (C) 1998 Paul Brannan//Copyright (C) 1998 I.Ioannou//Copyright (C) 1997 Brad Johnson////This program is free software; you can redistribute it and/or//modify it under the terms of the GNU General Public License//as published by the Free Software Foundation; either version 2//of the License, or (at your option) any later version.////This program is distributed in the hope that it will be useful,//but WITHOUT ANY WARRANTY; without even the implied warranty of//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the//GNU General Public License for more details.////You should have received a copy of the GNU General Public License//along with this program; if not, write to the Free Software//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.////I.Ioannou//roryt@hol.gr/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////// Module: ttelhndl.cpp//// Contents: Telnet Handler//// Product: telnet//// Revisions: August 30, 1998 Paul Brannan <pbranna@clemson.edu>// June 15, 1998 pbranna@clemson.edu (Paul Brannan)//// This is code originally from tnnet.cpp and ansiprsr.cpp/////////////////////////////////////////////////////////////////////////////////
#include "precomp.h"
#include "telnet.h"
int naws_string(char *buf, int width, int height);
// This helps make the code more readable (Paul Brannan 1/1/99)#ifdef DEBUG_TELOPT#define TELOPT_PRINTD(x) printit(x);#define TELOPT_PRINTD2(x,n) { \ static char buf[20]; \ printit(s); \ printit(" "); \ itoa(d, buf, 10); \ printit(buf); \ printit("\n"); \}#else#define TELOPT_PRINTD(x) ;#define TELOPT_PRINTD2(x,n) ;#endif
// A new print function for debugging (Paul Brannan 5/15/98)#ifdef DEBUG_TELOPTvoid TTelnetHandler::print_telopt(const char *s, int d) { static char buf[20]; printit(s); printit(" "); itoa(d, buf, 10); printit(buf); printit("\n");}#endif
TTelnetHandler::TTelnetHandler(TNetwork &RefNetwork, TConsole &RefConsole, TParser &RefParser):Network(RefNetwork), Console(RefConsole), Parser(RefParser) { init();
// Paul Brannan 9/13/98 dwBuffer = ini.get_buffer_size(); szBuffer = new char [dwBuffer]; Network.SetNawsFunc(NULL);}
void TTelnetHandler::init() { iTermSet = 0; bInBinaryRx = 0; bInBinaryTx = 0; bInEchoTx = 0; bInEchoRx = 0; Network.set_local_echo(1);}
TTelnetHandler::~TTelnetHandler() { delete[] szBuffer;}
int TTelnetHandler::escapeIAC(char *buf, int length){ // The size of buffer must be greater than 2 * length to ensure no memory // out of bounds errors. The 0xff is escaped into 0xff 0xff. char * temp; temp = new char [length * 2]; int current=0; for (int x=0; x < length; x++){ if (buf[x] == (signed char)IAC) temp[current++]=(char)IAC; temp[current++]=buf[x]; } memcpy( buf, temp, current); delete [] temp; return current;}
// This lets us get rid of all the printf's (Paul Brannan 5/15/98)void TTelnetHandler::SendIAC(char c) { static char buf[2] = {IAC}; buf[1] = c; Network.WriteString(buf, 2);}void TTelnetHandler::SendIAC(char c1, char c2) { static char buf[3] = {IAC}; buf[1] = c1; buf[2] = c2; Network.WriteString(buf, 3);}void TTelnetHandler::SendIACParams(char c) { static char buf[2]; buf[0] = c; static int length = escapeIAC(buf, 1); Network.WriteString(buf, length);}void TTelnetHandler::SendIACParams(char c1, char c2) { static char buf[4]; buf[0] = c1; buf[1] = c2; static int length = escapeIAC(buf, 2); Network.WriteString(buf, length);}
int naws_string(char *b, int width, int height) { int l = 0; unsigned char *buf = (unsigned char *)b;
union { char szResponse[2]; int n; };
buf[l++] = IAC; buf[l++] = SB; buf[l++] = TELOPT_NAWS;
n = width; buf[l] = szResponse[1]; if(buf[l-1] == IAC) buf[l++] = IAC; buf[l++] = szResponse[0]; if(buf[l-1] == IAC) buf[l++] = IAC;
n = height; buf[l++] = szResponse[1]; if(buf[l-1] == IAC) buf[l++] = IAC; buf[l++] = szResponse[0]; if(buf[l-1] == IAC) buf[l++] = IAC;
buf[l++] = IAC; buf[l++] = SE;
return l;}
// Ioannou 29 May 1998 : Something strange happens with// Borland compiler at this point when it passes the arguments// to SendIACParams. It always sends 80 lines to the server !!!// There seems to be a bug with optimization (the disassemble shows// that it uses an address plus 0xa than the right one).// This turns them off for this point.#ifdef __BORLANDC__#pragma -O-#endif
// Removed old printf code that was commented out to clean this function// up a bit (Paul brannan 6/15/98)char* TTelnetHandler::ParseIAC(char* pszBuffer, char* pszBufferEnd){ // int n,l; // char szResponse[40]; // Ioannou 29 May 1998 : I prefer the union redefinitions // than the typecasting (used with them from Pascal and Cobol :-) ) // FIX ME !!!! Shall we use the winsock routines instead ?
union { char szResponse[2]; int n; };
// Added support for user-defined term name (Paul Brannan 5/13/98)#define LASTTERM 4 const char *pszTerms[] = {ini.get_term(), "ANSI","DEC-VT100","DEC-VT52","UNKNOWN"}; if(!iTermSet && (pszTerms[0] == 0 || *pszTerms[0] == 0)) iTermSet++;
if (pszBuffer + 2 < pszBufferEnd) { switch ((unsigned char)pszBuffer[1]) {
///////////////// DO //////////////////// case DO: { switch (pszBuffer[2]){ case TELOPT_BINARY: TELOPT_PRINTD("RCVD DO TELOPT_BINARY\n"); if (!bInBinaryRx){ SendIAC(WILL, TELOPT_BINARY); bInBinaryRx = 1; TELOPT_PRINTD("SENT WILL TELOPT_BINARY\n"); } break; case TELOPT_ECHO: // we shouldn't echo for the server! (Paul Brannan 5/30/98) TELOPT_PRINTD2("RCVD DO TELOPT_ECHO", pszBuffer[2]); SendIAC(WONT, TELOPT_ECHO); TELOPT_PRINTD("SENT WONT TELOPT_ECHO\n"); break; case TELOPT_TTYPE: TELOPT_PRINTD("RCVD DO TELOPT_TTYPE\n"); SendIAC(WILL, TELOPT_TTYPE); TELOPT_PRINTD("SENT WILL TELOPT_TTYPE\n"); break; case TELOPT_NAWS: TELOPT_PRINTD("RCVD DO TELOPT_NAWS\n"); SendIAC(WILL, TELOPT_NAWS); SendIAC(SB, TELOPT_NAWS);
Network.SetNawsFunc(naws_string);
n = Console.GetWidth(); SendIACParams(szResponse[1],szResponse [0]);
n = Console.GetHeight(); SendIACParams(szResponse[1],szResponse[0]);
SendIAC(SE); TELOPT_PRINTD("SENT WILL TELOPT_NAWS\n"); break; case TELOPT_XDISPLOC: TELOPT_PRINTD("RCVD DO TELOPT_XDISPLOC\n"); SendIAC(WILL, TELOPT_XDISPLOC); TELOPT_PRINTD("SENT WILL TELOPT_XDISPLOC\n"); printit("Retrieving IP..."); break; default: TELOPT_PRINTD2("RCVD DO", pszBuffer[2]); SendIAC(WONT, pszBuffer[2]); TELOPT_PRINTD2("SENT WONT", pszBuffer[2]); break; } if (pszBuffer + 2 < pszBufferEnd) pszBuffer += 3; break; }
///////////////// WILL //////////////////// case WILL: { switch ((unsigned char)pszBuffer[2]){ case TELOPT_BINARY: TELOPT_PRINTD("RCVD WILL TELOPT_BINARY\n"); if (!bInBinaryTx){ SendIAC(DO, TELOPT_BINARY); bInBinaryTx = 1; TELOPT_PRINTD("SENT DO TELOPT_BINARY\n"); } break; case TELOPT_ECHO: TELOPT_PRINTD2("RCVD WILL TELOPT_ECHO", pszBuffer[2]); if(!bInEchoRx) { SendIAC(DO, TELOPT_ECHO); bInEchoRx = 1; Network.set_local_echo(0); // Paul Brannan 8/25/98 if(iWillSGA) Network.set_line_mode(0); TELOPT_PRINTD2("SENT DO TELOPT_ECHO", pszBuffer[2]); if(Network.get_local_echo()) Network.set_line_mode(0); } break;
// Suppress Go Ahead (Paul Brannan 12/31/98) case TELOPT_SGA: TELOPT_PRINTD("RCVD WILL TELOPT_SGA\n"); if(!iWillSGA) { SendIAC(DO, TELOPT_SGA); if(bInEchoRx) Network.set_line_mode(0); iWillSGA = 1; TELOPT_PRINTD("SENT DO TELOPT_SGA\n"); } break;
////added 1/28/97 default: TELOPT_PRINTD2("RCVD WILL", pszBuffer[2]); SendIAC(DONT, pszBuffer[2]); TELOPT_PRINTD2("SENT DONT", pszBuffer[2]); break; //// } if (pszBuffer + 2 < pszBufferEnd) pszBuffer += 3; break; }
///////////////// WONT //////////////////// case WONT: { switch ((unsigned char)pszBuffer[2]){ case TELOPT_ECHO: TELOPT_PRINTD("RCVD WONT TELOPT_ECHO\n"); if (bInEchoRx){ SendIAC(DONT, TELOPT_ECHO); // bInBinaryRx = 0; bInEchoRx = 0; // Paul Brannan 8/25/98 Network.set_local_echo(1); Network.set_line_mode(0); TELOPT_PRINTD("SENT DONT TELOPT_ECHO\n"); } break;
// Suppress Go Ahead (Paul Brannan 12/31/98) case TELOPT_SGA: TELOPT_PRINTD("RCVD WONT TELOPT_SGA\n"); if(iWillSGA) { SendIAC(DONT, TELOPT_SGA); Network.set_line_mode(0); iWillSGA = 0; TELOPT_PRINTD("SENT DONT TELOPT_SGA\n"); } break;
default: TELOPT_PRINTD2("RCVD WONT", pszBuffer[2]); break; } if (pszBuffer + 2 < pszBufferEnd) pszBuffer += 3; break; }
///////////////// DONT //////////////////// case DONT: { switch ((unsigned char)pszBuffer[2]){ case TELOPT_ECHO: TELOPT_PRINTD("RCVD DONT TELOPT_ECHO\n"); if (bInEchoTx){ SendIAC(WONT, TELOPT_ECHO); bInEchoTx = 0; TELOPT_PRINTD("SENT WONT TELOPT_ECHO\n"); } break; case TELOPT_NAWS: TELOPT_PRINTD("RCVD DONT TELOPT_NAWS\n"); SendIAC(WONT, TELOPT_NAWS); Network.SetNawsFunc(naws_string); TELOPT_PRINTD("SENT WONT TELOPT_NAWS\n"); break; default: TELOPT_PRINTD2("RCVD DONT", pszBuffer[2]); break; } if (pszBuffer + 2 < pszBufferEnd) pszBuffer += 3; break; }
///////////////// SB //////////////////// case SB: { switch ((unsigned char)pszBuffer[2]){ case TELOPT_TTYPE: if (pszBuffer + 5 < pszBufferEnd) { TELOPT_PRINTD("RCVD SB TELOPT_TTYPE\n"); if (pszBuffer[3] == 1){ TELOPT_PRINTD("SENT SB TT"); TELOPT_PRINTD(pszTerms[iTermSet]); TELOPT_PRINTD("\n"); SendIAC(SB, TELOPT_TTYPE); SendIACParams(0); Network.WriteString(pszTerms[iTermSet], strlen(pszTerms[iTermSet])); SendIAC(SE);
if (iTermSet < LASTTERM ) iTermSet+=1; } if (pszBuffer + 5 < pszBufferEnd) pszBuffer += 6; } break; case TELOPT_XDISPLOC: if(pszBuffer + 5 < pszBufferEnd) { TELOPT_PRINTD("RCVD SB XDISPLOC\n"); SendIAC(SB, TELOPT_XDISPLOC); TELOPT_PRINTD("SENT SB XDISPLOC"); SendIACParams(0); if(Network.GetLocalAddress()) Network.WriteString(Network.GetLocalAddress(), strlen(Network.GetLocalAddress())); TELOPT_PRINTD(Network.GetLocalAddress()); TELOPT_PRINTD("\n"); SendIAC(SE); if (pszBuffer + 5 < pszBufferEnd) pszBuffer += 6; } break; default: break; } break; } default: pszBuffer += 2; break; } } return pszBuffer;}
#ifdef __BORLANDC__// bring bug optimazations#pragma -O.#endif
// This is the code from TANSIParser::ParseBuffer. It parses out IACs, and// then calls TParser::ParseBuffer to do the terminal emulation.// (Paul Brannan 6/15/98)// Hopefully eliminating the unnecessary copying should speed things up a// little. (Paul Brannan 6/28/98)char* TTelnetHandler::ParseBuffer(char* pszBuffer, char* pszBufferEnd){ char *pszResult; char *pszHead = pszBuffer;
if(Network.get_net_type() == TN_NETSOCKET) { while (pszBuffer < pszBufferEnd) { // if IAC then parse IAC if((unsigned char) *pszBuffer == IAC) {
// check for escaped IAC if((pszBufferEnd >= pszBuffer + 1) && (unsigned char)*(pszBuffer + 1) == IAC) { // we move data at the front of the buffer to the end so // that if we only have IACs we won't return pszBuffer // even though we did parse something. Returning // pszBuffer is an error condition. memmove(pszHead + 1, pszHead, pszBuffer - pszHead); pszBuffer+=2; pszHead++; } // parse the IAC else { pszResult = ParseIAC(pszBuffer, pszBufferEnd); if(pszBuffer == pszResult) return pszBuffer; // see above regarding moving from front to end. memmove(pszHead + (pszResult - pszBuffer), pszHead, pszBuffer - pszHead); pszHead += (pszResult - pszBuffer); pszBuffer = pszResult; } } // else copy char over to ANSI buffer else { pszBuffer++; } }
// Not a socket connection, so don't parse out IACs. // (Paul Brannan 3/19/99) } else { pszBuffer = pszBufferEnd; }
return(Parser.ParseBuffer(pszHead, pszBuffer));}
// telProcessNetwork calls the member function TTelnetHandler::Go, since// TTelnetHandler::Go is not a static function, and cannot be called with// CreateThread(). (Paul Brannan 6/15/98)DWORD WINAPI telProcessNetwork(LPVOID lpParameter) { TelThreadParams *pParams = (TelThreadParams *)lpParameter; return pParams->TelHandler.Go(&pParams->p);}
// This function is what used to be telProcessNetwork (Paul Brannan 6/15/98)DWORD TTelnetHandler::Go(LPVOID pvParams){ NetParams *pParams = (NetParams *)pvParams;
// No longer a need to copy pParams-> socket and create an instance // of TANSIParser (Paul Brannan 6/15/98)
Console.sync(); // Sync with the parser so the cursor is positioned
Parser.Init(); // Reset the parser (Paul Brannan 9/19/98) init(); // Turn on local echo (Paul Brannan 9/19/98)
*pParams->bNetFinished = 0; char* pszHead = szBuffer; char* pszTail = szBuffer; while (!*pParams->bNetFinish) { // Get data from Socket *pParams->bNetPaused = 1; //Pause int Result = Network.ReadString(pszTail, (szBuffer + dwBuffer) - pszTail);
// Speed up mouse by not going into loop (Paul Brannan 8/10/98) // while(*pParams->bNetPause && !*pParams->bNetFinish) *pParams->bNetPaused = 1; //Pause if(WaitForSingleObject(pParams->hPause, 0) == WAIT_OBJECT_0) WaitForSingleObject(pParams->hUnPause, INFINITE);
*pParams->bNetPaused = 0; //UnPause
if (Result <= 0 || Result > dwBuffer ){ break; } pszTail += Result;
// Process the buffer char* pszNewHead = pszHead; do { // Speed up mouse by not going into loop (Paul Brannan 8/10/98) if(WaitForSingleObject(pParams->hPause, 0) == WAIT_OBJECT_0) { *pParams->bNetPaused = 1; WaitForSingleObject(pParams->hUnPause, INFINITE); *pParams->bNetPaused = 0; }
pszHead = pszNewHead; pszNewHead = ParseBuffer(pszHead, pszTail); // Parse buffer } while ((pszNewHead != pszHead) && (pszNewHead < pszTail) && !*pParams->bNetFinish); pszHead = pszNewHead;
// When we reach the end of the buffer, move contents to the // beginning of the buffer to get free space at the end. if (pszTail == (szBuffer + dwBuffer)) { memmove(szBuffer, pszHead, pszTail - pszHead); pszTail = szBuffer + (pszTail - pszHead); pszHead = szBuffer; } } SetEvent(pParams->hExit);
printm(0, FALSE, MSG_TERMBYREM); *pParams->bNetPaused = 1; //Pause *pParams->bNetFinished = 1; return 0;}