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
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.
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.
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.
24 ///////////////////////////////////////////////////////////////////////////
26 ///////////////////////////////////////////////////////////////////////////////
28 // Module: tnclass.cpp
30 // Contents: telnet object definition
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
42 ///////////////////////////////////////////////////////////////////////////////
49 // Mingw32 needs these (Paul Brannan 9/4/98)
57 // Ioannou Dec. 8, 1998
60 #define WM_SETICON STM_SETICON
64 // DoInit() - performs initialization that is common to both the
65 // constructors (Paul Brannan 6/15/98)
66 void Telnet::DoInit() {
67 Socket
= INVALID_SOCKET
;
72 hThread
= 0; // Sam Robertson 12/7/98
78 telSetConsoleTitle("No Connection");
81 hConsoleWindow
= GetConsoleWindow();
82 iconChange
= SetIcon(hConsoleWindow
, 0, &oldBIcon
, &oldSIcon
, ini
.get_startdir());
84 if (WSAStartup(MAKEWORD(1, 1), &WsaData
)) {
85 DWORD dwLastError
= GetLastError();
86 printm(0, FALSE
, MSG_ERROR
, "WSAStartup()");
87 printm(0, TRUE
, dwLastError
);
93 // Get keyfile (Paul Brannan 5/12/98)
94 const char *keyfile
= ini
.get_keyfile();
96 // This should be changed later to use the Tnerror routines
97 // This has been done (Paul Brannan 6/5/98)
98 if(LoadKeyMap( keyfile
, ini
.get_default_config()) != 1)
99 // printf("Error loading keymap.\n");
100 printm(0, FALSE
, MSG_ERRKEYMAP
);
104 MapLoader(KeyTrans
, Charmap
),
105 Console(GetStdHandle(STD_OUTPUT_HANDLE
)),
106 TelHandler(Network
, Console
, Parser
),
107 ThreadParams(TelHandler
),
108 Clipboard(GetConsoleWindow(), Network
),
110 Scroller(Mouse
, ini
.get_scroll_size()),
111 Parser(Console
, KeyTrans
, Scroller
, Network
, Charmap
) {
115 Telnet::Telnet(const char * szHost1
, const char *strPort1
):
116 MapLoader(KeyTrans
, Charmap
),
117 Console(GetStdHandle(STD_OUTPUT_HANDLE
)),
118 TelHandler(Network
, Console
, Parser
),
119 ThreadParams(TelHandler
),
120 Clipboard(GetConsoleWindow(), Network
),
122 Scroller(Mouse
, ini
.get_scroll_size()),
123 Parser(Console
, KeyTrans
, Scroller
, Network
, Charmap
) {
125 Open( szHost1
, strPort1
);
130 if(bConnected
) Close();
134 // Paul Brannan 8/10/98
136 ResetIcon(hConsoleWindow
, oldBIcon
, oldSIcon
);
141 // changed from char * to const char * (Paul Brannan 5/12/98)
142 int Telnet::LoadKeyMap(const char * file
, const char * name
){
143 // printf("Loading %s from %s.\n", name ,file);
144 printm(0, FALSE
, MSG_KEYMAP
, name
, file
);
145 return MapLoader
.Load(file
,name
);
148 void Telnet::DisplayKeyMap(){ // display available keymaps
152 int Telnet::SwitchKeyMap(int to
) { // switch to selected keymap
153 int ret
= KeyTrans
.SwitchTo(to
);
155 case -1: printm(0, FALSE
, MSG_KEYNOKEYMAPS
); break;
156 case 0: printm(0, FALSE
, MSG_KEYBADMAP
); break;
157 case 1: printm(0, FALSE
, MSG_KEYMAPSWITCHED
); break;
163 int Telnet::Open(const char *szHost1
, const char *strPort1
){
164 if (bWinsockUp
&& !bConnected
){
165 telSetConsoleTitle(szHost1
);
167 strncpy (szHost
,szHost1
, 127);
168 strncpy(strPort
, strPort1
, sizeof(strPort
));
170 // Determine whether to pipe to an executable or use our own sockets
171 // (Paul Brannan March 18, 1999)
173 if(*(netpipe
=ini
.get_netpipe())) {
174 PROCESS_INFORMATION pi
;
175 HANDLE hInWrite
, hOutRead
, hErrRead
;
176 if(!CreateHiddenConsoleProcess(netpipe
, &pi
, &hInWrite
,
177 &hOutRead
, &hErrRead
)) {
178 printm(0, FALSE
, MSG_ERRPIPE
);
181 Network
.SetPipe(hOutRead
, hInWrite
);
182 hProcess
= pi
.hProcess
;
185 if (Socket
== INVALID_SOCKET
) {
186 printm(0, FALSE
, GetLastError());
189 Network
.SetSocket(Socket
);
190 SetLocalAddress(Socket
);
195 ThreadParams
.p
.bNetPaused
= &bNetPaused
;
196 ThreadParams
.p
.bNetFinish
= &bNetFinish
;
197 ThreadParams
.p
.bNetFinished
= &bNetFinished
;
198 ThreadParams
.p
.hExit
= CreateEvent(0, TRUE
, FALSE
, "");
199 ThreadParams
.p
.hPause
= CreateEvent(0, FALSE
, FALSE
, "");
200 ThreadParams
.p
.hUnPause
= CreateEvent(0, FALSE
, FALSE
, "");
203 // Disable Ctrl-break (PB 5/14/98);
204 // Fixed (Thomas Briggs 8/17/98)
205 if(ini
.get_disable_break() || ini
.get_control_break_as_c())
206 SetConsoleCtrlHandler(ControlEventHandler
, TRUE
);
208 hThread
= CreateThread(0, 0,
210 (LPVOID
)&ThreadParams
, 0, &idThread
);
211 // This helps the display thread a little (Paul Brannan 8/3/98)
212 SetThreadPriority(hThread
, THREAD_PRIORITY_ABOVE_NORMAL
);
214 } else if(bWinsockUp
&& bConnected
) {
215 printm (0, FALSE
, MSG_ALREADYCONNECTED
, szHost
);
218 return TNNOCON
; // cannot do winsock stuff or already connected
221 // There seems to be a bug with MSVC's optimization. This turns them off
222 // for these two functions.
223 // (Paul Brannan 5/14/98)
225 #pragma optimize("", off)
229 int Telnet::Close() {
231 switch(Network
.get_net_type()) {
233 if(Socket
!= INVALID_SOCKET
) closesocket(Socket
);
234 Socket
= INVALID_SOCKET
;
238 TerminateProcess(hProcess
, 0);
239 CloseHandle(hProcess
);
245 // Enable Ctrl-break (PB 5/14/98);
246 // Ioannou : this must be FALSE
247 if(ini
.get_disable_break()) SetConsoleCtrlHandler(NULL
, FALSE
);
249 if (hThread
) CloseHandle(hThread
); // Paul Brannan 8/11/98
250 hThread
= NULL
; // Daniel Straub 11/12/98
252 SetEvent(ThreadParams
.p
.hUnPause
);
254 while (!bNetFinished
)
255 Sleep (0); // give up our time slice- this lets our connection thread
256 // finish itself, so we don't hang -crn@ozemail.com.au
257 telSetConsoleTitle("No Connection");
262 int Telnet::Resume(){
267 SetEvent(ThreadParams
.p
.hUnPause
);
268 i
= telProcessConsole(&ThreadParams
.p
, KeyTrans
, Console
,
269 Network
, Mouse
, Clipboard
, hThread
);
270 if (i
) bConnected
= 1;
272 ResetEvent(ThreadParams
.p
.hUnPause
);
273 SetEvent(ThreadParams
.p
.hPause
);
275 Sleep (0); // give up our time slice- this lets our connection thread
276 // unpause itself, so we don't hang -crn@ozemail.com.au
284 Scroller
.ScrollBack();
294 // Turn optimization back on (Paul Brannan 5/12/98)
296 #pragma optimize("", on)
299 // The scrollback functions have been moved to TScroll.cpp
300 // (Paul Brannan 6/15/98)
301 SOCKET
Telnet::Connect()
303 SOCKET Socket1
= socket(AF_INET
, SOCK_STREAM
, 0);
304 SOCKADDR_IN SockAddr
;
305 SockAddr
.sin_family
= AF_INET
;
306 SockAddr
.sin_addr
.s_addr
= inet_addr(szHost
);
308 // determine the port correctly -crn@ozemail.com.au 15/12/98
310 sp
= getservbyname (strPort
, "tcp");
312 if (isdigit (*(strPort
)))
313 SockAddr
.sin_port
= htons(atoi(strPort
));
315 printm(0, FALSE
, MSG_NOSERVICE
, strPort
);
316 return INVALID_SOCKET
;
319 SockAddr
.sin_port
= sp
->s_port
;
322 // Were we given host name?
323 if (SockAddr
.sin_addr
.s_addr
== INADDR_NONE
) {
325 // Resolve host name to IP address.
326 printm(0, FALSE
, MSG_RESOLVING
, szHost
);
327 hostent
* pHostEnt
= gethostbyname(szHost
);
329 return INVALID_SOCKET
;
332 SockAddr
.sin_addr
.s_addr
= *(DWORD
*)pHostEnt
->h_addr
;
335 // Print a message telling the user the IP we are connecting to
336 // (Paul Brannan 5/14/98)
337 char ss_b1
[4], ss_b2
[4], ss_b3
[4], ss_b4
[4], ss_b5
[12];
338 itoa(SockAddr
.sin_addr
.S_un
.S_un_b
.s_b1
, ss_b1
, 10);
339 itoa(SockAddr
.sin_addr
.S_un
.S_un_b
.s_b2
, ss_b2
, 10);
340 itoa(SockAddr
.sin_addr
.S_un
.S_un_b
.s_b3
, ss_b3
, 10);
341 itoa(SockAddr
.sin_addr
.S_un
.S_un_b
.s_b4
, ss_b4
, 10);
342 itoa(ntohs(SockAddr
.sin_port
), ss_b5
, 10);
343 printm(0, FALSE
, MSG_TRYING
, ss_b1
, ss_b2
, ss_b3
, ss_b4
, ss_b5
);
345 if (connect(Socket1
, (sockaddr
*)&SockAddr
, sizeof(SockAddr
)))
346 return INVALID_SOCKET
;
349 esc
[0] = ini
.get_escape_key();
351 printm(0, FALSE
, MSG_CONNECTED
, szHost
, esc
);
356 void Telnet::telSetConsoleTitle(const char * szHost1
)
358 char szTitle
[128] = "Telnet - ";
359 strcat(szTitle
, szHost1
);
360 if(ini
.get_set_title()) SetConsoleTitle(szTitle
);
363 void Telnet::NewProcess() {
364 char cmd_line
[MAX_PATH
*2];
365 PROCESS_INFORMATION pi
;
367 strcpy(cmd_line
, ini
.get_startdir());
368 strcat(cmd_line
, ini
.get_exename()); // Thomas Briggs 12/7/98
370 if(!SpawnProcess(cmd_line
, &pi
)) printm(0, FALSE
, MSG_NOSPAWN
);
373 void Telnet::SetLocalAddress(SOCKET s
) {
374 SOCKADDR_IN SockAddr
;
375 int size
= sizeof(SOCKADDR_IN
);
376 memset(&SockAddr
, 0, sizeof(SockAddr
));
377 SockAddr
.sin_family
= AF_INET
;
379 getsockname(Network
.GetSocket(), (sockaddr
*)&SockAddr
, &size
);
380 char ss_b1
[4], ss_b2
[4], ss_b3
[4], ss_b4
[4];
381 itoa(SockAddr
.sin_addr
.S_un
.S_un_b
.s_b1
, ss_b1
, 10);
382 itoa(SockAddr
.sin_addr
.S_un
.S_un_b
.s_b2
, ss_b2
, 10);
383 itoa(SockAddr
.sin_addr
.S_un
.S_un_b
.s_b3
, ss_b3
, 10);
384 itoa(SockAddr
.sin_addr
.S_un
.S_un_b
.s_b4
, ss_b4
, 10);
394 strcat(addr
, ":0.0");
396 Network
.SetLocalAddress(addr
);