1
/****************************************************************************
5
PURPOSE: Windows networking kernel - Telnet
9
WinMain() - calls initialization function, processes message loop
10
InitApplication() - initializes window data and registers window
11
InitInstance() - saves instance handle and creates main window
12
MainWndProc() - processes messages
13
About() - processes messages for "About" dialog box
17
Windows can have several copies of your application running at the
18
same time. The variable hInst keeps track of which instance this
19
application is so that processing will be to the correct window.
21
****************************************************************************/
32
static CONFIG *tmpConfig;
33
static CONNECTION *con = NULL;
34
static char hostdata[MAXGETHOSTSTRUCT];
38
char strTmp[1024]; /* Scratch buffer */
39
BOOL bAutoConnection = FALSE;
41
char szUserName[64]; /* Used in auth.c */
45
#define WINDOW_CLASS "K4_telnetWClass"
49
krb5_context k5_context;
50
#define WINDOW_CLASS "K5_telnetWClass"
55
* FUNCTION: WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
57
* PURPOSE: calls initialization function, processes message loop
61
* Windows recognizes this function by name as the initial entry point
62
* for the program. This function calls the application initialization
63
* routine, if no other instance of the program is running, and always
64
* calls the instance initialization routine. It then executes a message
65
* retrieval and dispatch loop that is the top-level control structure
66
* for the remainder of execution. The loop is terminated when a WM_QUIT
67
* message is received, at which time this function exits the application
68
* instance by returning the value passed by PostQuitMessage().
70
* If this function must abort before entering the message loop, it
71
* returns the conventional value NULL.
75
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
80
if (!InitApplication(hInstance))
84
* Perform initializations that apply to a specific instance
86
bAutoConnection = parse_cmdline(lpCmdLine);
88
if (!InitInstance(hInstance, nCmdShow))
92
SetDebugErrorLevel(SLE_WARNING);
96
* Acquire and dispatch messages until a WM_QUIT message is received.
98
while (GetMessage(&msg, NULL, 0, 0)) {
99
TranslateMessage(&msg);
100
DispatchMessage(&msg);
102
/* Process all non-network messages */
103
while (PeekMessage(&msg, NULL, 0, WM_NETWORKEVENT-1, PM_REMOVE) ||
104
PeekMessage(&msg, NULL, WM_NETWORKEVENT+1, (UINT)-1, PM_REMOVE))
106
if (msg.message == WM_QUIT) // Special case: WM_QUIT -- return
107
return msg.wParam; // the value from PostQuitMessage
109
TranslateMessage(&msg);
110
DispatchMessage(&msg);
114
return (msg.wParam); /* Returns the value from PostQuitMessage */
118
* FUNCTION: InitApplication(HINSTANCE)
120
* PURPOSE: Initializes window data and registers window class
124
* This function is called at initialization time only if no other
125
* instances of the application are running. This function performs
126
* initialization tasks that can be done once for any number of running
129
* In this case, we initialize a window class by filling out a data
130
* structure of type WNDCLASS and calling the Windows RegisterClass()
131
* function. Since all instances of this application use the same window
132
* class, we only need to do this when the first instance is initialized.
136
InitApplication(HINSTANCE hInstance)
140
ScreenInit(hInstance);
143
* Fill in window class structure with parameters that describe the
146
wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
147
wc.lpfnWndProc = MainWndProc; /* Function to retrieve messages for
148
* windows of this class.
150
wc.cbClsExtra = 0; /* No per-class extra data. */
151
wc.cbWndExtra = 0; /* No per-window extra data. */
152
wc.hInstance = hInstance; /* Application that owns the class. */
153
wc.hIcon = NULL; /* LoadIcon(hInstance, "NCSA"); */
154
wc.hCursor = NULL; /* Cursor(NULL, IDC_ARROW); */
155
wc.hbrBackground = NULL; /* GetStockObject(WHITE_BRUSH); */
156
wc.lpszMenuName = NULL; /* Name of menu resource in .RC file. */
157
wc.lpszClassName = WINDOW_CLASS; /* Name used in call to CreateWindow. */
159
return(RegisterClass(&wc));
164
* FUNCTION: InitInstance(HANDLE, int)
166
* PURPOSE: Saves instance handle and creates main window
170
* This function is called at initialization time for every instance of
171
* this application. This function performs initialization tasks that
172
* cannot be shared by multiple instances.
174
* In this case, we save the instance handle in a static variable and
175
* create and display the main program window.
178
InitInstance(HINSTANCE hInstance, int nCmdShow)
184
SetScreenInstance(hInstance);
187
* Save the instance handle in static variable, which will be used in
188
* many subsequence calls from this application to Windows.
193
* Create a main window for this application instance.
196
WINDOW_CLASS, /* See RegisterClass() call. */
197
"TCPWin", /* Text for window title bar. */
198
WS_SYSMENU, /* Window style. */
199
xScreen / 3, /* Default horizontal position. */
200
yScreen / 3, /* Default vertical position. */
201
xScreen / 3, /* Default width. */
202
yScreen / 3, /* Default height. */
203
NULL, /* Overlapped windows have no parent */
204
NULL, /* Use the window class menu. */
205
hInstance, /* This instance owns this window. */
206
NULL); /* Pointer not needed. */
211
if (WSAStartup(0x0101, &wsaData) != 0) { /* Initialize the network */
212
MessageBox(NULL, "Couldn't initialize Winsock!", NULL,
213
MB_OK | MB_ICONEXCLAMATION);
217
if (!OpenTelnetConnection()) {
223
krb5_init_context(&k5_context);
232
* FUNCTION: MainWndProc(HWND, UINT, WPARAM, LPARAM)
234
* PURPOSE: Processes messages
238
* WM_COMMAND - application menu (About dialog box)
239
* WM_DESTROY - destroy window
242
MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
246
int iEvent, cnt, ret;
248
struct sockaddr_in remote_addr;
249
struct hostent *remote_host;
252
case WM_MYSCREENCHANGEBKSP:
255
con->backspace = wParam;
256
if (con->backspace == VK_BACK) {
257
con->ctrl_backspace = 0x7f;
258
WritePrivateProfileString(INI_TELNET, INI_BACKSPACE,
259
INI_BACKSPACE_BS, TELNET_INI);
262
con->ctrl_backspace = VK_BACK;
263
WritePrivateProfileString(INI_TELNET, INI_BACKSPACE,
264
INI_BACKSPACE_DEL, TELNET_INI);
266
GetPrivateProfileString(INI_HOSTS, INI_HOST "0", "", buf, 128, TELNET_INI);
267
tmpCommaLoc = strchr(buf, ',');
268
if (tmpCommaLoc == NULL) {
270
tmpCommaLoc = strchr(buf, ',');
274
if (con->backspace == VK_BACK)
275
strcpy(tmpCommaLoc, INI_HOST_BS);
277
strcpy(tmpCommaLoc, INI_HOST_DEL);
279
WritePrivateProfileString(INI_HOSTS, INI_HOST "0", buf, TELNET_INI);
282
case WM_MYSCREENCHAR:
288
if (wParam == VK_BACK)
290
else if (wParam == 0x7f)
291
c = con->ctrl_backspace;
292
else if (wParam == VK_SPACE && GetKeyState(VK_CONTROL) < 0)
296
TelnetSend(con->ks, &c, 1, 0);
301
/* Acts as a send through: buffer is lParam and length in wParam */
304
memcpy(buf, (char *)lParam, wParam);
305
TelnetSend (con->ks, buf, wParam, 0);
308
case WM_MYSCREENBLOCK:
311
hBuffer = (HGLOBAL) wParam;
312
lpBuffer = GlobalLock(hBuffer);
313
TelnetSend(con->ks, lpBuffer, lstrlen(lpBuffer), 0);
314
GlobalUnlock(hBuffer);
317
case WM_MYSCREENCLOSE:
321
kstream_destroy(con->ks);
332
case WM_DESTROY: /* message: window being destroyed */
335
kstream_destroy(con->ks);
342
case WM_NETWORKEVENT:
343
iEvent = WSAGETSELECTEVENT(lParam);
350
cnt = kstream_read(con->ks, buf, 1500);
352
parse((CONNECTION *)con, (unsigned char *)buf, cnt);
353
ScreenEm(buf, cnt, con->pScreen);
357
kstream_destroy(con->ks);
365
ret = WSAGETSELECTERROR(lParam);
367
wsprintf(buf, "Error %d on Connect", ret);
368
MessageBox(NULL, buf, NULL, MB_OK | MB_ICONEXCLAMATION);
369
kstream_destroy(con->ks);
375
start_negotiation(con->ks);
381
case WM_HOSTNAMEFOUND:
382
ret = WSAGETASYNCERROR(lParam);
384
wsprintf(buf, "Error %d on GetHostbyName", ret);
385
MessageBox(NULL, buf, NULL, MB_OK | MB_ICONEXCLAMATION);
386
kstream_destroy(con->ks);
393
remote_host = (struct hostent *)hostdata;
394
remote_addr.sin_family = AF_INET;
395
memcpy(&(remote_addr.sin_addr), &(remote_host->h_addr[0]), 4);
396
remote_addr.sin_port = htons(port_no);
398
connect(con->socket, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr));
401
case WM_MYSCREENSIZE:
402
con->width = LOWORD(lParam); /* width in characters */
403
con->height = HIWORD(lParam); /* height in characters */
404
if (con->bResizeable && con->ks)
406
wsprintf(buf, "%d", con->height);
407
WritePrivateProfileString(INI_TELNET, INI_HEIGHT, buf, TELNET_INI);
408
wsprintf(buf, "%d", con->width);
409
WritePrivateProfileString(INI_TELNET, INI_WIDTH, buf, TELNET_INI);
412
default: /* Passes it on if unproccessed */
413
return(DefWindowProc(hWnd, message, wParam, lParam));
421
* FUNCTION: SaveHostName(hostname, port)
423
* PURPOSE: Saves the currently selected host name and port number
424
* in the KERBEROS.INI file and returns the preferred backspace
425
* setting if one exists for that host.
427
* RETURNS: VK_BACK or 0x7f depending on the desired backspace setting.
430
SaveHostName(char *host, int port)
432
char buf[128]; /* Scratch buffer */
433
char fullhost[128]; /* Host & port combination */
434
char hostName[10][128]; /* Entries from INI files */
435
char *comma; /* For parsing del/bs info */
436
int len; /* Length of fullhost */
437
int n; /* Number of items written */
439
int bs; /* What we return */
441
if (port == 23) /* Default telnet port */
442
strcpy(fullhost, host); /* ...then don't add it on */
444
wsprintf(fullhost, "%s %d", host, port);
445
len = strlen(fullhost);
448
for (i = 0; i < 10; i++) {
449
wsprintf(buf, INI_HOST "%d", i); /* INI item to fetch */
450
GetPrivateProfileString(INI_HOSTS, buf, "", hostName[i],
456
if (strncmp (hostName[i], fullhost, len)) /* A match?? */
457
continue; /* Nope, keep going */
458
comma = strchr (hostName[i], ',');
462
++comma; /* Past the comma */
463
while (*comma == ' ') /* Past leading white space */
465
bs = VK_BACK; /* Default for unknown entry */
466
if (_stricmp(comma, INI_HOST_DEL) == 0)
469
else { /* No matching entry */
470
GetPrivateProfileString(INI_TELNET, INI_BACKSPACE, INI_BACKSPACE_BS,
471
buf, sizeof(buf), TELNET_INI);
472
bs = VK_BACK; /* Default value */
473
if (_stricmp(buf, INI_BACKSPACE_DEL) == 0)
478
* Build up default host name
480
strcpy(buf, fullhost);
482
strcat(buf, (bs == VK_BACK) ? INI_BACKSPACE_BS : INI_BACKSPACE_DEL);
483
WritePrivateProfileString(INI_HOSTS, INI_HOST "0", buf, TELNET_INI);
486
for (i = 0; i < 10; i++) {
487
if (!hostName[i][0]) /* End of the list? */
489
if (strncmp(hostName[i], fullhost, len) != 0) {
490
wsprintf(buf, INI_HOST "%d", ++n);
491
WritePrivateProfileString(INI_HOSTS, buf, hostName[i], TELNET_INI);
499
OpenTelnetConnection(void)
502
struct sockaddr_in sockaddr;
504
static struct kstream_crypt_ctl_block ctl;
507
tmpConfig = calloc(sizeof(CONFIG), 1);
509
if (bAutoConnection) {
510
tmpConfig->title = calloc(lstrlen(szHostName), 1);
511
lstrcpy(tmpConfig->title, (char *) szHostName);
513
nReturn = DoDialog("OPENTELNETDLG", OpenTelnetDlg);
514
if (nReturn == FALSE)
518
con = (CONNECTION *) GetNewConnection();
523
GetPrivateProfileInt(INI_TELNET, INI_WIDTH, DEF_WIDTH, TELNET_INI);
526
GetPrivateProfileInt(INI_TELNET, INI_HEIGHT, DEF_HEIGHT, TELNET_INI);
527
con->width = tmpConfig->width;
528
con->height = tmpConfig->height;
530
con->backspace = SaveHostName(tmpConfig->title, port_no);
532
if (con->backspace == VK_BACK) {
533
tmpConfig->backspace = TRUE;
534
con->ctrl_backspace = 0x7f;
536
tmpConfig->backspace = FALSE;
537
con->ctrl_backspace = 0x08;
540
tmpConfig->hwndTel = hWnd;
541
con->pScreen = InitNewScreen(tmpConfig);
550
ret = (SOCKET) socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
552
if (ret == SOCKET_ERROR) {
553
wsprintf(buf, "Socket error on socket = %d!", WSAGetLastError());
554
MessageBox(NULL, buf, NULL, MB_OK | MB_ICONEXCLAMATION);
555
if (con->pScreen != NULL)
556
DestroyWindow(con->pScreen->hWnd);
564
sockaddr.sin_family = AF_INET;
565
sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
566
sockaddr.sin_port = htons(0);
568
ret = bind(con->socket, (struct sockaddr *) &sockaddr,
569
(int) sizeof(struct sockaddr_in));
571
if (ret == SOCKET_ERROR) {
572
wsprintf(buf, "Socket error on bind!");
573
MessageBox(NULL, buf, NULL, MB_OK | MB_ICONEXCLAMATION);
574
if (con->pScreen != NULL)
575
DestroyWindow(con->pScreen->hWnd);
581
WSAAsyncSelect(con->socket, hWnd, WM_NETWORKEVENT,
582
FD_READ | FD_CLOSE | FD_CONNECT);
584
lstrcpy(szHostName, tmpConfig->title);
585
p = strchr(szHostName, '@');
588
strcpy (szUserName, szHostName);
589
strcpy(szHostName, ++p);
592
WSAAsyncGetHostByName(hWnd, WM_HOSTNAMEFOUND, szHostName, hostdata,
595
ctl.encrypt = auth_encrypt;
596
ctl.decrypt = auth_decrypt;
597
ctl.init = auth_init;
598
ctl.destroy = auth_destroy;
600
con->ks = kstream_create_from_fd(con->socket, &ctl, NULL);
605
kstream_set_buffer_mode(con->ks, 0);
612
GetNewConnection(void)
616
pCon = calloc(sizeof(CONNECTION), 1);
619
pCon->backspace = TRUE;
620
pCon->bResizeable = TRUE;
626
DoDialog(char *szDialog, DLGPROC lpfnDlgProc)
630
nReturn = DialogBox(hInst, szDialog, hWnd, lpfnDlgProc);
636
* FUNCTION: OpenTelnetDlg(HWND, unsigned, WORD, LONG)
638
* PURPOSE: Processes messages for "Open New Telnet Connection" dialog box
642
* WM_INITDIALOG - initialize dialog box
643
* WM_COMMAND - Input received
646
OpenTelnetDlg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
648
char szConnectName[256];
662
Ext = GetDialogBaseUnits();
663
xExt = (190 *LOWORD(Ext)) /4 ;
664
yExt = (72 * HIWORD(Ext)) /8 ;
665
GetPrivateProfileString(INI_HOSTS, INI_HOST "0", "", tmpName,
668
tmpCommaLoc = strchr(tmpName, ',');
671
SetDlgItemText(hDlg, TEL_CONNECT_NAME, tmpName);
673
hEdit = GetWindow(GetDlgItem(hDlg, TEL_CONNECT_NAME), GW_CHILD);
675
wsprintf(tmpBuf, INI_HOST "%d", iHostNum++);
676
GetPrivateProfileString(INI_HOSTS, tmpBuf, "", tmpName,
678
tmpCommaLoc = strchr(tmpName, ',');
682
SendDlgItemMessage(hDlg, TEL_CONNECT_NAME, CB_ADDSTRING, 0,
683
(LPARAM) ((LPSTR) tmpName));
688
EnableWindow(GetDlgItem(hDlg, IDC_FORWARD), 1);
689
SendDlgItemMessage(hDlg, IDC_FORWARD, BM_SETCHECK, forward_flag, 0);
691
EnableWindow(GetDlgItem(hDlg, IDC_FORWARDFORWARD), 1);
693
EnableWindow(GetDlgItem(hDlg, IDC_FORWARDFORWARD), 0);
694
SendDlgItemMessage(hDlg, IDC_FORWARDFORWARD, BM_SETCHECK,
695
forwardable_flag, 0);
699
EnableWindow(GetDlgItem(hDlg, IDC_ENCRYPT), 1);
700
SendDlgItemMessage(hDlg, IDC_ENCRYPT,
701
BM_SETCHECK, encrypt_flag, 0);
704
EnableWindow(GetDlgItem(hDlg, TEL_CONNECT_USERID), 1);
706
SetWindowPos(hDlg, NULL,
707
(GetSystemMetrics(SM_CXSCREEN)/2)-(xExt/2),
708
(GetSystemMetrics(SM_CYSCREEN)/2)-(yExt/2),
709
0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
710
ReleaseDC(hDlg, hDC);
711
SendMessage(hEdit, WM_USER + 1, 0, 0);
712
SendMessage(hDlg, WM_SETFOCUS, 0, 0);
718
case IDCANCEL: /* From the menu */
719
EndDialog(hDlg, FALSE);
724
forward_flag = (BOOL)SendDlgItemMessage(hDlg, IDC_FORWARD,
727
EnableWindow(GetDlgItem(hDlg, IDC_FORWARDFORWARD), 1);
729
EnableWindow(GetDlgItem(hDlg, IDC_FORWARDFORWARD), 0);
732
case IDC_FORWARDFORWARD:
733
forwardable_flag = (BOOL)SendDlgItemMessage(hDlg, IDC_FORWARDFORWARD,
740
encrypt_flag = (BOOL)SendDlgItemMessage(hDlg, IDC_ENCRYPT,
744
case TEL_CONNECT_USERID:
745
GetDlgItemText(hDlg, TEL_CONNECT_USERID, szUserName, sizeof(szUserName));
749
GetDlgItemText(hDlg, TEL_CONNECT_NAME, szConnectName, 256);
751
n = parse_cmdline (szConnectName);
753
MessageBox(hDlg, "You must enter a session name!",
757
tmpConfig->title = calloc(lstrlen(szHostName) + 1, 1);
758
lstrcpy(tmpConfig->title, szConnectName);
759
EndDialog(hDlg, TRUE);
770
* FUNCTION: TelnetSend(kstream ks, char *buf, int len, int flags)
772
* PURPOSE: This is a replacement for the WinSock send() function, to
773
* send a buffer of characters to an output socket. It differs
774
* by retrying endlessly if sending the bytes would cause
775
* the send() to block. <gnu@cygnus.com> observed EWOULDBLOCK
776
* errors when running using TCP Software's PC/TCP 3.0 stack,
777
* even when writing as little as 109 bytes into a socket
778
* that had no more than 9 bytes queued for output. Note also
779
* that a kstream is used during output rather than a socket
780
* to facilitate encryption.
782
* Eventually, for cleanliness and responsiveness, this
783
* routine should not loop; instead, if the send doesn't
784
* send all the bytes, it should put them into a buffer
785
* and return. Message handling code would send out the
786
* buffer whenever it gets an FD_WRITE message.
789
TelnetSend(kstream ks, char *buf, int len, int flags)
795
writelen = kstream_write(ks, buf, len);
797
if (writelen == len) /* Success, first or Nth time */
800
if (writelen == SOCKET_ERROR) {
801
if (WSAGetLastError() != WSAEWOULDBLOCK)
802
return (SOCKET_ERROR); /* Some error */
803
/* For WOULDBLOCK, immediately repeat the send. */
806
/* Partial write; update the pointers and retry. */
815
* Function: Trim leading and trailing white space from a string.
818
* s - the string to trim.
826
for (i = 0; s[i]; i++)
827
if (s[i] != ' ' && s[i] != '\t')
831
memmove(s, &s[i], l + 1);
833
for (l--; l >= 0; l--) {
834
if (s[l] != ' ' && s[l] != '\t')
845
* Reads hostname and port number off the command line.
849
* telnet <host> <port no>
850
* telnet -p <port no>
852
* Returns: TRUE if we have a hostname
855
parse_cmdline(char *cmdline)
859
*szHostName = '\0'; /* Nothing yet */
860
if (*cmdline == '\0') /* Empty command line? */
863
trim (cmdline); /* Remove excess spaces */
864
ptr = strchr (cmdline, ' '); /* Find 2nd token */
866
if (ptr != NULL) { /* Port number given */
867
*ptr++ = '\0'; /* Separate into 2 words */
868
port_no = atoi (ptr);
871
if (*cmdline != '-' && *cmdline != '/') { /* Host name given */
872
lstrcpy (szHostName, cmdline);
881
hexdump(char *msg, unsigned char *st, int cnt)
886
OutputDebugString("\r\n");
888
OutputDebugString(msg);
889
OutputDebugString("\r\n");
891
for(i = 0 ; i < cnt ; i++) {
894
for(j = 0 ; (j < 16) && ((i + j) < cnt) ; j++) {
895
wsprintf(strTmp,"%02x ", st[i + j]);
897
OutputDebugString("| ");
898
OutputDebugString(strTmp);
901
OutputDebugString("\r\n");