Develop and Download Open Source Software

Browse Subversion Repository

Contents of /branches/ssh_chacha20poly1305/ttssh2/ttxssh/ttxssh.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2728 - (show annotations) (download) (as text)
Sun Nov 14 15:53:21 2004 UTC (19 years, 5 months ago) by yutakakn
Original Path: ttssh2/branches/avendor/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 51976 byte(s)
no message

1 /*
2 Copyright (c) 1998-2001, Robert O'Callahan
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8 Redistributions of source code must retain the above copyright notice, this list of
9 conditions and the following disclaimer.
10
11 Redistributions in binary form must reproduce the above copyright notice, this list
12 of conditions and the following disclaimer in the documentation and/or other materials
13 provided with the distribution.
14
15 The name of Robert O'Callahan may not be used to endorse or promote products derived from
16 this software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21 THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /* Teraterm extension mechanism
30 Robert O'Callahan (roc+tt@cs.cmu.edu)
31
32 Teraterm by Takashi Teranishi (teranishi@rikaxp.riken.go.jp)
33 */
34
35 #include "ttxssh.h"
36 #include "fwdui.h"
37 #include "util.h"
38
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <io.h>
43 #include <fcntl.h>
44 #include <sys/stat.h>
45 #include <time.h>
46
47 #include "resource.h"
48 #include <commctrl.h>
49 #include <commdlg.h>
50 #ifdef INET6
51 #include <winsock2.h>
52 static char FAR *ProtocolFamilyList[] = { "UNSPEC", "IPv6", "IPv4", NULL };
53 #else
54 #include <winsock.h>
55 #endif /* INET6 */
56
57 #define MATCH_STR(s, o) _strnicmp((s), (o), NUM_ELEM(o) - 1)
58
59 /* This extension implements SSH, so we choose a load order in the
60 "protocols" range. */
61 #define ORDER 2500
62
63 #ifdef TERATERM32
64 static HICON SecureIcon = NULL;
65 #endif
66
67 static TInstVar FAR *pvar;
68
69 #ifdef TERATERM32
70 /* WIN32 allows multiple instances of a DLL */
71 static TInstVar InstVar;
72 #define GET_VAR()
73 #else
74 /* WIN16 does not allow multiple instances of a DLL */
75
76 /* maximum number of Tera Term instances */
77 #define MAXNUMINST 32
78 /* list of task handles for Tera Term instances */
79 static HANDLE FAR TaskList[MAXNUMINST];
80 /* variable sets for instances */
81 static TInstVar FAR *FAR InstVar[MAXNUMINST];
82
83 /* Here's how the TS settings work.
84 Whenever the TS settings are read or written to the INI file, then
85 the shared memory containing those settings is updated.
86 When Teraterm starts, the shared memory is read to initialize the TS
87 settings. */
88
89 /* TS settings shared across instances */
90 static TS_SSH ts_SSH_settings;
91
92
93 extern void SSH2_update_cipher_myproposal(PTInstVar pvar);
94
95
96 static BOOL NewVar()
97 {
98 int i = 0;
99 HANDLE Task = GetCurrentTask();
100
101 if (TaskList[0] == NULL)
102
103 if (Task == NULL)
104 return FALSE;
105 while ((i < MAXNUMINST) && (TaskList[i] != NULL))
106 i++;
107 if (i >= MAXNUMINST)
108 return FALSE;
109 pvar = (TInstVar FAR *) malloc(sizeof(TInstVar));
110 InstVar[i] = pvar;
111 TaskList[i] = Task;
112 return TRUE;
113 }
114
115 void DelVar()
116 {
117 int i = 0;
118 HANDLE Task = GetCurrentTask();
119
120 if (Task == NULL)
121 return;
122 while ((i < MAXNUMINST) && (TaskList[i] != Task))
123 i++;
124 if (i >= MAXNUMINST)
125 return;
126 free(TaskList[i]);
127 TaskList[i] = NULL;
128 }
129
130 BOOL GetVar()
131 {
132 int i = 0;
133 HANDLE Task = GetCurrentTask();
134
135 if (Task == NULL)
136 return FALSE;
137 while ((i < MAXNUMINST) && (TaskList[i] != Task))
138 i++;
139 if (i >= MAXNUMINST)
140 return FALSE;
141 pvar = InstVar[i];
142 return TRUE;
143 }
144
145 #define GET_VAR() if (!GetVar()) return
146 #endif
147
148 /*
149 This code makes lots of assumptions about the order in which Teraterm
150 does things, and how. A key assumption is that the Notification window
151 passed into WSAAsyncSelect is the main terminal window. We also assume
152 that the socket used in the first WSAconnect is the main session socket.
153 */
154
155 static void init_TTSSH(PTInstVar pvar)
156 {
157 pvar->socket = INVALID_SOCKET;
158 pvar->OldLargeIcon = NULL;
159 pvar->OldSmallIcon = NULL;
160 pvar->NotificationWindow = NULL;
161 pvar->hostdlg_activated = FALSE;
162 pvar->socket = INVALID_SOCKET;
163 pvar->NotificationWindow = NULL;
164 pvar->protocol_major = 0;
165 pvar->protocol_minor = 0;
166
167 PKT_init(pvar);
168 SSH_init(pvar);
169 CRYPT_init(pvar);
170 AUTH_init(pvar);
171 HOSTS_init(pvar);
172 FWD_init(pvar);
173 FWDUI_init(pvar);
174 }
175
176 static void uninit_TTSSH(PTInstVar pvar)
177 {
178 SSH_end(pvar);
179 PKT_end(pvar);
180 AUTH_end(pvar);
181 CRYPT_end(pvar);
182 HOSTS_end(pvar);
183 FWD_end(pvar);
184 FWDUI_end(pvar);
185
186 if (pvar->OldLargeIcon != NULL) {
187 PostMessage(pvar->NotificationWindow, WM_SETICON, ICON_BIG,
188 (LPARAM) pvar->OldLargeIcon);
189 pvar->OldLargeIcon = NULL;
190 }
191 if (pvar->OldSmallIcon != NULL) {
192 PostMessage(pvar->NotificationWindow, WM_SETICON, ICON_SMALL,
193 (LPARAM) pvar->OldSmallIcon);
194 pvar->OldSmallIcon = NULL;
195 }
196 }
197
198 static void PASCAL FAR TTXInit(PTTSet ts, PComVar cv)
199 {
200 #ifndef TERATERM32
201 if (!NewVar())
202 return; /* should be called first */
203 pvar->ts_SSH = &ts_SSH_settings;
204 #endif
205 pvar->settings = *pvar->ts_SSH;
206 pvar->ts = ts;
207 pvar->cv = cv;
208 pvar->fatal_error = FALSE;
209 pvar->showing_err = FALSE;
210 pvar->err_msg = NULL;
211
212 init_TTSSH(pvar);
213 }
214
215 static void normalize_cipher_order(char FAR * buf)
216 {
217 char ciphers_listed[SSH_CIPHER_MAX + 1];
218 char ciphers_allowed[SSH_CIPHER_MAX + 1];
219 int i, j;
220
221 /* SSH_CIPHER_NONE means that all ciphers below that one are disabled.
222 We *never* allow no encryption. */
223 #if 0
224 static char default_ciphers[] = {
225 SSH_CIPHER_3DES,
226 SSH_CIPHER_NONE,
227 SSH_CIPHER_DES, SSH_CIPHER_BLOWFISH
228 };
229 #else
230 // for SSH2(yutaka)
231 static char default_ciphers[] = {
232 SSH_CIPHER_AES128,
233 SSH_CIPHER_3DES_CBC,
234 SSH_CIPHER_3DES,
235 SSH_CIPHER_NONE,
236 SSH_CIPHER_DES, SSH_CIPHER_BLOWFISH
237 };
238 #endif
239
240 memset(ciphers_listed, 0, sizeof(ciphers_listed));
241
242 memset(ciphers_allowed, 0, sizeof(ciphers_allowed));
243 for (i = 0; i < NUM_ELEM(default_ciphers); i++) {
244 ciphers_allowed[default_ciphers[i]] = 1;
245 }
246
247 for (i = 0; buf[i] != 0; i++) {
248 int cipher_num = buf[i] - '0';
249
250 if (cipher_num < 0 || cipher_num > SSH_CIPHER_MAX
251 || !ciphers_allowed[cipher_num]
252 || ciphers_listed[cipher_num]) {
253 memmove(buf + i, buf + i + 1, strlen(buf + i + 1) + 1);
254 i--;
255 } else {
256 ciphers_listed[cipher_num] = 1;
257 }
258 }
259
260 for (j = 0; j < NUM_ELEM(default_ciphers); j++) {
261 int cipher_num = default_ciphers[j];
262
263 if (!ciphers_listed[cipher_num]) {
264 buf[i] = cipher_num + '0';
265 i++;
266 }
267 }
268
269 buf[i] = 0;
270 }
271
272 /* Remove local settings from the shared memory block. */
273 static void clear_local_settings(PTInstVar pvar)
274 {
275 pvar->ts_SSH->TryDefaultAuth = FALSE;
276 }
277
278 static BOOL read_BOOL_option(PCHAR fileName, char FAR * keyName, BOOL def)
279 {
280 char buf[1024];
281
282 buf[0] = 0;
283 GetPrivateProfileString("TTSSH", keyName, "", buf, sizeof(buf),
284 fileName);
285 if (buf[0] == 0) {
286 return def;
287 } else {
288 return atoi(buf) != 0 ||
289 stricmp(buf, "yes") == 0 || stricmp(buf, "y") == 0;
290 }
291 }
292
293 static void read_string_option(PCHAR fileName, char FAR * keyName,
294 char FAR * def, char FAR * buf, int bufSize)
295 {
296
297 buf[0] = 0;
298 GetPrivateProfileString("TTSSH", keyName, def, buf, bufSize, fileName);
299 }
300
301 static void read_ssh_options(PTInstVar pvar, PCHAR fileName)
302 {
303 extern void SSH2_update_cipher_myproposal(PTInstVar pvar);
304 char buf[1024];
305 TS_SSH FAR *settings = pvar->ts_SSH;
306
307 #define READ_STD_STRING_OPTION(name) \
308 read_string_option(fileName, #name, "", settings->name, sizeof(settings->name))
309
310 settings->Enabled = read_BOOL_option(fileName, "Enabled", FALSE);
311
312 buf[0] = 0;
313 GetPrivateProfileString("TTSSH", "Compression", "", buf, sizeof(buf),
314 fileName);
315 settings->CompressionLevel = atoi(buf);
316 if (settings->CompressionLevel < 0 || settings->CompressionLevel > 9) {
317 settings->CompressionLevel = 0;
318 }
319
320 READ_STD_STRING_OPTION(DefaultUserName);
321 READ_STD_STRING_OPTION(DefaultForwarding);
322 READ_STD_STRING_OPTION(DefaultRhostsLocalUserName);
323 READ_STD_STRING_OPTION(DefaultRhostsHostPrivateKeyFile);
324 READ_STD_STRING_OPTION(DefaultRSAPrivateKeyFile);
325
326 READ_STD_STRING_OPTION(CipherOrder);
327 normalize_cipher_order(settings->CipherOrder);
328 SSH2_update_cipher_myproposal(pvar); // yutaka
329
330 read_string_option(fileName, "KnownHostsFiles", "ssh_known_hosts",
331 settings->KnownHostsFiles,
332 sizeof(settings->KnownHostsFiles));
333
334 buf[0] = 0;
335 GetPrivateProfileString("TTSSH", "DefaultAuthMethod", "", buf,
336 sizeof(buf), fileName);
337 settings->DefaultAuthMethod = atoi(buf);
338 if (settings->DefaultAuthMethod != SSH_AUTH_PASSWORD
339 && settings->DefaultAuthMethod != SSH_AUTH_RSA
340 && settings->DefaultAuthMethod != SSH_AUTH_RHOSTS) {
341 /* this default can never be SSH_AUTH_RHOSTS_RSA because that is not a
342 selection in the dialog box; SSH_AUTH_RHOSTS_RSA is automatically chosen
343 when the dialog box has rhosts selected and an host private key file
344 is supplied. */
345 settings->DefaultAuthMethod = SSH_AUTH_PASSWORD;
346 }
347
348 buf[0] = 0;
349 GetPrivateProfileString("TTSSH", "LogLevel", "", buf, sizeof(buf),
350 fileName);
351 settings->LogLevel = atoi(buf);
352
353 buf[0] = 0;
354 GetPrivateProfileString("TTSSH", "WriteBufferSize", "", buf,
355 sizeof(buf), fileName);
356 settings->WriteBufferSize = atoi(buf);
357 if (settings->WriteBufferSize <= 0) {
358 settings->WriteBufferSize = 2 * 1024 * 1024;
359 }
360
361 settings->LocalForwardingIdentityCheck =
362 read_BOOL_option(fileName, "LocalForwardingIdentityCheck", TRUE);
363
364 // SSH protocol version (2004.10.11 yutaka)
365 settings->ssh_protocol_version = GetPrivateProfileInt("TTSSH", "ProtocolVersion", 1, fileName);
366
367 clear_local_settings(pvar);
368 }
369
370 static void write_ssh_options(PTInstVar pvar, PCHAR fileName,
371 TS_SSH FAR * settings)
372 {
373 char buf[1024];
374
375 WritePrivateProfileString("TTSSH", "Enabled",
376 settings->Enabled ? "1" : "0", fileName);
377
378 _itoa(settings->CompressionLevel, buf, 10);
379 WritePrivateProfileString("TTSSH", "Compression", buf, fileName);
380
381 WritePrivateProfileString("TTSSH", "DefaultUserName",
382 settings->DefaultUserName, fileName);
383
384 WritePrivateProfileString("TTSSH", "DefaultForwarding",
385 settings->DefaultForwarding, fileName);
386
387 WritePrivateProfileString("TTSSH", "CipherOrder",
388 settings->CipherOrder, fileName);
389
390 WritePrivateProfileString("TTSSH", "KnownHostsFiles",
391 settings->KnownHostsFiles, fileName);
392
393 WritePrivateProfileString("TTSSH", "DefaultRhostsLocalUserName",
394 settings->DefaultRhostsLocalUserName,
395 fileName);
396
397 WritePrivateProfileString("TTSSH", "DefaultRhostsHostPrivateKeyFile",
398 settings->DefaultRhostsHostPrivateKeyFile,
399 fileName);
400
401 WritePrivateProfileString("TTSSH", "DefaultRSAPrivateKeyFile",
402 settings->DefaultRSAPrivateKeyFile,
403 fileName);
404
405 _itoa(settings->DefaultAuthMethod, buf, 10);
406 WritePrivateProfileString("TTSSH", "DefaultAuthMethod", buf, fileName);
407
408 _itoa(settings->LogLevel, buf, 10);
409 WritePrivateProfileString("TTSSH", "LogLevel", buf, fileName);
410
411 _itoa(settings->WriteBufferSize, buf, 10);
412 WritePrivateProfileString("TTSSH", "WriteBufferSize", buf, fileName);
413
414 WritePrivateProfileString("TTSSH", "LocalForwardingIdentityCheck",
415 settings->
416 LocalForwardingIdentityCheck ? "1" : "0",
417 fileName);
418
419 // SSH protocol version (2004.10.11 yutaka)
420 WritePrivateProfileString("TTSSH", "ProtocolVersion",
421 settings->ssh_protocol_version==2 ? "2" : "1",
422 fileName);
423
424 }
425
426 /* find free port in all protocol family */
427 static unsigned short find_local_port(PTInstVar pvar)
428 {
429 int tries;
430 #ifdef INET6
431 SOCKET connecter;
432 struct addrinfo hints;
433 struct addrinfo FAR *res;
434 struct addrinfo FAR *res0;
435 unsigned short port;
436 char pname[NI_MAXHOST];
437 #endif /* INET6 */
438
439 if (pvar->session_settings.DefaultAuthMethod != SSH_AUTH_RHOSTS) {
440 return 0;
441 }
442
443 /* The random numbers here are only used to try to get fresh
444 ports across runs (dangling ports can cause bind errors
445 if we're unlucky). They do not need to be (and are not)
446 cryptographically strong.
447 */
448 srand((unsigned) GetTickCount());
449
450 #ifdef INET6
451 for (tries = 20; tries > 0; tries--) {
452 memset(&hints, 0, sizeof(hints));
453 hints.ai_family = pvar->ts->ProtocolFamily;
454 hints.ai_flags = AI_PASSIVE;
455 hints.ai_socktype = SOCK_STREAM;
456 port = (unsigned) rand() % 512 + 512;
457 _snprintf(pname, sizeof(pname), "%d", (int) port);
458 if (getaddrinfo(NULL, pname, &hints, &res0)) {
459 return 0;
460 /* NOT REACHED */
461 }
462
463 for (res = res0; res; res = res->ai_next) {
464 if (res->ai_family == AF_INET || res->ai_family == AF_INET6)
465 continue;
466
467 connecter =
468 socket(res->ai_family, res->ai_socktype, res->ai_protocol);
469 if (connecter == INVALID_SOCKET) {
470 freeaddrinfo(res0);
471 return 0;
472 }
473
474 if (bind(connecter, res->ai_addr, res->ai_addrlen) !=
475 SOCKET_ERROR) {
476 return port;
477 freeaddrinfo(res0);
478 closesocket(connecter);
479 } else if (WSAGetLastError() != WSAEADDRINUSE) {
480 closesocket(connecter);
481 freeaddrinfo(res0);
482 return 0;
483 }
484
485 closesocket(connecter);
486 }
487 freeaddrinfo(res0);
488 }
489
490 return 0;
491 #else
492 for (tries = 20; tries > 0; tries--) {
493 SOCKET connecter = socket(AF_INET, SOCK_STREAM, 0);
494 struct sockaddr_in connecter_addr;
495
496 connecter_addr.sin_family = AF_INET;
497 connecter_addr.sin_port = (unsigned) rand() % 512 + 512;
498 connecter_addr.sin_addr.s_addr = htonl(INADDR_ANY);
499
500 if (connecter == INVALID_SOCKET) {
501 return 0;
502 }
503
504 if (bind
505 (connecter, (struct sockaddr FAR *) &connecter_addr,
506 sizeof(connecter_addr)) != SOCKET_ERROR) {
507 closesocket(connecter);
508 return connecter_addr.sin_port;
509 } else if (WSAGetLastError() != WSAEADDRINUSE) {
510 closesocket(connecter);
511 return 0;
512 }
513
514 closesocket(connecter);
515 }
516
517 return 0;
518 #endif /* INET6 */
519 }
520
521 static int PASCAL FAR TTXconnect(SOCKET s,
522 const struct sockaddr FAR * name,
523 int namelen)
524 {
525 GET_VAR();
526
527 #ifdef INET6
528 if (pvar->socket == INVALID_SOCKET) {
529 struct sockaddr_storage ss;
530 int len;
531
532 pvar->socket = s;
533
534 memset(&ss, 0, sizeof(ss));
535 switch (pvar->ts->ProtocolFamily) {
536 case AF_INET:
537 len = sizeof(struct sockaddr_in);
538 ((struct sockaddr_in FAR *) &ss)->sin_family = AF_INET;
539 ((struct sockaddr_in FAR *) &ss)->sin_addr.s_addr = INADDR_ANY;
540 ((struct sockaddr_in FAR *) &ss)->sin_port =
541 htons(find_local_port(pvar));
542 break;
543 case AF_INET6:
544 len = sizeof(struct sockaddr_in6);
545 ((struct sockaddr_in6 FAR *) &ss)->sin6_family = AF_INET6;
546 #if 0 /* symbol "in6addr_any" is not included in wsock32.lib */
547 /* if wsock32.lib will be linked, we can't refer "in6addr_any" */
548 ((struct sockaddr_in6 FAR *) &ss)->sin6_addr = in6addr_any;
549 #eles
550 memset(&((struct sockaddr_in6 FAR *) &ss)->sin6_addr, 0,
551 sizeof(struct in_addr6));
552 #endif /* 0 */
553 ((struct sockaddr_in6 FAR *) &ss)->sin6_port =
554 htons(find_local_port(pvar));
555 break;
556 default:
557 /* NOT REACHED */
558 break;
559 }
560
561 bind(s, (struct sockaddr FAR *) &ss, len);
562 }
563 #else
564 if (pvar->socket == INVALID_SOCKET) {
565 struct sockaddr_in addr;
566
567 pvar->socket = s;
568
569 addr.sin_family = AF_INET;
570 addr.sin_port = htons(find_local_port(pvar));
571 addr.sin_addr.s_addr = INADDR_ANY;
572 memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
573
574 bind(s, (struct sockaddr FAR *) &addr, sizeof(addr));
575 }
576 #endif /* INET6 */
577
578 return (pvar->Pconnect) (s, name, namelen);
579 }
580
581 static int PASCAL FAR TTXWSAAsyncSelect(SOCKET s, HWND hWnd, u_int wMsg,
582 long lEvent)
583 {
584 GET_VAR();
585
586 if (s == pvar->socket) {
587 pvar->notification_events = lEvent;
588 pvar->notification_msg = wMsg;
589
590 if (pvar->NotificationWindow == NULL) {
591 pvar->NotificationWindow = hWnd;
592 AUTH_advance_to_next_cred(pvar);
593 }
594 }
595
596 return (pvar->PWSAAsyncSelect) (s, hWnd, wMsg, lEvent);
597 }
598
599 static int PASCAL FAR TTXrecv(SOCKET s, char FAR * buf, int len, int flags)
600 {
601 GET_VAR();
602
603 if (s == pvar->socket) {
604 return PKT_recv(pvar, buf, len);
605 } else {
606 return (pvar->Precv) (s, buf, len, flags);
607 }
608 }
609
610 static int PASCAL FAR TTXsend(SOCKET s, char const FAR * buf, int len,
611 int flags)
612 {
613 GET_VAR();
614
615 if (s == pvar->socket) {
616 SSH_send(pvar, buf, len);
617 return len;
618 } else {
619 return (pvar->Psend) (s, buf, len, flags);
620 }
621 }
622
623 void notify_established_secure_connection(PTInstVar pvar)
624 {
625 #ifdef TERATERM32
626 if (SecureIcon == NULL) {
627 SecureIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_SECURETT));
628 }
629
630 if (SecureIcon != NULL) {
631 pvar->OldSmallIcon =
632 (HICON) SendMessage(pvar->NotificationWindow, WM_GETICON,
633 ICON_SMALL, 0);
634 pvar->OldLargeIcon =
635 (HICON) SendMessage(pvar->NotificationWindow, WM_GETICON,
636 ICON_BIG, 0);
637 PostMessage(pvar->NotificationWindow, WM_SETICON, ICON_BIG,
638 (LPARAM) SecureIcon);
639 PostMessage(pvar->NotificationWindow, WM_SETICON, ICON_SMALL,
640 (LPARAM) SecureIcon);
641 }
642 #endif
643
644 notify_verbose_message(pvar, "Entering secure mode",
645 LOG_LEVEL_VERBOSE);
646 }
647
648 void notify_closed_connection(PTInstVar pvar)
649 {
650 PostMessage(pvar->NotificationWindow, WM_USER_COMMNOTIFY,
651 pvar->socket, MAKELPARAM(FD_CLOSE, 0));
652
653 SSH_notify_disconnecting(pvar, NULL);
654 AUTH_notify_disconnecting(pvar);
655 HOSTS_notify_disconnecting(pvar);
656 }
657
658 static void add_err_msg(PTInstVar pvar, char FAR * msg)
659 {
660 if (pvar->err_msg != NULL) {
661 char FAR *buf =
662 (char FAR *) malloc(strlen(pvar->err_msg) + 3 + strlen(msg));
663
664 strcpy(buf, pvar->err_msg);
665 strcat(buf, "\n\n");
666 strcat(buf, msg);
667 free(pvar->err_msg);
668 pvar->err_msg = buf;
669 } else {
670 pvar->err_msg = _strdup(msg);
671 }
672 }
673
674 void notify_nonfatal_error(PTInstVar pvar, char FAR * msg)
675 {
676 if (!pvar->showing_err) {
677 PostMessage(pvar->NotificationWindow, WM_COMMAND,
678 ID_SSHASYNCMESSAGEBOX, 0);
679 }
680 if (msg[0] != 0) {
681 notify_verbose_message(pvar, msg, LOG_LEVEL_ERROR);
682 add_err_msg(pvar, msg);
683 }
684 }
685
686 void notify_fatal_error(PTInstVar pvar, char FAR * msg)
687 {
688 if (msg[0] != 0) {
689 notify_verbose_message(pvar, msg, LOG_LEVEL_FATAL);
690 add_err_msg(pvar, msg);
691 }
692
693 if (!pvar->fatal_error) {
694 pvar->fatal_error = TRUE;
695
696 SSH_notify_disconnecting(pvar, msg);
697 AUTH_notify_disconnecting(pvar);
698 HOSTS_notify_disconnecting(pvar);
699
700 PostMessage(pvar->NotificationWindow, WM_USER_COMMNOTIFY,
701 pvar->socket, MAKELPARAM(FD_CLOSE,
702 (pvar->PWSAGetLastError) ()));
703 }
704 }
705
706 void notify_verbose_message(PTInstVar pvar, char FAR * msg, int level)
707 {
708 if (level <= pvar->session_settings.LogLevel) {
709 char buf[1024];
710 int file;
711
712 get_teraterm_dir_relative_name(buf, NUM_ELEM(buf), "TTSSH.LOG");
713 file = _open(buf, _O_RDWR | _O_APPEND | _O_CREAT | _O_TEXT,
714 _S_IREAD | _S_IWRITE);
715
716 if (file >= 0) {
717 _write(file, msg, strlen(msg));
718 _write(file, "\n", 1);
719 _close(file);
720 }
721 }
722 }
723
724 static void PASCAL FAR TTXOpenTCP(TTXSockHooks FAR * hooks)
725 {
726 GET_VAR();
727
728 if (pvar->settings.Enabled) {
729 char buf[1024] = "\nInitiating SSH session at ";
730 struct tm FAR *newtime;
731 time_t long_time;
732
733 pvar->session_settings = pvar->settings;
734
735 time(&long_time);
736 newtime = localtime(&long_time);
737 strcat(buf, asctime(newtime));
738 buf[strlen(buf) - 1] = 0;
739 notify_verbose_message(pvar, buf, LOG_LEVEL_VERBOSE);
740
741 FWDUI_load_settings(pvar);
742
743 pvar->cv->TelAutoDetect = FALSE;
744 /* This next line should not be needed because Teraterm's
745 CommLib should find ts->Telnet == 0 ... but we'll do this
746 just to be on the safe side. */
747 pvar->cv->TelFlag = FALSE;
748
749 pvar->Precv = *hooks->Precv;
750 pvar->Psend = *hooks->Psend;
751 pvar->PWSAAsyncSelect = *hooks->PWSAAsyncSelect;
752 pvar->Pconnect = *hooks->Pconnect;
753 pvar->PWSAGetLastError = *hooks->PWSAGetLastError;
754
755 *hooks->Precv = TTXrecv;
756 *hooks->Psend = TTXsend;
757 *hooks->PWSAAsyncSelect = TTXWSAAsyncSelect;
758 *hooks->Pconnect = TTXconnect;
759
760 SSH_open(pvar);
761 HOSTS_open(pvar);
762 FWDUI_open(pvar);
763 }
764 }
765
766 static void PASCAL FAR TTXCloseTCP(TTXSockHooks FAR * hooks)
767 {
768 GET_VAR();
769
770 if (pvar->session_settings.Enabled) {
771 pvar->socket = INVALID_SOCKET;
772
773 notify_verbose_message(pvar, "Terminating SSH session...",
774 LOG_LEVEL_VERBOSE);
775
776 *hooks->Precv = pvar->Precv;
777 *hooks->Psend = pvar->Psend;
778 *hooks->PWSAAsyncSelect = pvar->PWSAAsyncSelect;
779 *hooks->Pconnect = pvar->Pconnect;
780 }
781
782 uninit_TTSSH(pvar);
783 init_TTSSH(pvar);
784 }
785
786 static void enable_dlg_items(HWND dlg, int from, int to, BOOL enabled)
787 {
788 for (; from <= to; from++) {
789 EnableWindow(GetDlgItem(dlg, from), enabled);
790 }
791 }
792
793 static BOOL CALLBACK TTXHostDlg(HWND dlg, UINT msg, WPARAM wParam,
794 LPARAM lParam)
795 {
796 static char *ssh_version[] = {"SSH1", "SSH2", NULL};
797 PGetHNRec GetHNRec;
798 char EntName[7];
799 char TempHost[HostNameMaxLength + 1];
800 WORD i, j, w;
801 BOOL Ok;
802
803 GET_VAR();
804
805 switch (msg) {
806 case WM_INITDIALOG:
807 GetHNRec = (PGetHNRec) lParam;
808 SetWindowLong(dlg, DWL_USER, lParam);
809
810 if (GetHNRec->PortType == IdFile)
811 GetHNRec->PortType = IdTCPIP;
812 CheckRadioButton(dlg, IDC_HOSTTCPIP, IDC_HOSTSERIAL,
813 IDC_HOSTTCPIP + GetHNRec->PortType - 1);
814
815 strcpy(EntName, "Host");
816
817 i = 1;
818 do {
819 sprintf(&EntName[4], "%d", i);
820 GetPrivateProfileString("Hosts", EntName, "",
821 TempHost, sizeof(TempHost),
822 GetHNRec->SetupFN);
823 if (strlen(TempHost) > 0)
824 SendDlgItemMessage(dlg, IDC_HOSTNAME, CB_ADDSTRING,
825 0, (LPARAM) TempHost);
826 i++;
827 } while ((i <= 99) && (strlen(TempHost) > 0));
828
829 SendDlgItemMessage(dlg, IDC_HOSTNAME, EM_LIMITTEXT,
830 HostNameMaxLength - 1, 0);
831
832 SendDlgItemMessage(dlg, IDC_HOSTNAME, CB_SETCURSEL, 0, 0);
833
834 CheckRadioButton(dlg, IDC_HOSTTELNET, IDC_HOSTOTHER,
835 pvar->settings.Enabled ? IDC_HOSTSSH : GetHNRec->
836 Telnet ? IDC_HOSTTELNET : IDC_HOSTOTHER);
837 SendDlgItemMessage(dlg, IDC_HOSTTCPPORT, EM_LIMITTEXT, 5, 0);
838 SetDlgItemInt(dlg, IDC_HOSTTCPPORT, GetHNRec->TCPPort, FALSE);
839 #ifdef INET6
840 for (i = 0; ProtocolFamilyList[i]; ++i) {
841 SendDlgItemMessage(dlg, IDC_HOSTTCPPROTOCOL, CB_ADDSTRING,
842 0, (LPARAM) ProtocolFamilyList[i]);
843 }
844 SendDlgItemMessage(dlg, IDC_HOSTTCPPROTOCOL, EM_LIMITTEXT,
845 ProtocolFamilyMaxLength - 1, 0);
846 SendDlgItemMessage(dlg, IDC_HOSTTCPPROTOCOL, CB_SETCURSEL, 0, 0);
847 #endif /* INET6 */
848
849 /////// SSH version
850 for (i = 0; ssh_version[i]; ++i) {
851 SendDlgItemMessage(dlg, IDC_SSH_VERSION, CB_ADDSTRING,
852 0, (LPARAM) ssh_version[i]);
853 }
854 SendDlgItemMessage(dlg, IDC_SSH_VERSION, EM_LIMITTEXT,
855 NUM_ELEM(ssh_version) - 1, 0);
856
857 if (pvar->settings.ssh_protocol_version == 2) {
858 SendDlgItemMessage(dlg, IDC_SSH_VERSION, CB_SETCURSEL, 1, 0); // SSH2
859 } else {
860 SendDlgItemMessage(dlg, IDC_SSH_VERSION, CB_SETCURSEL, 0, 0); // SSH1
861 }
862
863 if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
864 enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, TRUE); // enabled
865 } else {
866 enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
867 }
868 /////// SSH version
869
870
871 j = 0;
872 w = 1;
873 strcpy(EntName, "COM");
874 for (i = 1; i <= GetHNRec->MaxComPort; i++) {
875 sprintf(&EntName[3], "%d", i);
876 SendDlgItemMessage(dlg, IDC_HOSTCOM, CB_ADDSTRING,
877 0, (LPARAM) EntName);
878 j++;
879 if (GetHNRec->ComPort == i)
880 w = j;
881 }
882 if (j > 0)
883 SendDlgItemMessage(dlg, IDC_HOSTCOM, CB_SETCURSEL, w - 1, 0);
884 else /* All com ports are already used */
885 GetHNRec->PortType = IdTCPIP;
886
887 if (GetHNRec->PortType == IdTCPIP)
888 enable_dlg_items(dlg, IDC_HOSTCOMLABEL, IDC_HOSTCOM, FALSE);
889 #ifdef INET6
890 else {
891 enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
892 FALSE);
893 enable_dlg_items(dlg, IDC_HOSTTCPPROTOCOLLABEL,
894 IDC_HOSTTCPPROTOCOL, FALSE);
895 }
896 #else
897 else
898 enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
899 FALSE);
900 #endif /* INET6 */
901
902 // Host dialog���t�H�[�J�X�������� (2004.10.2 yutaka)
903 {
904 HWND hwnd = GetDlgItem(dlg, IDC_HOSTNAME);
905 SetFocus(dlg);
906 SetFocus(hwnd);
907 //SendMessage(dlg, WM_COMMAND, IDC_HOSTTCPIP, 0);
908 }
909
910 return TRUE;
911
912 case WM_COMMAND:
913 switch (LOWORD(wParam)) {
914 case IDOK:
915 GetHNRec = (PGetHNRec) GetWindowLong(dlg, DWL_USER);
916 if (GetHNRec != NULL) {
917 if (IsDlgButtonChecked(dlg, IDC_HOSTTCPIP)) {
918 #ifdef INET6
919 char afstr[BUFSIZ];
920 #endif /* INET6 */
921 i = GetDlgItemInt(dlg, IDC_HOSTTCPPORT, &Ok, FALSE);
922 if (Ok) {
923 GetHNRec->TCPPort = i;
924 } else {
925 MessageBox(dlg, "Teraterm",
926 "The TCP port must be a number.",
927 MB_OK | MB_ICONEXCLAMATION);
928 return TRUE;
929 }
930 #ifdef INET6
931 #define getaf(str) \
932 ((strcmp((str), "IPv6") == 0) ? AF_INET6 : \
933 ((strcmp((str), "IPv4") == 0) ? AF_INET : AF_UNSPEC))
934 memset(afstr, 0, sizeof(afstr));
935 GetDlgItemText(dlg, IDC_HOSTTCPPROTOCOL, afstr,
936 sizeof(afstr));
937 GetHNRec->ProtocolFamily = getaf(afstr);
938 #endif /* INET6 */
939 GetHNRec->PortType = IdTCPIP;
940 GetDlgItemText(dlg, IDC_HOSTNAME, GetHNRec->HostName,
941 HostNameMaxLength);
942 GetHNRec->Telnet = FALSE;
943 pvar->hostdlg_activated = TRUE;
944 pvar->hostdlg_Enabled = FALSE;
945 if (IsDlgButtonChecked(dlg, IDC_HOSTTELNET)) {
946 GetHNRec->Telnet = TRUE;
947 } else if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
948 pvar->hostdlg_Enabled = TRUE;
949
950 // check SSH protocol version
951 memset(afstr, 0, sizeof(afstr));
952 GetDlgItemText(dlg, IDC_SSH_VERSION, afstr, sizeof(afstr));
953 if (stricmp(afstr, "SSH1") == 0) {
954 pvar->settings.ssh_protocol_version = 1;
955 } else {
956 pvar->settings.ssh_protocol_version = 2;
957 }
958 }
959 } else {
960 GetHNRec->PortType = IdSerial;
961 GetHNRec->HostName[0] = 0;
962 memset(EntName, 0, sizeof(EntName));
963 GetDlgItemText(dlg, IDC_HOSTCOM, EntName,
964 sizeof(EntName) - 1);
965 GetHNRec->ComPort = (BYTE) (EntName[3]) - 0x30;
966 if (strlen(EntName) > 4)
967 GetHNRec->ComPort =
968 GetHNRec->ComPort * 10 + (BYTE) (EntName[4]) -
969 0x30;
970 }
971 }
972 EndDialog(dlg, 1);
973 return TRUE;
974
975 case IDCANCEL:
976 EndDialog(dlg, 0);
977 return TRUE;
978
979 case IDC_HOSTTCPIP:
980 enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
981 TRUE);
982 #ifdef INET6
983 enable_dlg_items(dlg, IDC_HOSTTCPPROTOCOLLABEL,
984 IDC_HOSTTCPPROTOCOL, TRUE);
985 #endif /* INET6 */
986 enable_dlg_items(dlg, IDC_HOSTCOMLABEL, IDC_HOSTCOM, FALSE);
987
988 if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
989 enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, TRUE);
990 } else {
991 enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
992 }
993
994 // Host dialog���t�H�[�J�X�������� (2004.10.2 yutaka)
995 {
996 HWND hwnd = GetDlgItem(dlg, IDC_HOSTNAME);
997 SetFocus(dlg);
998 SetFocus(hwnd);
999 }
1000
1001 return TRUE;
1002
1003 case IDC_HOSTSERIAL:
1004 enable_dlg_items(dlg, IDC_HOSTCOMLABEL, IDC_HOSTCOM, TRUE);
1005 enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
1006 FALSE);
1007 #ifdef INET6
1008 enable_dlg_items(dlg, IDC_HOSTTCPPROTOCOLLABEL,
1009 IDC_HOSTTCPPROTOCOL, FALSE);
1010 #endif /* INET6 */
1011 enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
1012
1013 return TRUE;
1014
1015 case IDC_HOSTSSH:
1016 enable_dlg_items(dlg, IDC_SSH_VERSION,
1017 IDC_SSH_VERSION, TRUE);
1018 goto hostssh_enabled;
1019
1020 case IDC_HOSTTELNET:
1021 case IDC_HOSTOTHER:
1022 enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
1023 hostssh_enabled:
1024
1025 GetHNRec = (PGetHNRec) GetWindowLong(dlg, DWL_USER);
1026
1027 if (IsDlgButtonChecked(dlg, IDC_HOSTTELNET)) {
1028 if (GetHNRec != NULL)
1029 SetDlgItemInt(dlg, IDC_HOSTTCPPORT, GetHNRec->TelPort,
1030 FALSE);
1031 } else if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
1032 SetDlgItemInt(dlg, IDC_HOSTTCPPORT, 22, FALSE);
1033 }
1034 return TRUE;
1035
1036 case IDC_HOSTHELP:
1037 PostMessage(GetParent(dlg), WM_USER_DLGHELP2, 0, 0);
1038 }
1039 }
1040 return FALSE;
1041 }
1042
1043 static BOOL FAR PASCAL TTXGetHostName(HWND parent, PGetHNRec rec)
1044 {
1045 return (BOOL) DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_HOSTDLG),
1046 parent, TTXHostDlg, (LONG) rec);
1047 }
1048
1049 static void PASCAL FAR TTXGetUIHooks(TTXUIHooks FAR * hooks)
1050 {
1051 GET_VAR();
1052
1053 *hooks->GetHostName = TTXGetHostName;
1054 }
1055
1056 static void FAR PASCAL TTXReadINIFile(PCHAR fileName, PTTSet ts)
1057 {
1058 GET_VAR();
1059
1060 (pvar->ReadIniFile) (fileName, ts);
1061 read_ssh_options(pvar, fileName);
1062 pvar->settings = *pvar->ts_SSH;
1063 notify_verbose_message(pvar, "Reading INI file", LOG_LEVEL_VERBOSE);
1064 FWDUI_load_settings(pvar);
1065 }
1066
1067 static void FAR PASCAL TTXWriteINIFile(PCHAR fileName, PTTSet ts)
1068 {
1069 GET_VAR();
1070
1071 (pvar->WriteIniFile) (fileName, ts);
1072 *pvar->ts_SSH = pvar->settings;
1073 clear_local_settings(pvar);
1074 notify_verbose_message(pvar, "Writing INI file", LOG_LEVEL_VERBOSE);
1075 write_ssh_options(pvar, fileName, pvar->ts_SSH);
1076 }
1077
1078 static void read_ssh_options_from_user_file(PTInstVar pvar,
1079 char FAR * user_file_name)
1080 {
1081 if (user_file_name[0] == '.') {
1082 read_ssh_options(pvar, user_file_name);
1083 } else {
1084 char buf[1024];
1085
1086 get_teraterm_dir_relative_name(buf, sizeof(buf), user_file_name);
1087 read_ssh_options(pvar, buf);
1088 }
1089
1090 pvar->settings = *pvar->ts_SSH;
1091 FWDUI_load_settings(pvar);
1092 }
1093
1094 /* returns 1 if the option text must be deleted */
1095 static int parse_option(PTInstVar pvar, char FAR * option)
1096 {
1097 if ((option[0] == '-' || option[0] == '/')) {
1098 if (MATCH_STR(option + 1, "ssh") == 0) {
1099 if (option[4] == 0) {
1100 pvar->settings.Enabled = 1;
1101 } else if (MATCH_STR(option + 4, "-L") == 0
1102 || MATCH_STR(option + 4, "-R") == 0
1103 || stricmp(option + 4, "-X") == 0) {
1104 if (pvar->settings.DefaultForwarding[0] == 0) {
1105 strcpy(pvar->settings.DefaultForwarding, option + 5);
1106 } else {
1107 strcat(pvar->settings.DefaultForwarding, ";");
1108 strcat(pvar->settings.DefaultForwarding, option + 5);
1109 }
1110 } else if (MATCH_STR(option + 4, "-f=") == 0) {
1111 read_ssh_options_from_user_file(pvar, option + 7);
1112 } else if (MATCH_STR(option + 4, "-v") == 0) {
1113 pvar->settings.LogLevel = LOG_LEVEL_VERBOSE;
1114 } else if (stricmp(option + 4, "-autologin") == 0
1115 || stricmp(option + 4, "-autologon") == 0) {
1116 pvar->settings.TryDefaultAuth = TRUE;
1117 } else if (MATCH_STR(option + 4, "-consume=") == 0) {
1118 read_ssh_options_from_user_file(pvar, option + 13);
1119 DeleteFile(option + 13);
1120 } else {
1121 char buf[1024];
1122
1123 _snprintf(buf, sizeof(buf),
1124 "Unrecognized command-line option: %s", option);
1125 buf[sizeof(buf) - 1] = 0;
1126
1127 MessageBox(NULL, buf, "TTSSH", MB_OK | MB_ICONEXCLAMATION);
1128 }
1129
1130 return 1;
1131 } else if (MATCH_STR(option + 1, "t=") == 0) {
1132 if (strcmp(option + 3, "2") == 0) {
1133 pvar->settings.Enabled = 1;
1134 return 1;
1135 } else {
1136 pvar->settings.Enabled = 0;
1137 }
1138 } else if (MATCH_STR(option + 1, "f=") == 0) {
1139 read_ssh_options_from_user_file(pvar, option + 3);
1140
1141 // /1 ������ /2 �I�v�V�������V�K���� (2004.10.3 yutaka)
1142 } else if (MATCH_STR(option + 1, "1") == 0) {
1143 // command line: /ssh /1 is SSH1 only
1144 pvar->settings.ssh_protocol_version = 1;
1145
1146 } else if (MATCH_STR(option + 1, "2") == 0) {
1147 // command line: /ssh /2 is SSH2 & SSH1
1148 pvar->settings.ssh_protocol_version = 2;
1149
1150 } else if (MATCH_STR(option + 1, "nossh") == 0) {
1151 // '/nossh' �I�v�V�����������B
1152 // TERATERM.INI ��SSH���L�������������������A������Cygterm���N��������������
1153 // �����������������B(2004.10.11 yutaka)
1154 pvar->settings.Enabled = 0;
1155
1156 }
1157
1158 }
1159
1160 return 0;
1161 }
1162
1163 static void FAR PASCAL TTXParseParam(PCHAR param, PTTSet ts,
1164 PCHAR DDETopic)
1165 {
1166 int i;
1167 BOOL inParam = FALSE;
1168 BOOL inQuotes = FALSE;
1169 PCHAR option = NULL;
1170 GET_VAR();
1171
1172 if (pvar->hostdlg_activated) {
1173 pvar->settings.Enabled = pvar->hostdlg_Enabled;
1174 }
1175
1176 for (i = 0; param[i] != 0; i++) {
1177 if (inQuotes ? param[i] ==
1178 '"' : (param[i] == ' ' || param[i] == '\t')) {
1179 if (option != NULL) {
1180 char ch = param[i];
1181
1182 param[i] = 0;
1183 if (parse_option
1184 (pvar, *option == '"' ? option + 1 : option)) {
1185 memset(option, ' ', i + 1 - (option - param));
1186 } else {
1187 param[i] = ch;
1188 }
1189 option = NULL;
1190 }
1191 inParam = FALSE;
1192 inQuotes = FALSE;
1193 } else if (!inParam) {
1194 if (param[i] == '"') {
1195 inQuotes = TRUE;
1196 inParam = TRUE;
1197 option = param + i;
1198 } else if (param[i] != ' ' && param[i] != '\t') {
1199 inParam = TRUE;
1200 option = param + i;
1201 }
1202 }
1203 }
1204
1205 if (option != NULL) {
1206 if (parse_option(pvar, option)) {
1207 memset(option, ' ', i - (option - param));
1208 }
1209 }
1210
1211 FWDUI_load_settings(pvar);
1212
1213 (pvar->ParseParam) (param, ts, DDETopic);
1214
1215 }
1216
1217 static void PASCAL FAR TTXGetSetupHooks(TTXSetupHooks FAR * hooks)
1218 {
1219 GET_VAR();
1220
1221 pvar->ReadIniFile = *hooks->ReadIniFile;
1222 pvar->WriteIniFile = *hooks->WriteIniFile;
1223 pvar->ParseParam = *hooks->ParseParam;
1224
1225 *hooks->ReadIniFile = TTXReadINIFile;
1226 *hooks->WriteIniFile = TTXWriteINIFile;
1227 *hooks->ParseParam = TTXParseParam;
1228 }
1229
1230 static void PASCAL FAR TTXSetWinSize(int rows, int cols)
1231 {
1232 GET_VAR();
1233
1234 SSH_notify_win_size(pvar, cols, rows);
1235 }
1236
1237 static void insertMenuBeforeItem(HMENU menu, WORD beforeItemID, WORD flags,
1238 WORD newItemID, char FAR * text)
1239 {
1240 int i, j;
1241
1242 for (i = GetMenuItemCount(menu) - 1; i >= 0; i--) {
1243 HMENU submenu = GetSubMenu(menu, i);
1244
1245 for (j = GetMenuItemCount(submenu) - 1; j >= 0; j--) {
1246 if (GetMenuItemID(submenu, j) == beforeItemID) {
1247 InsertMenu(submenu, j, MF_BYPOSITION | flags, newItemID,
1248 text);
1249 return;
1250 }
1251 }
1252 }
1253 }
1254
1255 static void PASCAL FAR TTXModifyMenu(HMENU menu)
1256 {
1257 GET_VAR();
1258
1259 /* inserts before ID_HELP_ABOUT */
1260 insertMenuBeforeItem(menu, 50990, MF_ENABLED, ID_ABOUTMENU,
1261 "About &TTSSH...");
1262
1263 /* inserts before ID_SETUP_TCPIP */
1264 insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHSETUPMENU,
1265 "SS&H...");
1266 /* inserts before ID_SETUP_TCPIP */
1267 insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHAUTHSETUPMENU,
1268 "SSH &Authentication...");
1269 /* inserts before ID_SETUP_TCPIP */
1270 insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHFWDSETUPMENU,
1271 "SSH F&orwarding...");
1272 }
1273
1274 static void append_about_text(HWND dlg, char FAR * prefix, char FAR * msg)
1275 {
1276 SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0,
1277 (LPARAM) prefix);
1278 SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0, (LPARAM) msg);
1279 SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0,
1280 (LPARAM) (char FAR *) "\r\n");
1281 }
1282
1283 static void init_about_dlg(PTInstVar pvar, HWND dlg)
1284 {
1285 char buf[1024];
1286
1287 // TTSSH�_�C�A���O���\������SSH������������ (2004.10.30 yutaka)
1288
1289 if (pvar->socket != INVALID_SOCKET) {
1290 if (SSHv1(pvar)) {
1291 SSH_get_server_ID_info(pvar, buf, sizeof(buf));
1292 append_about_text(dlg, "Server ID: ", buf);
1293 SSH_get_protocol_version_info(pvar, buf, sizeof(buf));
1294 append_about_text(dlg, "Using protocol: ", buf);
1295 CRYPT_get_cipher_info(pvar, buf, sizeof(buf));
1296 append_about_text(dlg, "Encryption: ", buf);
1297 CRYPT_get_server_key_info(pvar, buf, sizeof(buf));
1298 append_about_text(dlg, "Server keys: ", buf);
1299 AUTH_get_auth_info(pvar, buf, sizeof(buf));
1300 append_about_text(dlg, "Authentication: ", buf);
1301 SSH_get_compression_info(pvar, buf, sizeof(buf));
1302 append_about_text(dlg, "Compression: ", buf);
1303
1304 } else { // SSH2
1305 SSH_get_server_ID_info(pvar, buf, sizeof(buf));
1306 append_about_text(dlg, "Server ID: ", buf);
1307
1308 append_about_text(dlg, "Client ID: ", pvar->client_version_string);
1309
1310 SSH_get_protocol_version_info(pvar, buf, sizeof(buf));
1311 append_about_text(dlg, "Using protocol: ", buf);
1312
1313 if (pvar->kex_type == KEX_DH_GRP1_SHA1) {
1314 strcpy(buf, KEX_DH1);
1315 } else if (pvar->kex_type == KEX_DH_GRP14_SHA1) {
1316 strcpy(buf, KEX_DH14);
1317 } else {
1318 strcpy(buf, KEX_DHGEX);
1319 }
1320 append_about_text(dlg, "KEX: ", buf);
1321
1322 if (pvar->hostkey_type == KEY_DSA) {
1323 strcpy(buf, "ssh-dss");
1324 } else {
1325 strcpy(buf, "ssh-rsa");
1326 }
1327 append_about_text(dlg, "Host Key: ", buf);
1328
1329 CRYPT_get_cipher_info(pvar, buf, sizeof(buf));
1330 append_about_text(dlg, "Encryption: ", buf);
1331 CRYPT_get_server_key_info(pvar, buf, sizeof(buf));
1332 append_about_text(dlg, "Server keys: ", buf);
1333 AUTH_get_auth_info(pvar, buf, sizeof(buf));
1334 append_about_text(dlg, "Authentication: ", buf);
1335 SSH_get_compression_info(pvar, buf, sizeof(buf));
1336 append_about_text(dlg, "Compression: ", buf);
1337
1338 }
1339 }
1340 }
1341
1342 static BOOL CALLBACK TTXAboutDlg(HWND dlg, UINT msg, WPARAM wParam,
1343 LPARAM lParam)
1344 {
1345 switch (msg) {
1346 case WM_INITDIALOG:
1347 init_about_dlg((PTInstVar) lParam, dlg);
1348 return TRUE;
1349 case WM_COMMAND:
1350 switch (LOWORD(wParam)) {
1351 case IDOK:
1352 EndDialog(dlg, 1);
1353 return TRUE;
1354 case IDCANCEL: /* there isn't a cancel button, but other Windows
1355 UI things can send this message */
1356 EndDialog(dlg, 0);
1357 return TRUE;
1358 }
1359 break;
1360 }
1361
1362 return FALSE;
1363 }
1364
1365 static char FAR *get_cipher_name(int cipher)
1366 {
1367 switch (cipher) {
1368 case SSH_CIPHER_NONE:
1369 return "<ciphers below this line are disabled>";
1370 case SSH_CIPHER_RC4:
1371 return "RC4";
1372 case SSH_CIPHER_3DES:
1373 return "3DES";
1374 case SSH_CIPHER_DES:
1375 return "DES";
1376 case SSH_CIPHER_IDEA:
1377 return "IDEA";
1378 case SSH_CIPHER_TSS:
1379 return "TSS";
1380 case SSH_CIPHER_BLOWFISH:
1381 return "Blowfish";
1382
1383 // for SSH2(yutaka)
1384 case SSH_CIPHER_AES128:
1385 return "AES128(SSH2)";
1386 case SSH_CIPHER_3DES_CBC:
1387 return "3DES-CBC(SSH2)";
1388
1389 default:
1390 return NULL;
1391 }
1392 }
1393
1394 static void set_move_button_status(HWND dlg)
1395 {
1396 HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1397 int curPos = (int) SendMessage(cipherControl, LB_GETCURSEL, 0, 0);
1398 int maxPos = (int) SendMessage(cipherControl, LB_GETCOUNT, 0, 0) - 1;
1399
1400 EnableWindow(GetDlgItem(dlg, IDC_SSHMOVECIPHERUP), curPos > 0
1401 && curPos <= maxPos);
1402 EnableWindow(GetDlgItem(dlg, IDC_SSHMOVECIPHERDOWN), curPos >= 0
1403 && curPos < maxPos);
1404 }
1405
1406 static void init_setup_dlg(PTInstVar pvar, HWND dlg)
1407 {
1408 HWND compressionControl = GetDlgItem(dlg, IDC_SSHCOMPRESSIONLEVEL);
1409 HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1410 int i;
1411 int ch;
1412
1413 SendMessage(compressionControl, TBM_SETRANGE, TRUE, MAKELONG(0, 9));
1414 SendMessage(compressionControl, TBM_SETPOS, TRUE,
1415 pvar->settings.CompressionLevel);
1416
1417 normalize_cipher_order(pvar->settings.CipherOrder);
1418 SSH2_update_cipher_myproposal(pvar); // yutaka
1419
1420 for (i = 0; pvar->settings.CipherOrder[i] != 0; i++) {
1421 int cipher = pvar->settings.CipherOrder[i] - '0';
1422 char FAR *name = get_cipher_name(cipher);
1423
1424 if (name != NULL) {
1425 SendMessage(cipherControl, LB_ADDSTRING, 0, (LPARAM) name);
1426 }
1427 }
1428
1429 SendMessage(cipherControl, LB_SETCURSEL, 0, 0);
1430 set_move_button_status(dlg);
1431
1432 for (i = 0; (ch = pvar->settings.KnownHostsFiles[i]) != 0 && ch != ';';
1433 i++) {
1434 }
1435 if (ch != 0) {
1436 pvar->settings.KnownHostsFiles[i] = 0;
1437 SetDlgItemText(dlg, IDC_READWRITEFILENAME,
1438 pvar->settings.KnownHostsFiles);
1439 pvar->settings.KnownHostsFiles[i] = ch;
1440 SetDlgItemText(dlg, IDC_READONLYFILENAME,
1441 pvar->settings.KnownHostsFiles + i + 1);
1442 } else {
1443 SetDlgItemText(dlg, IDC_READWRITEFILENAME,
1444 pvar->settings.KnownHostsFiles);
1445 }
1446 }
1447
1448 void get_teraterm_dir_relative_name(char FAR * buf, int bufsize,
1449 char FAR * basename)
1450 {
1451 int filename_start = 0;
1452 int i;
1453 int ch;
1454
1455 if (basename[0] == '\\' || basename[0] == '/'
1456 || (basename[0] != 0 && basename[1] == ':')) {
1457 strncpy(buf, basename, bufsize);
1458 buf[bufsize - 1] = 0;
1459 return;
1460 }
1461
1462 GetModuleFileName(NULL, buf, bufsize);
1463 for (i = 0; (ch = buf[i]) != 0; i++) {
1464 if (ch == '\\' || ch == '/' || ch == ':') {
1465 filename_start = i + 1;
1466 }
1467 }
1468
1469 if (bufsize > filename_start) {
1470 strncpy(buf + filename_start, basename, bufsize - filename_start);
1471 }
1472 buf[bufsize - 1] = 0;
1473 }
1474
1475 int copy_teraterm_dir_relative_path(char FAR * dest, int destsize,
1476 char FAR * basename)
1477 {
1478 char buf[1024];
1479 int filename_start = 0;
1480 int i;
1481 int ch, ch2;
1482
1483 if (basename[0] != '\\' && basename[0] != '/'
1484 && (basename[0] == 0 || basename[1] != ':')) {
1485 strncpy(dest, basename, destsize);
1486 dest[destsize - 1] = 0;
1487 return strlen(dest);
1488 }
1489
1490 GetModuleFileName(NULL, buf, sizeof(buf));
1491 for (i = 0; (ch = buf[i]) != 0; i++) {
1492 if (ch == '\\' || ch == '/' || ch == ':') {
1493 filename_start = i + 1;
1494 }
1495 }
1496
1497 for (i = 0; i < filename_start; i++) {
1498 ch = toupper(buf[i]);
1499 ch2 = toupper(basename[i]);
1500
1501 if (ch == ch2
1502 || ((ch == '\\' || ch == '/')
1503 && (ch2 == '\\' || ch2 == '/'))) {
1504 } else {
1505 break;
1506 }
1507 }
1508
1509 if (i == filename_start) {
1510 strncpy(dest, basename + i, destsize);
1511 } else {
1512 strncpy(dest, basename, destsize);
1513 }
1514 dest[destsize - 1] = 0;
1515 return strlen(dest);
1516 }
1517
1518 static void complete_setup_dlg(PTInstVar pvar, HWND dlg)
1519 {
1520 char buf[4096];
1521 char buf2[1024];
1522 HWND compressionControl = GetDlgItem(dlg, IDC_SSHCOMPRESSIONLEVEL);
1523 HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1524 int i, j, buf2index, bufindex;
1525 int count = (int) SendMessage(cipherControl, LB_GETCOUNT, 0, 0);
1526
1527 pvar->settings.CompressionLevel =
1528 (int) SendMessage(compressionControl, TBM_GETPOS, 0, 0);
1529
1530 buf2index = 0;
1531 for (i = 0; i < count; i++) {
1532 int len = SendMessage(cipherControl, LB_GETTEXTLEN, i, 0);
1533
1534 if (len > 0 && len < sizeof(buf)) { /* should always be true */
1535 buf[0] = 0;
1536 SendMessage(cipherControl, LB_GETTEXT, i, (LPARAM) buf);
1537 for (j = 0;
1538 j <= SSH_CIPHER_MAX
1539 && strcmp(buf, get_cipher_name(j)) != 0; j++) {
1540 }
1541 if (j <= SSH_CIPHER_MAX) {
1542 buf2[buf2index] = '0' + j;
1543 buf2index++;
1544 }
1545 }
1546 }
1547 buf2[buf2index] = 0;
1548 normalize_cipher_order(buf2);
1549 strcpy(pvar->settings.CipherOrder, buf2);
1550 SSH2_update_cipher_myproposal(pvar); // yutaka
1551
1552 buf[0] = 0;
1553 GetDlgItemText(dlg, IDC_READWRITEFILENAME, buf, sizeof(buf));
1554 j = copy_teraterm_dir_relative_path(pvar->settings.KnownHostsFiles,
1555 sizeof(pvar->settings.
1556 KnownHostsFiles), buf);
1557 buf[0] = 0;
1558 bufindex = 0;
1559 GetDlgItemText(dlg, IDC_READONLYFILENAME, buf, sizeof(buf));
1560 for (i = 0; buf[i] != 0; i++) {
1561 if (buf[i] == ';') {
1562 buf[i] = 0;
1563 if (j < sizeof(pvar->settings.KnownHostsFiles) - 1) {
1564 pvar->settings.KnownHostsFiles[j] = ';';
1565 j++;
1566 j += copy_teraterm_dir_relative_path(pvar->settings.
1567 KnownHostsFiles + j,
1568 sizeof(pvar->settings.
1569 KnownHostsFiles)
1570 - j, buf + bufindex);
1571 }
1572 bufindex = i + 1;
1573 }
1574 }
1575 if (bufindex < i && j < sizeof(pvar->settings.KnownHostsFiles) - 1) {
1576 pvar->settings.KnownHostsFiles[j] = ';';
1577 j++;
1578 copy_teraterm_dir_relative_path(pvar->settings.KnownHostsFiles + j,
1579 sizeof(pvar->settings.
1580 KnownHostsFiles) - j,
1581 buf + bufindex);
1582 }
1583 }
1584
1585 static void move_cur_sel_delta(HWND listbox, int delta)
1586 {
1587 int curPos = (int) SendMessage(listbox, LB_GETCURSEL, 0, 0);
1588 int maxPos = (int) SendMessage(listbox, LB_GETCOUNT, 0, 0) - 1;
1589 int newPos = curPos + delta;
1590 char buf[1024];
1591
1592 if (curPos >= 0 && newPos >= 0 && newPos <= maxPos) {
1593 int len = SendMessage(listbox, LB_GETTEXTLEN, curPos, 0);
1594
1595 if (len > 0 && len < sizeof(buf)) { /* should always be true */
1596 buf[0] = 0;
1597 SendMessage(listbox, LB_GETTEXT, curPos, (LPARAM) buf);
1598 SendMessage(listbox, LB_DELETESTRING, curPos, 0);
1599 SendMessage(listbox, LB_INSERTSTRING, newPos,
1600 (LPARAM) (char FAR *) buf);
1601 SendMessage(listbox, LB_SETCURSEL, newPos, 0);
1602 }
1603 }
1604 }
1605
1606 static int get_keys_file_name(HWND parent, char FAR * buf, int bufsize,
1607 int readonly)
1608 {
1609 #ifdef TERATERM32
1610 OPENFILENAME params;
1611 char fullname_buf[2048] = "ssh_known_hosts";
1612
1613 params.lStructSize = sizeof(OPENFILENAME);
1614 params.hwndOwner = parent;
1615 params.lpstrFilter = NULL;
1616 params.lpstrCustomFilter = NULL;
1617 params.nFilterIndex = 0;
1618 buf[0] = 0;
1619 params.lpstrFile = fullname_buf;
1620 params.nMaxFile = sizeof(fullname_buf);
1621 params.lpstrFileTitle = NULL;
1622 params.lpstrInitialDir = NULL;
1623 params.lpstrTitle =
1624 readonly ? "Choose a read-only known-hosts file to add" :
1625 "Choose a read/write known-hosts file";
1626 params.Flags = (readonly ? OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST : 0)
1627 | OFN_HIDEREADONLY | (!readonly ? OFN_NOREADONLYRETURN : 0);
1628 params.lpstrDefExt = NULL;
1629
1630 if (GetOpenFileName(&params) != 0) {
1631 copy_teraterm_dir_relative_path(buf, bufsize, fullname_buf);
1632 return 1;
1633 } else {
1634 int err = CommDlgExtendedError();
1635
1636 if (err != 0) {
1637 char buf[1024];
1638
1639 _snprintf(buf, sizeof(buf),
1640 "Cannot show file dialog box: error %d", err);
1641 buf[sizeof(buf) - 1] = 0;
1642 MessageBox(parent, buf, "TTSSH Error",
1643 MB_OK | MB_ICONEXCLAMATION);
1644 }
1645
1646 return 0;
1647 }
1648 #else
1649 return 0;
1650 #endif
1651 }
1652
1653 static void choose_read_write_file(HWND dlg)
1654 {
1655 char buf[1024];
1656
1657 if (get_keys_file_name(dlg, buf, sizeof(buf), 0)) {
1658 SetDlgItemText(dlg, IDC_READWRITEFILENAME, buf);
1659 }
1660 }
1661
1662 static void choose_read_only_file(HWND dlg)
1663 {
1664 char buf[1024];
1665 char buf2[4096];
1666
1667 if (get_keys_file_name(dlg, buf, sizeof(buf), 1)) {
1668 buf2[0] = 0;
1669 GetDlgItemText(dlg, IDC_READONLYFILENAME, buf2, sizeof(buf2));
1670 if (buf2[0] != 0 && buf2[strlen(buf2) - 1] != ';') {
1671 strncat(buf2, ";", sizeof(buf2));
1672 }
1673 strncat(buf2, buf, sizeof(buf2));
1674 SetDlgItemText(dlg, IDC_READONLYFILENAME, buf2);
1675 }
1676 }
1677
1678 static BOOL CALLBACK TTXSetupDlg(HWND dlg, UINT msg, WPARAM wParam,
1679 LPARAM lParam)
1680 {
1681 switch (msg) {
1682 case WM_INITDIALOG:
1683 SetWindowLong(dlg, DWL_USER, lParam);
1684 init_setup_dlg((PTInstVar) lParam, dlg);
1685 return TRUE;
1686 case WM_COMMAND:
1687 switch (LOWORD(wParam)) {
1688 case IDOK:
1689 complete_setup_dlg((PTInstVar) GetWindowLong(dlg, DWL_USER),
1690 dlg);
1691 EndDialog(dlg, 1);
1692 return TRUE;
1693 case IDCANCEL: /* there isn't a cancel button, but other Windows
1694 UI things can send this message */
1695 EndDialog(dlg, 0);
1696 return TRUE;
1697 case IDC_SSHMOVECIPHERUP:
1698 move_cur_sel_delta(GetDlgItem(dlg, IDC_SSHCIPHERPREFS), -1);
1699 set_move_button_status(dlg);
1700 SetFocus(GetDlgItem(dlg, IDC_SSHCIPHERPREFS));
1701 return TRUE;
1702 case IDC_SSHMOVECIPHERDOWN:
1703 move_cur_sel_delta(GetDlgItem(dlg, IDC_SSHCIPHERPREFS), 1);
1704 set_move_button_status(dlg);
1705 SetFocus(GetDlgItem(dlg, IDC_SSHCIPHERPREFS));
1706 return TRUE;
1707 case IDC_SSHCIPHERPREFS:
1708 set_move_button_status(dlg);
1709 return TRUE;
1710 case IDC_CHOOSEREADWRITEFILE:
1711 choose_read_write_file(dlg);
1712 return TRUE;
1713 case IDC_CHOOSEREADONLYFILE:
1714 choose_read_only_file(dlg);
1715 return TRUE;
1716 }
1717 break;
1718 }
1719
1720 return FALSE;
1721 }
1722
1723 static int PASCAL FAR TTXProcessCommand(HWND hWin, WORD cmd)
1724 {
1725 GET_VAR();
1726
1727 if (pvar->fatal_error) {
1728 return 0;
1729 }
1730
1731 switch (cmd) {
1732 case ID_ABOUTMENU:
1733 if (DialogBoxParam
1734 (hInst, MAKEINTRESOURCE(IDD_ABOUTDIALOG), hWin, TTXAboutDlg,
1735 (LPARAM) pvar)
1736 == -1) {
1737 MessageBox(hWin, "Cannot create About box window.",
1738 "TTSSH Error", MB_OK | MB_ICONEXCLAMATION);
1739 }
1740 return 1;
1741 case ID_SSHAUTH:
1742 AUTH_do_cred_dialog(pvar);
1743 return 1;
1744 case ID_SSHSETUPMENU:
1745 if (DialogBoxParam
1746 (hInst, MAKEINTRESOURCE(IDD_SSHSETUP), hWin, TTXSetupDlg,
1747 (LPARAM) pvar)
1748 == -1) {
1749 MessageBox(hWin, "Cannot create TTSSH Setup window.",
1750 "TTSSH Error", MB_OK | MB_ICONEXCLAMATION);
1751 }
1752 return 1;
1753 case ID_SSHAUTHSETUPMENU:
1754 AUTH_do_default_cred_dialog(pvar);
1755 return 1;
1756 case ID_SSHFWDSETUPMENU:
1757 FWDUI_do_forwarding_dialog(pvar);
1758 return 1;
1759 case ID_SSHUNKNOWNHOST:
1760 HOSTS_do_unknown_host_dialog(hWin, pvar);
1761 return 1;
1762 case ID_SSHDIFFERENTHOST:
1763 HOSTS_do_different_host_dialog(hWin, pvar);
1764 return 1;
1765 case ID_SSHASYNCMESSAGEBOX:
1766 if (pvar->err_msg != NULL) {
1767 char FAR *msg = pvar->err_msg;
1768
1769 /* Could there be a buffer overrun bug anywhere in Win32
1770 MessageBox? Who knows? I'm paranoid. */
1771 if (strlen(msg) > 2048) {
1772 msg[2048] = 0;
1773 }
1774
1775 pvar->showing_err = TRUE;
1776 pvar->err_msg = NULL;
1777 MessageBox(NULL, msg, "TTSSH",
1778 MB_TASKMODAL | MB_ICONEXCLAMATION);
1779 free(msg);
1780 pvar->showing_err = FALSE;
1781 if (pvar->err_msg != NULL) {
1782 PostMessage(hWin, WM_COMMAND, ID_SSHASYNCMESSAGEBOX, 0);
1783 } else {
1784 AUTH_notify_end_error(pvar);
1785 }
1786 }
1787 return 1;
1788 default:
1789 return 0;
1790 }
1791 }
1792
1793 static void PASCAL FAR TTXSetCommandLine(PCHAR cmd, int cmdlen,
1794 PGetHNRec rec)
1795 {
1796 char tmpFile[MAX_PATH];
1797 char tmpPath[1024];
1798 char buf[1024];
1799 int i;
1800 GET_VAR();
1801
1802 GetTempPath(sizeof(tmpPath), tmpPath);
1803 GetTempFileName(tmpPath, "TTX", 0, tmpFile);
1804
1805 for (i = 0; cmd[i] != ' ' && cmd[i] != 0; i++) {
1806 }
1807
1808 if (i < cmdlen) {
1809 strncpy(buf, cmd + i, sizeof(buf));
1810 cmd[i] = 0;
1811
1812 write_ssh_options(pvar, tmpFile, &pvar->settings);
1813
1814 strncat(cmd, " /ssh-consume=", cmdlen);
1815 strncat(cmd, tmpFile, cmdlen);
1816
1817 strncat(cmd, buf, cmdlen);
1818
1819 if (pvar->hostdlg_Enabled) {
1820 strncat(cmd, " /ssh", cmdlen);
1821
1822 // add option of SSH protcol version (2004.10.11 yutaka)
1823 if (pvar->settings.ssh_protocol_version == 2) {
1824 strncat(cmd, " /2", cmdlen);
1825 } else {
1826 strncat(cmd, " /1", cmdlen);
1827 }
1828
1829 }
1830 }
1831 }
1832
1833 /* This function is called when Teraterm is quitting. You can use it to clean
1834 up.
1835
1836 This function is called for each extension, in reverse load order (see
1837 below).
1838 */
1839 static void PASCAL FAR TTXEnd(void)
1840 {
1841 GET_VAR();
1842
1843 uninit_TTSSH(pvar);
1844
1845 if (pvar->err_msg != NULL) {
1846 /* Could there be a buffer overrun bug anywhere in Win32
1847 MessageBox? Who knows? I'm paranoid. */
1848 if (strlen(pvar->err_msg) > 2048) {
1849 pvar->err_msg[2048] = 0;
1850 }
1851
1852 MessageBox(NULL, pvar->err_msg, "TTSSH",
1853 MB_TASKMODAL | MB_ICONEXCLAMATION);
1854
1855 free(pvar->err_msg);
1856 pvar->err_msg = NULL;
1857 }
1858 #ifndef TERATERM32
1859 DelVar();
1860 #endif
1861 }
1862
1863 /* This record contains all the information that the extension forwards to the
1864 main Teraterm code. It mostly consists of pointers to the above functions.
1865 Any of the function pointers can be replaced with NULL, in which case
1866 Teraterm will just ignore that function and assume default behaviour, which
1867 means "do nothing".
1868 */
1869 static TTXExports Exports = {
1870 /* This must contain the size of the structure. See below for its usage. */
1871 sizeof(TTXExports),
1872 ORDER,
1873
1874 /* Now we just list the functions that we've implemented. */
1875 TTXInit,
1876 TTXGetUIHooks,
1877 TTXGetSetupHooks,
1878 TTXOpenTCP,
1879 TTXCloseTCP,
1880 TTXSetWinSize,
1881 TTXModifyMenu,
1882 NULL,
1883 TTXProcessCommand,
1884 TTXEnd,
1885 TTXSetCommandLine
1886 };
1887
1888 #ifdef TERATERM32
1889 BOOL __declspec(dllexport)
1890 PASCAL FAR TTXBind(WORD Version, TTXExports FAR * exports)
1891 {
1892 #else
1893 BOOL __export PASCAL FAR TTXBind(WORD Version, TTXExports FAR * exports)
1894 {
1895 #endif
1896 int size = sizeof(Exports) - sizeof(exports->size);
1897 /* do version checking if necessary */
1898 /* if (Version!=TTVERSION) return FALSE; */
1899
1900 if (size > exports->size) {
1901 size = exports->size;
1902 }
1903 memcpy((char FAR *) exports + sizeof(exports->size),
1904 (char FAR *) &Exports + sizeof(exports->size), size);
1905 return TRUE;
1906 }
1907
1908 #ifdef TERATERM32
1909 static HANDLE __mem_mapping = NULL;
1910
1911 BOOL WINAPI DllMain(HANDLE hInstance,
1912 ULONG ul_reason_for_call, LPVOID lpReserved)
1913 {
1914 switch (ul_reason_for_call) {
1915 case DLL_THREAD_ATTACH:
1916 /* do thread initialization */
1917 break;
1918 case DLL_THREAD_DETACH:
1919 /* do thread cleanup */
1920 break;
1921 case DLL_PROCESS_ATTACH:
1922 /* do process initialization */
1923 DisableThreadLibraryCalls(hInstance);
1924 hInst = hInstance;
1925 pvar = &InstVar;
1926 __mem_mapping =
1927 CreateFileMapping((HANDLE) 0xFFFFFFFF, NULL, PAGE_READWRITE, 0,
1928 sizeof(TS_SSH), "TTSSH_1-4_TS_data");
1929 if (__mem_mapping == NULL) {
1930 /* fake it. The settings won't be shared, but what the heck. */
1931 pvar->ts_SSH = NULL;
1932 } else {
1933 pvar->ts_SSH =
1934 (TS_SSH *) MapViewOfFile(__mem_mapping, FILE_MAP_WRITE, 0,
1935 0, 0);
1936 }
1937 if (pvar->ts_SSH == NULL) {
1938 /* fake it. The settings won't be shared, but what the heck. */
1939 pvar->ts_SSH = (TS_SSH *) malloc(sizeof(TS_SSH));
1940 if (__mem_mapping != NULL) {
1941 CloseHandle(__mem_mapping);
1942 }
1943 }
1944 break;
1945 case DLL_PROCESS_DETACH:
1946 /* do process cleanup */
1947 if (__mem_mapping == NULL) {
1948 free(pvar->ts_SSH);
1949 } else {
1950 CloseHandle(__mem_mapping);
1951 UnmapViewOfFile(pvar->ts_SSH);
1952 }
1953 break;
1954 }
1955 return TRUE;
1956 }
1957 #else
1958 #ifdef WATCOM
1959 #pragma off (unreferenced);
1960 #endif
1961 int CALLBACK LibMain(HANDLE hInstance, WORD wDataSegment,
1962 WORD wHeapSize, LPSTR lpszCmdLine)
1963 #ifdef WATCOM
1964 #pragma on (unreferenced);
1965 #endif
1966 {
1967 int i;
1968 for (i = 0; i < MAXNUMINST; i++)
1969 TaskList[i] = NULL;
1970 hInst = hInstance;
1971 return (1);
1972 }
1973 #endif

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26