mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
c98929fa7e
svn path=/trunk/; revision=2458
398 lines
11 KiB
C++
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);
|
|
}
|
|
|