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)
DoInit()63 void 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 
Telnet()100 Telnet::Telnet():
101 MapLoader(KeyTrans, Charmap),
102 Console(GetStdHandle(STD_OUTPUT_HANDLE)),
103 TelHandler(Network, Console, Parser),
104 ThreadParams(TelHandler),
105 Clipboard(TelnetGetConsoleWindow(), Network),
106 Mouse(Clipboard),
107 Scroller(Mouse, ini.get_scroll_size()),
108 Parser(Console, KeyTrans, Scroller, Network, Charmap) {
109 	DoInit();
110 }
111 
Telnet(const char * szHost1,const char * strPort1)112 Telnet::Telnet(const char * szHost1, const char *strPort1):
113 MapLoader(KeyTrans, Charmap),
114 Console(GetStdHandle(STD_OUTPUT_HANDLE)),
115 TelHandler(Network, Console, Parser),
116 ThreadParams(TelHandler),
117 Clipboard(TelnetGetConsoleWindow(), Network),
118 Mouse(Clipboard),
119 Scroller(Mouse, ini.get_scroll_size()),
120 Parser(Console, KeyTrans, Scroller, Network, Charmap) {
121 	DoInit();
122 	Open( szHost1, strPort1);
123 }
124 
~Telnet()125 Telnet::~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)
LoadKeyMap(const char * file,const char * name)139 int 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 
DisplayKeyMap()145 void Telnet::DisplayKeyMap(){ // display available keymaps
146 	MapLoader.Display();
147 };
148 
SwitchKeyMap(int to)149 int  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 
Open(const char * szHost1,const char * strPort1)160 int 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 
Close()226 int 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 
Resume()259 int 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)
Connect()298 SOCKET 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 
telSetConsoleTitle(const char * szHost1)353 void 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 
NewProcess()360 void 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 
SetLocalAddress(SOCKET s)370 void 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 
396