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 ///////////////////////////////////////////////////////////////////////////////
46 // Mingw32 needs these (Paul Brannan 9/4/98)
54 // Ioannou Dec. 8, 1998
57 #define WM_SETICON STM_SETICON
61 // DoInit() - performs initialization that is common to both the
62 // constructors (Paul Brannan 6/15/98)
63 void Telnet::DoInit() {
64 Socket
= INVALID_SOCKET
;
69 hThread
= 0; // Sam Robertson 12/7/98
75 telSetConsoleTitle("No Connection");
78 hConsoleWindow
= TelnetGetConsoleWindow();
79 iconChange
= SetIcon(hConsoleWindow
, 0, &oldBIcon
, &oldSIcon
, ini
.get_startdir());
81 if (WSAStartup(MAKEWORD(1, 1), &WsaData
)) {
82 DWORD dwLastError
= GetLastError();
83 printm(0, FALSE
, MSG_ERROR
, "WSAStartup()");
84 printm(0, TRUE
, dwLastError
);
90 // Get keyfile (Paul Brannan 5/12/98)
91 const char *keyfile
= ini
.get_keyfile();
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
);
101 MapLoader(KeyTrans
, Charmap
),
102 Console(GetStdHandle(STD_OUTPUT_HANDLE
)),
103 TelHandler(Network
, Console
, Parser
),
104 ThreadParams(TelHandler
),
105 Clipboard(TelnetGetConsoleWindow(), Network
),
107 Scroller(Mouse
, ini
.get_scroll_size()),
108 Parser(Console
, KeyTrans
, Scroller
, Network
, Charmap
) {
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
),
119 Scroller(Mouse
, ini
.get_scroll_size()),
120 Parser(Console
, KeyTrans
, Scroller
, Network
, Charmap
) {
122 Open( szHost1
, strPort1
);
127 if(bConnected
) Close();
131 // Paul Brannan 8/10/98
133 ResetIcon(hConsoleWindow
, oldBIcon
, oldSIcon
);
138 // changed from char * to const char * (Paul Brannan 5/12/98)
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
);
145 void Telnet::DisplayKeyMap(){ // display available keymaps
149 int Telnet::SwitchKeyMap(int to
) { // switch to selected keymap
150 int ret
= KeyTrans
.SwitchTo(to
);
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;
160 int Telnet::Open(const char *szHost1
, const char *strPort1
){
161 if (bWinsockUp
&& !bConnected
){
162 telSetConsoleTitle(szHost1
);
164 strncpy (szHost
,szHost1
, 127);
165 strncpy(strPort
, strPort1
, sizeof(strPort
));
167 // Determine whether to pipe to an executable or use our own sockets
168 // (Paul Brannan March 18, 1999)
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
);
178 Network
.SetPipe(hOutRead
, hInWrite
);
179 hProcess
= pi
.hProcess
;
182 if (Socket
== INVALID_SOCKET
) {
183 printm(0, FALSE
, GetLastError());
186 Network
.SetSocket(Socket
);
187 SetLocalAddress(Socket
);
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
, "");
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
);
205 hThread
= CreateThread(0, 0,
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
);
211 } else if(bWinsockUp
&& bConnected
) {
212 printm (0, FALSE
, MSG_ALREADYCONNECTED
, szHost
);
215 return TNNOCON
; // cannot do winsock stuff or already connected
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)
222 #pragma optimize("", off)
226 int Telnet::Close() {
228 switch(Network
.get_net_type()) {
230 if(Socket
!= INVALID_SOCKET
) closesocket(Socket
);
231 Socket
= INVALID_SOCKET
;
235 TerminateProcess(hProcess
, 0);
236 CloseHandle(hProcess
);
242 // Enable Ctrl-break (PB 5/14/98);
243 // Ioannou : this must be FALSE
244 if(ini
.get_disable_break()) SetConsoleCtrlHandler(NULL
, FALSE
);
246 if (hThread
) CloseHandle(hThread
); // Paul Brannan 8/11/98
247 hThread
= NULL
; // Daniel Straub 11/12/98
249 SetEvent(ThreadParams
.p
.hUnPause
);
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");
259 int Telnet::Resume(){
264 SetEvent(ThreadParams
.p
.hUnPause
);
265 i
= telProcessConsole(&ThreadParams
.p
, KeyTrans
, Console
,
266 Network
, Mouse
, Clipboard
, hThread
);
267 if (i
) bConnected
= 1;
269 ResetEvent(ThreadParams
.p
.hUnPause
);
270 SetEvent(ThreadParams
.p
.hPause
);
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
281 Scroller
.ScrollBack();
291 // Turn optimization back on (Paul Brannan 5/12/98)
293 #pragma optimize("", on)
296 // The scrollback functions have been moved to TScroll.cpp
297 // (Paul Brannan 6/15/98)
298 SOCKET
Telnet::Connect()
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
);
305 // determine the port correctly -crn@ozemail.com.au 15/12/98
307 sp
= getservbyname (strPort
, "tcp");
309 if (isdigit (*(strPort
)))
310 SockAddr
.sin_port
= htons(atoi(strPort
));
312 printm(0, FALSE
, MSG_NOSERVICE
, strPort
);
313 return INVALID_SOCKET
;
316 SockAddr
.sin_port
= sp
->s_port
;
319 // Were we given host name?
320 if (SockAddr
.sin_addr
.s_addr
== INADDR_NONE
) {
322 // Resolve host name to IP address.
323 printm(0, FALSE
, MSG_RESOLVING
, szHost
);
324 hostent
* pHostEnt
= gethostbyname(szHost
);
326 return INVALID_SOCKET
;
329 SockAddr
.sin_addr
.s_addr
= *(DWORD
*)pHostEnt
->h_addr
;
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
);
342 if (connect(Socket1
, (sockaddr
*)&SockAddr
, sizeof(SockAddr
)))
343 return INVALID_SOCKET
;
346 esc
[0] = ini
.get_escape_key();
348 printm(0, FALSE
, MSG_CONNECTED
, szHost
, esc
);
353 void Telnet::telSetConsoleTitle(const char * szHost1
)
355 char szTitle
[128] = "Telnet - ";
356 strcat(szTitle
, szHost1
);
357 if(ini
.get_set_title()) SetConsoleTitle(szTitle
);
360 void Telnet::NewProcess() {
361 char cmd_line
[MAX_PATH
*2];
362 PROCESS_INFORMATION pi
;
364 strcpy(cmd_line
, ini
.get_startdir());
365 strcat(cmd_line
, ini
.get_exename()); // Thomas Briggs 12/7/98
367 if(!SpawnProcess(cmd_line
, &pi
)) printm(0, FALSE
, MSG_NOSPAWN
);
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
;
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);
391 strcat(addr
, ":0.0");
393 Network
.SetLocalAddress(addr
);