Reactos
at master 395 lines 11 kB view raw
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 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// 24/////////////////////////////////////////////////////////////////////////// 25 26/////////////////////////////////////////////////////////////////////////////// 27// 28// Module: tnclass.cpp 29// 30// Contents: telnet object definition 31// 32// Product: telnet 33// 34// Revisions: August 30, 1998 Paul Brannan <pbranna@clemson.edu> 35// July 12, 1998 Paul Brannan 36// June 15, 1998 Paul Brannan 37// May 14, 1998 Paul Brannan 38// 5.April.1997 jbj@nounname.com 39// 14.Sept.1996 jbj@nounname.com 40// Version 2.0 41// 42/////////////////////////////////////////////////////////////////////////////// 43 44#include "precomp.h" 45 46// Mingw32 needs these (Paul Brannan 9/4/98) 47#ifndef ICON_SMALL 48#define ICON_SMALL 0 49#endif 50#ifndef ICON_BIG 51#define ICON_BIG 1 52#endif 53 54// Ioannou Dec. 8, 1998 55#ifdef __BORLANDC__ 56#ifndef WM_SETICON 57#define WM_SETICON STM_SETICON 58#endif 59#endif 60 61// DoInit() - performs initialization that is common to both the 62// constructors (Paul Brannan 6/15/98) 63void Telnet::DoInit() { 64 Socket = INVALID_SOCKET; 65 bConnected = 0; 66 bNetPaused = 1; 67 bNetFinished = 1; 68 bNetFinish = 0; 69 hThread = 0; // Sam Robertson 12/7/98 70 hProcess = 0; 71 72 WSADATA WsaData; 73 74 // Set the title 75 telSetConsoleTitle("No Connection"); 76 77 // Change the icon 78 hConsoleWindow = TelnetGetConsoleWindow(); 79 iconChange = SetIcon(hConsoleWindow, 0, &oldBIcon, &oldSIcon, ini.get_startdir()); 80 81 if (WSAStartup(MAKEWORD(1, 1), &WsaData)) { 82 DWORD dwLastError = GetLastError(); 83 printm(0, FALSE, MSG_ERROR, "WSAStartup()"); 84 printm(0, TRUE, dwLastError); 85 bWinsockUp = 0; 86 return; 87 } 88 bWinsockUp = 1; 89 90 // Get keyfile (Paul Brannan 5/12/98) 91 const char *keyfile = ini.get_keyfile(); 92 93 // This should be changed later to use the Tnerror routines 94 // This has been done (Paul Brannan 6/5/98) 95 if(LoadKeyMap( keyfile, ini.get_default_config()) != 1) 96 // printf("Error loading keymap.\n"); 97 printm(0, FALSE, MSG_ERRKEYMAP); 98} 99 100Telnet::Telnet(): 101MapLoader(KeyTrans, Charmap), 102Console(GetStdHandle(STD_OUTPUT_HANDLE)), 103TelHandler(Network, Console, Parser), 104ThreadParams(TelHandler), 105Clipboard(TelnetGetConsoleWindow(), Network), 106Mouse(Clipboard), 107Scroller(Mouse, ini.get_scroll_size()), 108Parser(Console, KeyTrans, Scroller, Network, Charmap) { 109 DoInit(); 110} 111 112Telnet::Telnet(const char * szHost1, const char *strPort1): 113MapLoader(KeyTrans, Charmap), 114Console(GetStdHandle(STD_OUTPUT_HANDLE)), 115TelHandler(Network, Console, Parser), 116ThreadParams(TelHandler), 117Clipboard(TelnetGetConsoleWindow(), Network), 118Mouse(Clipboard), 119Scroller(Mouse, ini.get_scroll_size()), 120Parser(Console, KeyTrans, Scroller, Network, Charmap) { 121 DoInit(); 122 Open( szHost1, strPort1); 123} 124 125Telnet::~Telnet(){ 126 if (bWinsockUp){ 127 if(bConnected) Close(); 128 WSACleanup(); 129 } 130 131 // Paul Brannan 8/10/98 132 if(iconChange) { 133 ResetIcon(hConsoleWindow, oldBIcon, oldSIcon); 134 } 135 136} 137 138// changed from char * to const char * (Paul Brannan 5/12/98) 139int Telnet::LoadKeyMap(const char * file, const char * name){ 140 // printf("Loading %s from %s.\n", name ,file); 141 printm(0, FALSE, MSG_KEYMAP, name, file); 142 return MapLoader.Load(file,name); 143} 144 145void Telnet::DisplayKeyMap(){ // display available keymaps 146 MapLoader.Display(); 147}; 148 149int Telnet::SwitchKeyMap(int to) { // switch to selected keymap 150 int ret = KeyTrans.SwitchTo(to); 151 switch(ret) { 152 case -1: printm(0, FALSE, MSG_KEYNOKEYMAPS); break; 153 case 0: printm(0, FALSE, MSG_KEYBADMAP); break; 154 case 1: printm(0, FALSE, MSG_KEYMAPSWITCHED); break; 155 } 156 return ret; 157}; 158 159 160int Telnet::Open(const char *szHost1, const char *strPort1){ 161 if (bWinsockUp && !bConnected){ 162 telSetConsoleTitle(szHost1); 163 164 strncpy (szHost,szHost1, 127); 165 strncpy(strPort, strPort1, sizeof(strPort)); 166 167 // Determine whether to pipe to an executable or use our own sockets 168 // (Paul Brannan March 18, 1999) 169 const char *netpipe; 170 if(*(netpipe=ini.get_netpipe())) { 171 PROCESS_INFORMATION pi; 172 HANDLE hInWrite, hOutRead, hErrRead; 173 if(!CreateHiddenConsoleProcess(netpipe, &pi, &hInWrite, 174 &hOutRead, &hErrRead)) { 175 printm(0, FALSE, MSG_ERRPIPE); 176 return TNNOCON; 177 } 178 Network.SetPipe(hOutRead, hInWrite); 179 hProcess = pi.hProcess; 180 } else { 181 Socket = Connect(); 182 if (Socket == INVALID_SOCKET) { 183 printm(0, FALSE, GetLastError()); 184 return TNNOCON; 185 } 186 Network.SetSocket(Socket); 187 SetLocalAddress(Socket); 188 } 189 190 bNetFinish = 0; 191 bConnected = 1; 192 ThreadParams.p.bNetPaused = &bNetPaused; 193 ThreadParams.p.bNetFinish = &bNetFinish; 194 ThreadParams.p.bNetFinished = &bNetFinished; 195 ThreadParams.p.hExit = CreateEvent(0, TRUE, FALSE, ""); 196 ThreadParams.p.hPause = CreateEvent(0, FALSE, FALSE, ""); 197 ThreadParams.p.hUnPause = CreateEvent(0, FALSE, FALSE, ""); 198 DWORD idThread; 199 200 // Disable Ctrl-break (PB 5/14/98); 201 // Fixed (Thomas Briggs 8/17/98) 202 if(ini.get_disable_break() || ini.get_control_break_as_c()) 203 SetConsoleCtrlHandler(ControlEventHandler, TRUE); 204 205 hThread = CreateThread(0, 0, 206 telProcessNetwork, 207 (LPVOID)&ThreadParams, 0, &idThread); 208 // This helps the display thread a little (Paul Brannan 8/3/98) 209 SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL); 210 return Resume(); 211 } else if(bWinsockUp && bConnected) { 212 printm (0, FALSE, MSG_ALREADYCONNECTED, szHost); 213 } 214 215 return TNNOCON; // cannot do winsock stuff or already connected 216} 217 218// There seems to be a bug with MSVC's optimization. This turns them off 219// for these two functions. 220// (Paul Brannan 5/14/98) 221#ifdef _MSC_VER 222#pragma optimize("", off) 223#endif 224 225 226int Telnet::Close() { 227 Console.sync(); 228 switch(Network.get_net_type()) { 229 case TN_NETSOCKET: 230 if(Socket != INVALID_SOCKET) closesocket(Socket); 231 Socket = INVALID_SOCKET; 232 break; 233 case TN_NETPIPE: 234 if(hProcess != 0) { 235 TerminateProcess(hProcess, 0); 236 CloseHandle(hProcess); 237 hProcess = 0; 238 } 239 break; 240 } 241 242 // Enable Ctrl-break (PB 5/14/98); 243 // Ioannou : this must be FALSE 244 if(ini.get_disable_break()) SetConsoleCtrlHandler(NULL, FALSE); 245 246 if (hThread) CloseHandle(hThread); // Paul Brannan 8/11/98 247 hThread = NULL; // Daniel Straub 11/12/98 248 249 SetEvent(ThreadParams.p.hUnPause); 250 bNetFinish = 1; 251 while (!bNetFinished) 252 Sleep (0); // give up our time slice- this lets our connection thread 253 // finish itself, so we don't hang -crn@ozemail.com.au 254 telSetConsoleTitle("No Connection"); 255 bConnected = 0; 256 return 1; 257} 258 259int Telnet::Resume(){ 260 int i; 261 if (bConnected) { 262 Console.sync(); 263 for(;;){ 264 SetEvent(ThreadParams.p.hUnPause); 265 i = telProcessConsole(&ThreadParams.p, KeyTrans, Console, 266 Network, Mouse, Clipboard, hThread); 267 if (i) bConnected = 1; 268 else bConnected = 0; 269 ResetEvent(ThreadParams.p.hUnPause); 270 SetEvent(ThreadParams.p.hPause); 271 while (!bNetPaused) 272 Sleep (0); // give up our time slice- this lets our connection thread 273 // unpause itself, so we don't hang -crn@ozemail.com.au 274 switch (i){ 275 case TNNOCON: 276 Close(); 277 return TNDONE; 278 case TNPROMPT: 279 return TNPROMPT; 280 case TNSCROLLBACK: 281 Scroller.ScrollBack(); 282 break; 283 case TNSPAWN: 284 NewProcess(); 285 } 286 } 287 } 288 return TNNOCON; 289} 290 291// Turn optimization back on (Paul Brannan 5/12/98) 292#ifdef _MSC_VER 293#pragma optimize("", on) 294#endif 295 296// The scrollback functions have been moved to TScroll.cpp 297// (Paul Brannan 6/15/98) 298SOCKET Telnet::Connect() 299{ 300 SOCKET Socket1 = socket(AF_INET, SOCK_STREAM, 0); 301 SOCKADDR_IN SockAddr; 302 SockAddr.sin_family = AF_INET; 303 SockAddr.sin_addr.s_addr = inet_addr(szHost); 304 305 // determine the port correctly -crn@ozemail.com.au 15/12/98 306 SERVENT *sp; 307 sp = getservbyname (strPort, "tcp"); 308 if (sp == NULL) { 309 if (isdigit (*(strPort))) 310 SockAddr.sin_port = htons(atoi(strPort)); 311 else { 312 printm(0, FALSE, MSG_NOSERVICE, strPort); 313 return INVALID_SOCKET; 314 } 315 } else 316 SockAddr.sin_port = sp->s_port; 317 /// 318 319 // Were we given host name? 320 if (SockAddr.sin_addr.s_addr == INADDR_NONE) { 321 322 // Resolve host name to IP address. 323 printm(0, FALSE, MSG_RESOLVING, szHost); 324 hostent* pHostEnt = gethostbyname(szHost); 325 if (!pHostEnt) 326 return INVALID_SOCKET; 327 printit("\n"); 328 329 SockAddr.sin_addr.s_addr = *(DWORD*)pHostEnt->h_addr; 330 } 331 332 // Print a message telling the user the IP we are connecting to 333 // (Paul Brannan 5/14/98) 334 char ss_b1[4], ss_b2[4], ss_b3[4], ss_b4[4], ss_b5[12]; 335 itoa(SockAddr.sin_addr.S_un.S_un_b.s_b1, ss_b1, 10); 336 itoa(SockAddr.sin_addr.S_un.S_un_b.s_b2, ss_b2, 10); 337 itoa(SockAddr.sin_addr.S_un.S_un_b.s_b3, ss_b3, 10); 338 itoa(SockAddr.sin_addr.S_un.S_un_b.s_b4, ss_b4, 10); 339 itoa(ntohs(SockAddr.sin_port), ss_b5, 10); 340 printm(0, FALSE, MSG_TRYING, ss_b1, ss_b2, ss_b3, ss_b4, ss_b5); 341 342 if (connect(Socket1, (sockaddr*)&SockAddr, sizeof(SockAddr))) 343 return INVALID_SOCKET; 344 345 char esc[2]; 346 esc [0] = ini.get_escape_key(); 347 esc [1] = 0; 348 printm(0, FALSE, MSG_CONNECTED, szHost, esc); 349 350 return Socket1; 351} 352 353void Telnet::telSetConsoleTitle(const char * szHost1) 354{ 355 char szTitle[128] = "Telnet - "; 356 strcat(szTitle, szHost1); 357 if(ini.get_set_title()) SetConsoleTitle(szTitle); 358} 359 360void Telnet::NewProcess() { 361 char cmd_line[MAX_PATH*2]; 362 PROCESS_INFORMATION pi; 363 364 strcpy(cmd_line, ini.get_startdir()); 365 strcat(cmd_line, ini.get_exename()); // Thomas Briggs 12/7/98 366 367 if(!SpawnProcess(cmd_line, &pi)) printm(0, FALSE, MSG_NOSPAWN); 368} 369 370void Telnet::SetLocalAddress(SOCKET s) { 371 SOCKADDR_IN SockAddr; 372 int size = sizeof(SOCKADDR_IN); 373 memset(&SockAddr, 0, sizeof(SockAddr)); 374 SockAddr.sin_family = AF_INET; 375 376 getsockname(Network.GetSocket(), (sockaddr*)&SockAddr, &size); 377 char ss_b1[4], ss_b2[4], ss_b3[4], ss_b4[4]; 378 itoa(SockAddr.sin_addr.S_un.S_un_b.s_b1, ss_b1, 10); 379 itoa(SockAddr.sin_addr.S_un.S_un_b.s_b2, ss_b2, 10); 380 itoa(SockAddr.sin_addr.S_un.S_un_b.s_b3, ss_b3, 10); 381 itoa(SockAddr.sin_addr.S_un.S_un_b.s_b4, ss_b4, 10); 382 383 char addr[40]; 384 strcpy(addr, ss_b1); 385 strcat(addr, "."); 386 strcat(addr, ss_b2); 387 strcat(addr, "."); 388 strcat(addr, ss_b3); 389 strcat(addr, "."); 390 strcat(addr, ss_b4); 391 strcat(addr, ":0.0"); 392 393 Network.SetLocalAddress(addr); 394} 395