reactos/rosapps/net/telnet/src/tnclass.cpp
Steven Edwards c98929fa7e New Telnet Client
svn path=/trunk/; revision=2458
2001-12-30 10:05:48 +00:00

398 lines
11 KiB
C++

///////////////////////////////////////////////////////////////////////////////
//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 <pbranna@clemson.edu>
// 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 <stdlib.h>
#include <string.h>
#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);
}