/////////////////////////////////////////////////////////////////////////////// //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: tnclass.cpp // // Contents: telnet object definition // // Product: telnet // // Revisions: August 30, 1998 Paul Brannan // July 12, 1998 Paul Brannan // June 15, 1998 Paul Brannan // May 14, 1998 Paul Brannan // 5.April.1997 jbj@nounname.com // 14.Sept.1996 jbj@nounname.com // Version 2.0 // /////////////////////////////////////////////////////////////////////////////// #include #include #include "tnclass.h" #include "tnmisc.h" // Mingw32 needs these (Paul Brannan 9/4/98) #ifndef ICON_SMALL #define ICON_SMALL 0 #endif #ifndef ICON_BIG #define ICON_BIG 1 #endif // Ioannou Dec. 8, 1998 #ifdef __BORLANDC__ #ifndef WM_SETICON #define WM_SETICON STM_SETICON #endif #endif // DoInit() - performs initialization that is common to both the // constructors (Paul Brannan 6/15/98) void Telnet::DoInit() { Socket = INVALID_SOCKET; bConnected = 0; bNetPaused = 1; bNetFinished = 1; bNetFinish = 0; hThread = 0; // Sam Robertson 12/7/98 hProcess = 0; WSADATA WsaData; // Set the title telSetConsoleTitle("No Connection"); // Change the icon hConsoleWindow = GetConsoleWindow(); iconChange = SetIcon(hConsoleWindow, 0, &oldBIcon, &oldSIcon, ini.get_startdir()); if (WSAStartup(MAKEWORD(1, 1), &WsaData)) { DWORD dwLastError = GetLastError(); printm(0, FALSE, MSG_ERROR, "WSAStartup()"); printm(0, TRUE, dwLastError); bWinsockUp = 0; return; } bWinsockUp = 1; // Get keyfile (Paul Brannan 5/12/98) const char *keyfile = ini.get_keyfile(); // This should be changed later to use the Tnerror routines // This has been done (Paul Brannan 6/5/98) if(LoadKeyMap( keyfile, ini.get_default_config()) != 1) // printf("Error loading keymap.\n"); printm(0, FALSE, MSG_ERRKEYMAP); } Telnet::Telnet(): MapLoader(KeyTrans, Charmap), Console(GetStdHandle(STD_OUTPUT_HANDLE)), TelHandler(Network, Console, Parser), ThreadParams(TelHandler), Clipboard(GetConsoleWindow(), Network), Mouse(Clipboard), Scroller(Mouse, ini.get_scroll_size()), Parser(Console, KeyTrans, Scroller, Network, Charmap) { DoInit(); } Telnet::Telnet(const char * szHost1, const char *strPort1): MapLoader(KeyTrans, Charmap), Console(GetStdHandle(STD_OUTPUT_HANDLE)), TelHandler(Network, Console, Parser), ThreadParams(TelHandler), Clipboard(GetConsoleWindow(), Network), Mouse(Clipboard), Scroller(Mouse, ini.get_scroll_size()), Parser(Console, KeyTrans, Scroller, Network, Charmap) { DoInit(); Open( szHost1, strPort1); } Telnet::~Telnet(){ if (bWinsockUp){ if(bConnected) Close(); WSACleanup(); } // Paul Brannan 8/10/98 if(iconChange) { ResetIcon(hConsoleWindow, oldBIcon, oldSIcon); } } // changed from char * to const char * (Paul Brannan 5/12/98) int Telnet::LoadKeyMap(const char * file, const char * name){ // printf("Loading %s from %s.\n", name ,file); printm(0, FALSE, MSG_KEYMAP, name, file); return MapLoader.Load(file,name); } void Telnet::DisplayKeyMap(){ // display available keymaps MapLoader.Display(); }; int Telnet::SwitchKeyMap(int to) { // switch to selected keymap int ret = KeyTrans.SwitchTo(to); switch(ret) { case -1: printm(0, FALSE, MSG_KEYNOKEYMAPS); break; case 0: printm(0, FALSE, MSG_KEYBADMAP); break; case 1: printm(0, FALSE, MSG_KEYMAPSWITCHED); break; } return ret; }; int Telnet::Open(const char *szHost1, const char *strPort1){ if (bWinsockUp && !bConnected){ telSetConsoleTitle(szHost1); strncpy (szHost,szHost1, 127); strncpy(strPort, strPort1, sizeof(strPort)); // Determine whether to pipe to an executable or use our own sockets // (Paul Brannan March 18, 1999) const char *netpipe; if(*(netpipe=ini.get_netpipe())) { PROCESS_INFORMATION pi; HANDLE hInWrite, hOutRead, hErrRead; if(!CreateHiddenConsoleProcess(netpipe, &pi, &hInWrite, &hOutRead, &hErrRead)) { printm(0, FALSE, MSG_ERRPIPE); return TNNOCON; } Network.SetPipe(hOutRead, hInWrite); hProcess = pi.hProcess; } else { Socket = Connect(); if (Socket == INVALID_SOCKET) { printm(0, FALSE, GetLastError()); return TNNOCON; } Network.SetSocket(Socket); SetLocalAddress(Socket); } bNetFinish = 0; bConnected = 1; ThreadParams.p.bNetPaused = &bNetPaused; ThreadParams.p.bNetFinish = &bNetFinish; ThreadParams.p.bNetFinished = &bNetFinished; ThreadParams.p.hExit = CreateEvent(0, TRUE, FALSE, ""); ThreadParams.p.hPause = CreateEvent(0, FALSE, FALSE, ""); ThreadParams.p.hUnPause = CreateEvent(0, FALSE, FALSE, ""); DWORD idThread; // Disable Ctrl-break (PB 5/14/98); // Fixed (Thomas Briggs 8/17/98) if(ini.get_disable_break() || ini.get_control_break_as_c()) SetConsoleCtrlHandler(ControlEventHandler, TRUE); hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) telProcessNetwork, (LPVOID)&ThreadParams, 0, &idThread); // This helps the display thread a little (Paul Brannan 8/3/98) SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL); return Resume(); } else if(bWinsockUp && bConnected) { printm (0, FALSE, MSG_ALREADYCONNECTED, szHost); } return TNNOCON; // cannot do winsock stuff or already connected } // There seems to be a bug with MSVC's optimization. This turns them off // for these two functions. // (Paul Brannan 5/14/98) #ifdef _MSC_VER #pragma optimize("", off) #endif int Telnet::Close() { Console.sync(); switch(Network.get_net_type()) { case TN_NETSOCKET: if(Socket != INVALID_SOCKET) closesocket(Socket); Socket = INVALID_SOCKET; break; case TN_NETPIPE: if(hProcess != 0) { TerminateProcess(hProcess, 0); CloseHandle(hProcess); hProcess = 0; } break; } // Enable Ctrl-break (PB 5/14/98); // Ioannou : this must be FALSE if(ini.get_disable_break()) SetConsoleCtrlHandler(NULL, FALSE); if (hThread) CloseHandle(hThread); // Paul Brannan 8/11/98 hThread = NULL; // Daniel Straub 11/12/98 SetEvent(ThreadParams.p.hUnPause); bNetFinish = 1; while (!bNetFinished) Sleep (0); // give up our time slice- this lets our connection thread // finish itself, so we don't hang -crn@ozemail.com.au telSetConsoleTitle("No Connection"); bConnected = 0; return 1; } int Telnet::Resume(){ int i; if (bConnected) { Console.sync(); for(;;){ SetEvent(ThreadParams.p.hUnPause); i = telProcessConsole(&ThreadParams.p, KeyTrans, Console, Network, Mouse, Clipboard, hThread); if (i) bConnected = 1; else bConnected = 0; ResetEvent(ThreadParams.p.hUnPause); SetEvent(ThreadParams.p.hPause); while (!bNetPaused) Sleep (0); // give up our time slice- this lets our connection thread // unpause itself, so we don't hang -crn@ozemail.com.au switch (i){ case TNNOCON: Close(); return TNDONE; case TNPROMPT: return TNPROMPT; case TNSCROLLBACK: Scroller.ScrollBack(); break; case TNSPAWN: NewProcess(); } } } return TNNOCON; } // Turn optimization back on (Paul Brannan 5/12/98) #ifdef _MSC_VER #pragma optimize("", on) #endif // The scrollback functions have been moved to TScroll.cpp // (Paul Brannan 6/15/98) SOCKET Telnet::Connect() { SOCKET Socket1 = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN SockAddr; SockAddr.sin_family = AF_INET; SockAddr.sin_addr.s_addr = inet_addr(szHost); // determine the port correctly -crn@ozemail.com.au 15/12/98 SERVENT *sp; sp = getservbyname (strPort, "tcp"); if (sp == NULL) { if (isdigit (*(strPort))) SockAddr.sin_port = htons(atoi(strPort)); else { printm(0, FALSE, MSG_NOSERVICE, strPort); return INVALID_SOCKET; } } else SockAddr.sin_port = sp->s_port; /// // Were we given host name? if (SockAddr.sin_addr.s_addr == INADDR_NONE) { // Resolve host name to IP address. printm(0, FALSE, MSG_RESOLVING, szHost); hostent* pHostEnt = gethostbyname(szHost); if (!pHostEnt) return INVALID_SOCKET; printit("\n"); SockAddr.sin_addr.s_addr = *(DWORD*)pHostEnt->h_addr; } // Print a message telling the user the IP we are connecting to // (Paul Brannan 5/14/98) char ss_b1[4], ss_b2[4], ss_b3[4], ss_b4[4], ss_b5[12]; itoa(SockAddr.sin_addr.S_un.S_un_b.s_b1, ss_b1, 10); itoa(SockAddr.sin_addr.S_un.S_un_b.s_b2, ss_b2, 10); itoa(SockAddr.sin_addr.S_un.S_un_b.s_b3, ss_b3, 10); itoa(SockAddr.sin_addr.S_un.S_un_b.s_b4, ss_b4, 10); itoa(ntohs(SockAddr.sin_port), ss_b5, 10); printm(0, FALSE, MSG_TRYING, ss_b1, ss_b2, ss_b3, ss_b4, ss_b5); if (connect(Socket1, (sockaddr*)&SockAddr, sizeof(SockAddr))) return INVALID_SOCKET; char esc[2]; esc [0] = ini.get_escape_key(); esc [1] = 0; printm(0, FALSE, MSG_CONNECTED, szHost, esc); return Socket1; } void Telnet::telSetConsoleTitle(const char * szHost1) { char szTitle[128] = "Telnet - "; strcat(szTitle, szHost1); if(ini.get_set_title()) SetConsoleTitle(szTitle); } void Telnet::NewProcess() { char cmd_line[MAX_PATH*2]; PROCESS_INFORMATION pi; strcpy(cmd_line, ini.get_startdir()); strcat(cmd_line, ini.get_exename()); // Thomas Briggs 12/7/98 if(!SpawnProcess(cmd_line, &pi)) printm(0, FALSE, MSG_NOSPAWN); } void Telnet::SetLocalAddress(SOCKET s) { SOCKADDR_IN SockAddr; int size = sizeof(SOCKADDR_IN); memset(&SockAddr, 0, sizeof(SockAddr)); SockAddr.sin_family = AF_INET; getsockname(Network.GetSocket(), (sockaddr*)&SockAddr, &size); char ss_b1[4], ss_b2[4], ss_b3[4], ss_b4[4]; itoa(SockAddr.sin_addr.S_un.S_un_b.s_b1, ss_b1, 10); itoa(SockAddr.sin_addr.S_un.S_un_b.s_b2, ss_b2, 10); itoa(SockAddr.sin_addr.S_un.S_un_b.s_b3, ss_b3, 10); itoa(SockAddr.sin_addr.S_un.S_un_b.s_b4, ss_b4, 10); char addr[40]; strcpy(addr, ss_b1); strcat(addr, "."); strcat(addr, ss_b2); strcat(addr, "."); strcat(addr, ss_b3); strcat(addr, "."); strcat(addr, ss_b4); strcat(addr, ":0.0"); Network.SetLocalAddress(addr); }