]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - windlg.c
3b973200aea020ba97fc80528b15e96d2dce3cc6
[PuTTY.git] / windlg.c
1 #include <windows.h>
2 #include <commctrl.h>
3 #include <commdlg.h>
4 #ifndef AUTO_WINSOCK
5 #ifdef WINSOCK_TWO
6 #include <winsock2.h>
7 #else
8 #include <winsock.h>
9 #endif
10 #endif
11 #include <stdio.h>
12 #include <stdlib.h>
13
14 #include "ssh.h"
15 #include "putty.h"
16 #include "win_res.h"
17 #include "storage.h"
18
19 #define NPANELS 9
20 #define MAIN_NPANELS 9
21 #define RECONF_NPANELS 6
22
23 static char **events = NULL;
24 static int nevents = 0, negsize = 0;
25
26 static HWND logbox = NULL, abtbox = NULL;
27
28 static void gpps(void *handle, char *name, char *def, char *val, int len) {
29     if (!read_setting_s(handle, name, val, len)) {
30         strncpy(val, def, len);
31         val[len-1] = '\0';
32     }
33 }
34
35 static void gppi(void *handle, char *name, int def, int *i) {
36     *i = read_setting_i(handle, name, def);
37 }
38
39 static HINSTANCE hinst;
40
41 static int readytogo;
42
43 static void save_settings (char *section, int do_host) {
44     int i;
45     char *p;
46     void *sesskey;
47
48     sesskey = open_settings_w(section);
49     if (!sesskey)
50         return;
51
52     write_setting_i (sesskey, "Present", 1);
53     if (do_host) {
54         write_setting_s (sesskey, "HostName", cfg.host);
55         write_setting_i (sesskey, "PortNumber", cfg.port);
56         p = "raw";
57         for (i = 0; backends[i].name != NULL; i++)
58             if (backends[i].protocol == cfg.protocol) {
59                 p = backends[i].name;
60                 break;
61             }
62         write_setting_s (sesskey, "Protocol", p);
63     }
64     write_setting_i (sesskey, "CloseOnExit", !!cfg.close_on_exit);
65     write_setting_i (sesskey, "WarnOnClose", !!cfg.warn_on_close);
66     write_setting_s (sesskey, "TerminalType", cfg.termtype);
67     write_setting_s (sesskey, "TerminalSpeed", cfg.termspeed);
68     {
69       char buf[2*sizeof(cfg.environmt)], *p, *q;
70         p = buf;
71       q = cfg.environmt;
72         while (*q) {
73             while (*q) {
74                 int c = *q++;
75                 if (c == '=' || c == ',' || c == '\\')
76                     *p++ = '\\';
77                 if (c == '\t')
78                     c = '=';
79                 *p++ = c;
80             }
81             *p++ = ',';
82             q++;
83         }
84         *p = '\0';
85         write_setting_s (sesskey, "Environment", buf);
86     }
87     write_setting_s (sesskey, "UserName", cfg.username);
88     write_setting_i (sesskey, "NoPTY", cfg.nopty);
89     write_setting_i (sesskey, "AgentFwd", cfg.agentfwd);
90     write_setting_s (sesskey, "RemoteCmd", cfg.remote_cmd);
91     write_setting_s (sesskey, "Cipher", cfg.cipher == CIPHER_BLOWFISH ? "blowfish" :
92                              cfg.cipher == CIPHER_DES ? "des" : "3des");
93     write_setting_i (sesskey, "AuthTIS", cfg.try_tis_auth);
94     write_setting_i (sesskey, "SshProt", cfg.sshprot);
95     write_setting_s (sesskey, "PublicKeyFile", cfg.keyfile);
96     write_setting_i (sesskey, "RFCEnviron", cfg.rfc_environ);
97     write_setting_i (sesskey, "BackspaceIsDelete", cfg.bksp_is_delete);
98     write_setting_i (sesskey, "RXVTHomeEnd", cfg.rxvt_homeend);
99     write_setting_i (sesskey, "LinuxFunctionKeys", cfg.funky_type);
100     write_setting_i (sesskey, "ApplicationCursorKeys", cfg.app_cursor);
101     write_setting_i (sesskey, "ApplicationKeypad", cfg.app_keypad);
102     write_setting_i (sesskey, "NetHackKeypad", cfg.nethack_keypad);
103     write_setting_i (sesskey, "AltF4", cfg.alt_f4);
104     write_setting_i (sesskey, "AltSpace", cfg.alt_space);
105     write_setting_i (sesskey, "LdiscTerm", cfg.ldisc_term);
106     write_setting_i (sesskey, "BlinkCur", cfg.blink_cur);
107     write_setting_i (sesskey, "Beep", cfg.beep);
108     write_setting_i (sesskey, "ScrollbackLines", cfg.savelines);
109     write_setting_i (sesskey, "DECOriginMode", cfg.dec_om);
110     write_setting_i (sesskey, "AutoWrapMode", cfg.wrap_mode);
111     write_setting_i (sesskey, "LFImpliesCR", cfg.lfhascr);
112     write_setting_i (sesskey, "WinNameAlways", cfg.win_name_always);
113     write_setting_s (sesskey, "WinTitle", cfg.wintitle);
114     write_setting_i (sesskey, "TermWidth", cfg.width);
115     write_setting_i (sesskey, "TermHeight", cfg.height);
116     write_setting_s (sesskey, "Font", cfg.font);
117     write_setting_i (sesskey, "FontIsBold", cfg.fontisbold);
118     write_setting_i (sesskey, "FontCharSet", cfg.fontcharset);
119     write_setting_i (sesskey, "FontHeight", cfg.fontheight);
120     write_setting_i (sesskey, "FontVTMode", cfg.vtmode);
121     write_setting_i (sesskey, "TryPalette", cfg.try_palette);
122     write_setting_i (sesskey, "BoldAsColour", cfg.bold_colour);
123     for (i=0; i<22; i++) {
124         char buf[20], buf2[30];
125         sprintf(buf, "Colour%d", i);
126         sprintf(buf2, "%d,%d,%d", cfg.colours[i][0],
127                 cfg.colours[i][1], cfg.colours[i][2]);
128         write_setting_s (sesskey, buf, buf2);
129     }
130     write_setting_i (sesskey, "MouseIsXterm", cfg.mouse_is_xterm);
131     for (i=0; i<256; i+=32) {
132         char buf[20], buf2[256];
133         int j;
134         sprintf(buf, "Wordness%d", i);
135         *buf2 = '\0';
136         for (j=i; j<i+32; j++) {
137             sprintf(buf2+strlen(buf2), "%s%d",
138                     (*buf2 ? "," : ""), cfg.wordness[j]);
139         }
140         write_setting_s (sesskey, buf, buf2);
141     }
142     write_setting_i (sesskey, "KoiWinXlat", cfg.xlat_enablekoiwin);
143     write_setting_i (sesskey, "88592Xlat", cfg.xlat_88592w1250);
144     write_setting_i (sesskey, "CapsLockCyr", cfg.xlat_capslockcyr);
145     write_setting_i (sesskey, "ScrollBar", cfg.scrollbar);
146     write_setting_i (sesskey, "ScrollOnKey", cfg.scroll_on_key);
147     write_setting_i (sesskey, "LockSize", cfg.locksize);
148     write_setting_i (sesskey, "BCE", cfg.bce);
149     write_setting_i (sesskey, "BlinkText", cfg.blinktext);
150
151     close_settings_w(sesskey);
152 }
153
154 static void load_settings (char *section, int do_host) {
155     int i;
156     char prot[10];
157     void *sesskey;
158
159     sesskey = open_settings_r(section);
160
161     gpps (sesskey, "HostName", "", cfg.host, sizeof(cfg.host));
162     gppi (sesskey, "PortNumber", default_port, &cfg.port);
163
164     gpps (sesskey, "Protocol", "default", prot, 10);
165     cfg.protocol = default_protocol;
166     for (i = 0; backends[i].name != NULL; i++)
167         if (!strcmp(prot, backends[i].name)) {
168             cfg.protocol = backends[i].protocol;
169             break;
170         }
171
172     gppi (sesskey, "CloseOnExit", 1, &cfg.close_on_exit);
173     gppi (sesskey, "WarnOnClose", 1, &cfg.warn_on_close);
174     gpps (sesskey, "TerminalType", "xterm", cfg.termtype,
175           sizeof(cfg.termtype));
176     gpps (sesskey, "TerminalSpeed", "38400,38400", cfg.termspeed,
177           sizeof(cfg.termspeed));
178     {
179       char buf[2*sizeof(cfg.environmt)], *p, *q;
180         gpps (sesskey, "Environment", "", buf, sizeof(buf));
181         p = buf;
182         q = cfg.environmt;
183         while (*p) {
184             while (*p && *p != ',') {
185                 int c = *p++;
186                 if (c == '=')
187                     c = '\t';
188                 if (c == '\\')
189                     c = *p++;
190                 *q++ = c;
191             }
192             if (*p == ',') p++;
193             *q++ = '\0';
194         }
195         *q = '\0';
196     }
197     gpps (sesskey, "UserName", "", cfg.username, sizeof(cfg.username));
198     gppi (sesskey, "NoPTY", 0, &cfg.nopty);
199     gppi (sesskey, "AgentFwd", 0, &cfg.agentfwd);
200     gpps (sesskey, "RemoteCmd", "", cfg.remote_cmd, sizeof(cfg.remote_cmd));
201     {
202         char cipher[10];
203         gpps (sesskey, "Cipher", "3des", cipher, 10);
204         if (!strcmp(cipher, "blowfish"))
205             cfg.cipher = CIPHER_BLOWFISH;
206         else if (!strcmp(cipher, "des"))
207             cfg.cipher = CIPHER_DES;
208         else
209             cfg.cipher = CIPHER_3DES;
210     }
211     gppi (sesskey, "SshProt", 1, &cfg.sshprot);
212     gppi (sesskey, "AuthTIS", 0, &cfg.try_tis_auth);
213     gpps (sesskey, "PublicKeyFile", "", cfg.keyfile, sizeof(cfg.keyfile));
214     gppi (sesskey, "RFCEnviron", 0, &cfg.rfc_environ);
215     gppi (sesskey, "BackspaceIsDelete", 1, &cfg.bksp_is_delete);
216     gppi (sesskey, "RXVTHomeEnd", 0, &cfg.rxvt_homeend);
217     gppi (sesskey, "LinuxFunctionKeys", 0, &cfg.funky_type);
218     gppi (sesskey, "ApplicationCursorKeys", 0, &cfg.app_cursor);
219     gppi (sesskey, "ApplicationKeypad", 0, &cfg.app_keypad);
220     gppi (sesskey, "NetHackKeypad", 0, &cfg.nethack_keypad);
221     gppi (sesskey, "AltF4", 1, &cfg.alt_f4);
222     gppi (sesskey, "AltSpace", 0, &cfg.alt_space);
223     gppi (sesskey, "LdiscTerm", 0, &cfg.ldisc_term);
224     gppi (sesskey, "BlinkCur", 0, &cfg.blink_cur);
225     gppi (sesskey, "Beep", 1, &cfg.beep);
226     gppi (sesskey, "ScrollbackLines", 200, &cfg.savelines);
227     gppi (sesskey, "DECOriginMode", 0, &cfg.dec_om);
228     gppi (sesskey, "AutoWrapMode", 1, &cfg.wrap_mode);
229     gppi (sesskey, "LFImpliesCR", 0, &cfg.lfhascr);
230     gppi (sesskey, "WinNameAlways", 0, &cfg.win_name_always);
231     gpps (sesskey, "WinTitle", "", cfg.wintitle, sizeof(cfg.wintitle));
232     gppi (sesskey, "TermWidth", 80, &cfg.width);
233     gppi (sesskey, "TermHeight", 24, &cfg.height);
234     gpps (sesskey, "Font", "Courier", cfg.font, sizeof(cfg.font));
235     gppi (sesskey, "FontIsBold", 0, &cfg.fontisbold);
236     gppi (sesskey, "FontCharSet", ANSI_CHARSET, &cfg.fontcharset);
237     gppi (sesskey, "FontHeight", 10, &cfg.fontheight);
238     gppi (sesskey, "FontVTMode", VT_OEMANSI, (int *)&cfg.vtmode);
239     gppi (sesskey, "TryPalette", 0, &cfg.try_palette);
240     gppi (sesskey, "BoldAsColour", 1, &cfg.bold_colour);
241     for (i=0; i<22; i++) {
242         static char *defaults[] = {
243             "187,187,187", "255,255,255", "0,0,0", "85,85,85", "0,0,0",
244             "0,255,0", "0,0,0", "85,85,85", "187,0,0", "255,85,85",
245             "0,187,0", "85,255,85", "187,187,0", "255,255,85", "0,0,187",
246             "85,85,255", "187,0,187", "255,85,255", "0,187,187",
247             "85,255,255", "187,187,187", "255,255,255"
248         };
249         char buf[20], buf2[30];
250         int c0, c1, c2;
251         sprintf(buf, "Colour%d", i);
252         gpps (sesskey, buf, defaults[i], buf2, sizeof(buf2));
253         if(sscanf(buf2, "%d,%d,%d", &c0, &c1, &c2) == 3) {
254             cfg.colours[i][0] = c0;
255             cfg.colours[i][1] = c1;
256             cfg.colours[i][2] = c2;
257         }
258     }
259     gppi (sesskey, "MouseIsXterm", 0, &cfg.mouse_is_xterm);
260     for (i=0; i<256; i+=32) {
261         static char *defaults[] = {
262             "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",
263             "0,1,2,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1",
264             "1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2",
265             "1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1",
266             "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1",
267             "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1",
268             "2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2",
269             "2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2"
270         };
271         char buf[20], buf2[256], *p;
272         int j;
273         sprintf(buf, "Wordness%d", i);
274         gpps (sesskey, buf, defaults[i/32], buf2, sizeof(buf2));
275         p = buf2;
276         for (j=i; j<i+32; j++) {
277             char *q = p;
278             while (*p && *p != ',') p++;
279             if (*p == ',') *p++ = '\0';
280             cfg.wordness[j] = atoi(q);
281         }
282     }
283     gppi (sesskey, "KoiWinXlat", 0, &cfg.xlat_enablekoiwin);
284     gppi (sesskey, "88592Xlat", 0, &cfg.xlat_88592w1250);
285     gppi (sesskey, "CapsLockCyr", 0, &cfg.xlat_capslockcyr);
286     gppi (sesskey, "ScrollBar", 1, &cfg.scrollbar);
287     gppi (sesskey, "ScrollOnKey", 0, &cfg.scroll_on_key);
288     gppi (sesskey, "LockSize", 0, &cfg.locksize);
289     gppi (sesskey, "BCE", 0, &cfg.bce);
290     gppi (sesskey, "BlinkText", 0, &cfg.blinktext);
291
292     close_settings_r(sesskey);
293 }
294
295 static void force_normal(HWND hwnd)
296 {
297 static int recurse = 0;
298
299     WINDOWPLACEMENT wp;
300
301     if(recurse) return;
302     recurse = 1;
303
304     wp.length = sizeof(wp);
305     if (GetWindowPlacement(hwnd, &wp))
306     {
307         wp.showCmd = SW_SHOWNORMAL;
308         SetWindowPlacement(hwnd, &wp);
309     }
310     recurse = 0;
311 }
312
313 static void MyGetDlgItemInt (HWND hwnd, int id, int *result) {
314     BOOL ok;
315     int n;
316     n = GetDlgItemInt (hwnd, id, &ok, FALSE);
317     if (ok)
318         *result = n;
319 }
320
321 static int CALLBACK LogProc (HWND hwnd, UINT msg,
322                              WPARAM wParam, LPARAM lParam) {
323     int i;
324
325     switch (msg) {
326       case WM_INITDIALOG:
327         for (i=0; i<nevents; i++)
328             SendDlgItemMessage (hwnd, IDN_LIST, LB_ADDSTRING,
329                                 0, (LPARAM)events[i]);
330         return 1;
331 /*      case WM_CTLCOLORDLG: */
332 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
333       case WM_COMMAND:
334         switch (LOWORD(wParam)) {
335           case IDOK:
336             logbox = NULL;
337             DestroyWindow (hwnd);
338             return 0;
339           case IDN_COPY:
340             if (HIWORD(wParam) == BN_CLICKED ||
341                 HIWORD(wParam) == BN_DOUBLECLICKED) {
342                 int selcount;
343                 int *selitems;
344                 selcount = SendDlgItemMessage(hwnd, IDN_LIST,
345                                               LB_GETSELCOUNT, 0, 0);
346                 selitems = malloc(selcount * sizeof(int));
347                 if (selitems) {
348                     int count = SendDlgItemMessage(hwnd, IDN_LIST,
349                                                    LB_GETSELITEMS,
350                                                    selcount, (LPARAM)selitems);
351                     int i;
352                     int size;
353                     char *clipdata;
354                     static unsigned char sel_nl[] = SEL_NL;
355
356                     size = 0;
357                     for (i = 0; i < count; i++)
358                         size += strlen(events[selitems[i]]) + sizeof(sel_nl);
359
360                     clipdata = malloc(size);
361                     if (clipdata) {
362                         char *p = clipdata;
363                         for (i = 0; i < count; i++) {
364                             char *q = events[selitems[i]];
365                             int qlen = strlen(q);
366                             memcpy(p, q, qlen);
367                             p += qlen;
368                             memcpy(p, sel_nl, sizeof(sel_nl));
369                             p += sizeof(sel_nl);
370                         }
371                         write_clip(clipdata, size);
372                         term_deselect();
373                         free(clipdata);
374                     }
375                     free(selitems);
376                 }
377             }
378             return 0;
379         }
380         return 0;
381       case WM_CLOSE:
382         logbox = NULL;
383         DestroyWindow (hwnd);
384         return 0;
385     }
386     return 0;
387 }
388
389 static int CALLBACK LicenceProc (HWND hwnd, UINT msg,
390                                  WPARAM wParam, LPARAM lParam) {
391     switch (msg) {
392       case WM_INITDIALOG:
393         return 1;
394       case WM_COMMAND:
395         switch (LOWORD(wParam)) {
396           case IDOK:
397             EndDialog(hwnd, 1);
398             return 0;
399         }
400         return 0;
401       case WM_CLOSE:
402         EndDialog(hwnd, 1);
403         return 0;
404     }
405     return 0;
406 }
407
408 static int CALLBACK AboutProc (HWND hwnd, UINT msg,
409                                WPARAM wParam, LPARAM lParam) {
410     switch (msg) {
411       case WM_INITDIALOG:
412         SetDlgItemText (hwnd, IDA_VERSION, ver);
413         return 1;
414 /*      case WM_CTLCOLORDLG: */
415 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
416 /*      case WM_CTLCOLORSTATIC: */
417 /*      SetBkColor ((HDC)wParam, RGB(192,192,192)); */
418 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
419       case WM_COMMAND:
420         switch (LOWORD(wParam)) {
421           case IDOK:
422             abtbox = NULL;
423             DestroyWindow (hwnd);
424             return 0;
425           case IDA_LICENCE:
426             EnableWindow(hwnd, 0);
427             DialogBox (hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
428                        NULL, LicenceProc);
429             EnableWindow(hwnd, 1);
430             SetActiveWindow(hwnd);
431             return 0;
432         }
433         return 0;
434       case WM_CLOSE:
435         abtbox = NULL;
436         DestroyWindow (hwnd);
437         return 0;
438     }
439     return 0;
440 }
441
442 static int GeneralPanelProc (HWND hwnd, UINT msg,
443                              WPARAM wParam, LPARAM lParam) {
444     switch (msg) {
445       case WM_INITDIALOG:
446         SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
447         return 1;
448 /*      case WM_CTLCOLORDLG: */
449 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
450 /*      case WM_CTLCOLORSTATIC: */
451 /*      case WM_CTLCOLORBTN: */
452 /*      SetBkColor ((HDC)wParam, RGB(192,192,192)); */
453 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
454       case WM_CLOSE:
455         DestroyWindow (hwnd);
456         return 1;
457     }
458     return 0;
459 }
460
461 static char savedsession[2048];
462
463 static int CALLBACK ConnectionProc (HWND hwnd, UINT msg,
464                                     WPARAM wParam, LPARAM lParam) {
465     int i;
466
467     switch (msg) {
468       case WM_INITDIALOG:
469         SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
470         SetDlgItemText (hwnd, IDC0_SESSEDIT, savedsession);
471         SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
472         for (i = 0; i < nsessions; i++)
473             SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
474                                 0, (LPARAM) (sessions[i]));
475         CheckRadioButton (hwnd, IDC0_PROTRAW, IDC0_PROTSSH,
476                           cfg.protocol==PROT_SSH ? IDC0_PROTSSH : 
477                           cfg.protocol==PROT_TELNET ? IDC0_PROTTELNET : IDC0_PROTRAW );
478         CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
479         CheckDlgButton (hwnd, IDC0_CLOSEWARN, cfg.warn_on_close);
480         break;
481       case WM_LBUTTONUP:
482         /*
483          * Button release should trigger WM_OK if there was a
484          * previous double click on the session list.
485          */
486         ReleaseCapture();
487         if (readytogo)
488             SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
489         break;
490       case WM_COMMAND:
491         switch (LOWORD(wParam)) {
492           case IDC0_PROTTELNET:
493           case IDC0_PROTSSH:
494           case IDC0_PROTRAW:
495             if (HIWORD(wParam) == BN_CLICKED ||
496                 HIWORD(wParam) == BN_DOUBLECLICKED) {
497                 int i = IsDlgButtonChecked (hwnd, IDC0_PROTSSH);
498                 int j = IsDlgButtonChecked (hwnd, IDC0_PROTTELNET);
499                 cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ;
500                 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
501                     (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
502                     cfg.port = i ? 22 : 23;
503                     SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
504                 }
505             }
506             break;
507           case IDC0_HOST:
508             if (HIWORD(wParam) == EN_CHANGE)
509                 GetDlgItemText (hwnd, IDC0_HOST, cfg.host,
510                                 sizeof(cfg.host)-1);
511             break;
512           case IDC0_PORT:
513             if (HIWORD(wParam) == EN_CHANGE)
514                 MyGetDlgItemInt (hwnd, IDC0_PORT, &cfg.port);
515             break;
516           case IDC0_CLOSEEXIT:
517             if (HIWORD(wParam) == BN_CLICKED ||
518                 HIWORD(wParam) == BN_DOUBLECLICKED)
519                 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC0_CLOSEEXIT);
520             break;
521           case IDC0_CLOSEWARN:
522             if (HIWORD(wParam) == BN_CLICKED ||
523                 HIWORD(wParam) == BN_DOUBLECLICKED)
524                 cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC0_CLOSEWARN);
525             break;
526           case IDC0_SESSEDIT:
527             if (HIWORD(wParam) == EN_CHANGE) {
528                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
529                                     (WPARAM) -1, 0);
530                 GetDlgItemText (hwnd, IDC0_SESSEDIT,
531                                 savedsession, sizeof(savedsession)-1);
532                 savedsession[sizeof(savedsession)-1] = '\0';
533             }
534             break;
535           case IDC0_SESSSAVE:
536             if (HIWORD(wParam) == BN_CLICKED ||
537                 HIWORD(wParam) == BN_DOUBLECLICKED) {
538                 /*
539                  * Save a session
540                  */
541                 char str[2048];
542                 GetDlgItemText (hwnd, IDC0_SESSEDIT, str, sizeof(str)-1);
543                 if (!*str) {
544                     int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
545                                                 LB_GETCURSEL, 0, 0);
546                     if (n == LB_ERR) {
547                         MessageBeep(0);
548                         break;
549                     }
550                     strcpy (str, sessions[n]);
551                 }
552                 save_settings (str, !!strcmp(str, "Default Settings"));
553                 get_sesslist (FALSE);
554                 get_sesslist (TRUE);
555                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
556                                     0, 0);
557                 for (i = 0; i < nsessions; i++)
558                     SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
559                                         0, (LPARAM) (sessions[i]));
560                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
561                                     (WPARAM) -1, 0);
562             }
563             break;
564           case IDC0_SESSLIST:
565           case IDC0_SESSLOAD:
566             if (LOWORD(wParam) == IDC0_SESSLOAD &&
567                 HIWORD(wParam) != BN_CLICKED &&
568                 HIWORD(wParam) != BN_DOUBLECLICKED)
569                 break;
570             if (LOWORD(wParam) == IDC0_SESSLIST &&
571                 HIWORD(wParam) != LBN_DBLCLK)
572                 break;
573             {
574                 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
575                                             LB_GETCURSEL, 0, 0);
576                 if (n == LB_ERR) {
577                     MessageBeep(0);
578                     break;
579                 }
580                 load_settings (sessions[n],
581                                !!strcmp(sessions[n], "Default Settings"));
582                 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
583                 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
584                 CheckRadioButton (hwnd, IDC0_PROTRAW, IDC0_PROTSSH,
585                                   (cfg.protocol==PROT_SSH ? IDC0_PROTSSH :
586                                   cfg.protocol==PROT_TELNET ? IDC0_PROTTELNET : IDC0_PROTRAW));
587                 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
588                 CheckDlgButton (hwnd, IDC0_CLOSEWARN, cfg.warn_on_close);
589                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
590                                     (WPARAM) -1, 0);
591             }
592             if (LOWORD(wParam) == IDC0_SESSLIST) {
593                 /*
594                  * A double-click on a saved session should
595                  * actually start the session, not just load it.
596                  * Unless it's Default Settings or some other
597                  * host-less set of saved settings.
598                  */
599                 if (*cfg.host) {
600                     readytogo = TRUE;
601                     SetCapture(hwnd);
602                 }
603             }
604             break;
605           case IDC0_SESSDEL:
606             if (HIWORD(wParam) == BN_CLICKED ||
607                 HIWORD(wParam) == BN_DOUBLECLICKED) {
608                 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
609                                             LB_GETCURSEL, 0, 0);
610                 if (n == LB_ERR || n == 0) {
611                     MessageBeep(0);
612                     break;
613                 }
614                 del_settings(sessions[n]);
615                 get_sesslist (FALSE);
616                 get_sesslist (TRUE);
617                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
618                                     0, 0);
619                 for (i = 0; i < nsessions; i++)
620                     SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
621                                         0, (LPARAM) (sessions[i]));
622                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
623                                     (WPARAM) -1, 0);
624             }
625         }
626     }
627     return GeneralPanelProc (hwnd, msg, wParam, lParam);
628 }
629
630 static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
631                                     WPARAM wParam, LPARAM lParam) {
632     switch (msg) {
633       case WM_INITDIALOG:
634         CheckRadioButton (hwnd, IDC1_DEL008, IDC1_DEL127,
635                           cfg.bksp_is_delete ? IDC1_DEL127 : IDC1_DEL008);
636         CheckRadioButton (hwnd, IDC1_HOMETILDE, IDC1_HOMERXVT,
637                           cfg.rxvt_homeend ? IDC1_HOMERXVT : IDC1_HOMETILDE);
638         CheckRadioButton (hwnd, IDC1_FUNCTILDE, IDC1_FUNCXTERM,
639                           cfg.funky_type ? 
640                           (cfg.funky_type==2 ? IDC1_FUNCXTERM 
641                            : IDC1_FUNCLINUX )
642                           : IDC1_FUNCTILDE);
643         CheckRadioButton (hwnd, IDC1_CURNORMAL, IDC1_CURAPPLIC,
644                           cfg.app_cursor ? IDC1_CURAPPLIC : IDC1_CURNORMAL);
645         CheckRadioButton (hwnd, IDC1_KPNORMAL, IDC1_KPNH,
646                           cfg.nethack_keypad ? IDC1_KPNH :
647                           cfg.app_keypad ? IDC1_KPAPPLIC : IDC1_KPNORMAL);
648         CheckDlgButton (hwnd, IDC1_ALTF4, cfg.alt_f4);
649         CheckDlgButton (hwnd, IDC1_ALTSPACE, cfg.alt_space);
650         CheckDlgButton (hwnd, IDC1_LDISCTERM, cfg.ldisc_term);
651         CheckDlgButton (hwnd, IDC1_SCROLLKEY, cfg.scroll_on_key);
652         break;
653       case WM_COMMAND:
654         if (HIWORD(wParam) == BN_CLICKED ||
655             HIWORD(wParam) == BN_DOUBLECLICKED)
656             switch (LOWORD(wParam)) {
657               case IDC1_DEL008:
658               case IDC1_DEL127:
659                 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC1_DEL127);
660                 break;
661               case IDC1_HOMETILDE:
662               case IDC1_HOMERXVT:
663                 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC1_HOMERXVT);
664                 break;
665               case IDC1_FUNCXTERM:
666                 cfg.funky_type = 2;
667                 break;
668               case IDC1_FUNCTILDE:
669               case IDC1_FUNCLINUX:
670                 cfg.funky_type = IsDlgButtonChecked (hwnd, IDC1_FUNCLINUX);
671                 break;
672               case IDC1_KPNORMAL:
673               case IDC1_KPAPPLIC:
674                 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC1_KPAPPLIC);
675                 cfg.nethack_keypad = FALSE;
676                 break;
677               case IDC1_KPNH:
678                 cfg.app_keypad = FALSE;
679                 cfg.nethack_keypad = TRUE;
680                 break;
681               case IDC1_CURNORMAL:
682               case IDC1_CURAPPLIC:
683                 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC1_CURAPPLIC);
684                 break;
685               case IDC1_ALTF4:
686                 if (HIWORD(wParam) == BN_CLICKED ||
687                     HIWORD(wParam) == BN_DOUBLECLICKED)
688                     cfg.alt_f4 = IsDlgButtonChecked (hwnd, IDC1_ALTF4);
689                 break;
690               case IDC1_ALTSPACE:
691                 if (HIWORD(wParam) == BN_CLICKED ||
692                     HIWORD(wParam) == BN_DOUBLECLICKED)
693                     cfg.alt_space = IsDlgButtonChecked (hwnd, IDC1_ALTSPACE);
694                 break;
695               case IDC1_LDISCTERM:
696                 if (HIWORD(wParam) == BN_CLICKED ||
697                     HIWORD(wParam) == BN_DOUBLECLICKED)
698                     cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC1_LDISCTERM);
699                 break;
700               case IDC1_SCROLLKEY:
701                 if (HIWORD(wParam) == BN_CLICKED ||
702                     HIWORD(wParam) == BN_DOUBLECLICKED)
703                     cfg.scroll_on_key = IsDlgButtonChecked (hwnd, IDC1_SCROLLKEY);
704                 break;
705             }
706     }
707     return GeneralPanelProc (hwnd, msg, wParam, lParam);
708 }
709
710 static void fmtfont (char *buf) {
711     sprintf (buf, "Font: %s, ", cfg.font);
712     if (cfg.fontisbold)
713         strcat(buf, "bold, ");
714     if (cfg.fontheight == 0)
715         strcat (buf, "default height");
716     else
717         sprintf (buf+strlen(buf), "%d-%s",
718                  (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
719                  (cfg.fontheight < 0 ? "pixel" : "point"));
720 }
721
722 static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
723                                     WPARAM wParam, LPARAM lParam) {
724     CHOOSEFONT cf;
725     LOGFONT lf;
726     char fontstatic[256];
727
728     switch (msg) {
729       case WM_INITDIALOG:
730         CheckDlgButton (hwnd, IDC2_WRAPMODE, cfg.wrap_mode);
731         CheckDlgButton (hwnd, IDC2_DECOM, cfg.dec_om);
732         CheckDlgButton (hwnd, IDC2_LFHASCR, cfg.lfhascr);
733         SetDlgItemInt (hwnd, IDC2_ROWSEDIT, cfg.height, FALSE);
734         SetDlgItemInt (hwnd, IDC2_COLSEDIT, cfg.width, FALSE);
735         SetDlgItemInt (hwnd, IDC2_SAVEEDIT, cfg.savelines, FALSE);
736         fmtfont (fontstatic);
737         SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
738         CheckDlgButton (hwnd, IDC1_BEEP, cfg.beep);
739         CheckDlgButton (hwnd, IDC2_BCE, cfg.bce);
740         CheckDlgButton (hwnd, IDC2_BLINKTEXT, cfg.blinktext);
741         break;
742       case WM_COMMAND:
743         switch (LOWORD(wParam)) {
744           case IDC2_WRAPMODE:
745             if (HIWORD(wParam) == BN_CLICKED ||
746                 HIWORD(wParam) == BN_DOUBLECLICKED)
747                 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC2_WRAPMODE);
748             break;
749           case IDC2_DECOM:
750             if (HIWORD(wParam) == BN_CLICKED ||
751                 HIWORD(wParam) == BN_DOUBLECLICKED)
752                 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC2_DECOM);
753             break;
754           case IDC2_LFHASCR:
755             if (HIWORD(wParam) == BN_CLICKED ||
756                 HIWORD(wParam) == BN_DOUBLECLICKED)
757                 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC2_LFHASCR);
758             break;
759           case IDC2_ROWSEDIT:
760             if (HIWORD(wParam) == EN_CHANGE)
761                 MyGetDlgItemInt (hwnd, IDC2_ROWSEDIT, &cfg.height);
762             break;
763           case IDC2_COLSEDIT:
764             if (HIWORD(wParam) == EN_CHANGE)
765                 MyGetDlgItemInt (hwnd, IDC2_COLSEDIT, &cfg.width);
766             break;
767           case IDC2_SAVEEDIT:
768             if (HIWORD(wParam) == EN_CHANGE)
769                 MyGetDlgItemInt (hwnd, IDC2_SAVEEDIT, &cfg.savelines);
770             break;
771           case IDC2_CHOOSEFONT:
772             lf.lfHeight = cfg.fontheight;
773             lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
774             lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
775             lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
776             lf.lfCharSet = cfg.fontcharset;
777             lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
778             lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
779             lf.lfQuality = DEFAULT_QUALITY;
780             lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
781             strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
782             lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
783
784             cf.lStructSize = sizeof(cf);
785             cf.hwndOwner = hwnd;
786             cf.lpLogFont = &lf;
787             cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
788                 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
789
790             if (ChooseFont (&cf)) {
791                 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
792                 cfg.font[sizeof(cfg.font)-1] = '\0';
793                 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
794                 cfg.fontcharset = lf.lfCharSet;
795                 cfg.fontheight = lf.lfHeight;
796                 fmtfont (fontstatic);
797                 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
798             }
799             break;
800            case IDC1_BEEP:
801              if (HIWORD(wParam) == BN_CLICKED ||
802                  HIWORD(wParam) == BN_DOUBLECLICKED)
803                  cfg.beep = IsDlgButtonChecked (hwnd, IDC1_BEEP);
804              break;
805            case IDC2_BLINKTEXT:
806              if (HIWORD(wParam) == BN_CLICKED ||
807                  HIWORD(wParam) == BN_DOUBLECLICKED)
808                  cfg.blinktext = IsDlgButtonChecked (hwnd, IDC2_BLINKTEXT);
809              break;
810            case IDC2_BCE:
811              if (HIWORD(wParam) == BN_CLICKED ||
812                  HIWORD(wParam) == BN_DOUBLECLICKED)
813                  cfg.bce = IsDlgButtonChecked (hwnd, IDC2_BCE);
814              break;
815         }
816         break;
817     }
818     return GeneralPanelProc (hwnd, msg, wParam, lParam);
819 }
820
821 static int CALLBACK WindowProc (HWND hwnd, UINT msg,
822                                     WPARAM wParam, LPARAM lParam) {
823     switch (msg) {
824       case WM_INITDIALOG:
825         SetDlgItemText (hwnd, IDCW_WINEDIT, cfg.wintitle);
826         CheckDlgButton (hwnd, IDCW_WINNAME, cfg.win_name_always);
827         CheckDlgButton (hwnd, IDCW_BLINKCUR, cfg.blink_cur);
828         CheckDlgButton (hwnd, IDCW_SCROLLBAR, cfg.scrollbar);
829         CheckDlgButton (hwnd, IDCW_LOCKSIZE, cfg.locksize);
830         break;
831       case WM_COMMAND:
832         switch (LOWORD(wParam)) {
833           case IDCW_WINNAME:
834             if (HIWORD(wParam) == BN_CLICKED ||
835                 HIWORD(wParam) == BN_DOUBLECLICKED)
836                 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDCW_WINNAME);
837             break;
838           case IDCW_BLINKCUR:
839             if (HIWORD(wParam) == BN_CLICKED ||
840                 HIWORD(wParam) == BN_DOUBLECLICKED)
841                 cfg.blink_cur = IsDlgButtonChecked (hwnd, IDCW_BLINKCUR);
842             break;
843           case IDCW_SCROLLBAR:
844             if (HIWORD(wParam) == BN_CLICKED ||
845                 HIWORD(wParam) == BN_DOUBLECLICKED)
846                 cfg.scrollbar = IsDlgButtonChecked (hwnd, IDCW_SCROLLBAR);
847             break;
848           case IDCW_LOCKSIZE:
849              if (HIWORD(wParam) == BN_CLICKED ||
850                  HIWORD(wParam) == BN_DOUBLECLICKED)
851                 cfg.locksize = IsDlgButtonChecked (hwnd, IDCW_LOCKSIZE);
852             break;
853           case IDCW_WINEDIT:
854             if (HIWORD(wParam) == EN_CHANGE)
855                 GetDlgItemText (hwnd, IDCW_WINEDIT, cfg.wintitle,
856                                 sizeof(cfg.wintitle)-1);
857             break;
858         }
859         break;
860     }
861     return GeneralPanelProc (hwnd, msg, wParam, lParam);
862 }
863
864 static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
865                                     WPARAM wParam, LPARAM lParam) {
866     int i;
867
868     switch (msg) {
869       case WM_INITDIALOG:
870         SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
871         SetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed);
872         SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
873         {
874           char *p = cfg.environmt;
875             while (*p) {
876                 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING, 0,
877                                     (LPARAM) p);
878                 p += strlen(p)+1;
879             }
880         }
881         CheckRadioButton (hwnd, IDC3_EMBSD, IDC3_EMRFC,
882                           cfg.rfc_environ ? IDC3_EMRFC : IDC3_EMBSD);
883         break;
884       case WM_COMMAND:
885         switch (LOWORD(wParam)) {
886           case IDC3_TTEDIT:
887             if (HIWORD(wParam) == EN_CHANGE)
888             GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
889                             sizeof(cfg.termtype)-1);
890             break;
891           case IDC3_TSEDIT:
892             if (HIWORD(wParam) == EN_CHANGE)
893                 GetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed,
894                                 sizeof(cfg.termspeed)-1);
895             break;
896           case IDC3_LOGEDIT:
897             if (HIWORD(wParam) == EN_CHANGE)
898                 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
899                                 sizeof(cfg.username)-1);
900             break;
901           case IDC3_EMBSD:
902           case IDC3_EMRFC:
903             cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC3_EMRFC);
904             break;
905           case IDC3_ENVADD:
906             if (HIWORD(wParam) == BN_CLICKED ||
907                 HIWORD(wParam) == BN_DOUBLECLICKED) {
908               char str[sizeof(cfg.environmt)];
909                 char *p;
910                 GetDlgItemText (hwnd, IDC3_VAREDIT, str, sizeof(str)-1);
911                 if (!*str) {
912                     MessageBeep(0);
913                     break;
914                 }
915                 p = str + strlen(str);
916                 *p++ = '\t';
917                 GetDlgItemText (hwnd, IDC3_VALEDIT, p, sizeof(str)-1-(p-str));
918                 if (!*p) {
919                     MessageBeep(0);
920                     break;
921                 }
922               p = cfg.environmt;
923                 while (*p) {
924                     while (*p) p++;
925                     p++;
926                 }
927               if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
928                     strcpy (p, str);
929                     p[strlen(str)+1] = '\0';
930                     SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING,
931                                         0, (LPARAM)str);
932                     SetDlgItemText (hwnd, IDC3_VAREDIT, "");
933                     SetDlgItemText (hwnd, IDC3_VALEDIT, "");
934                 } else {
935                     MessageBox(hwnd, "Environment too big", "PuTTY Error",
936                                MB_OK | MB_ICONERROR);
937                 }
938             }
939             break;
940           case IDC3_ENVREMOVE:
941             if (HIWORD(wParam) != BN_CLICKED &&
942                 HIWORD(wParam) != BN_DOUBLECLICKED)
943                 break;
944             i = SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_GETCURSEL, 0, 0);
945             if (i == LB_ERR)
946                 MessageBeep (0);
947             else {
948                 char *p, *q;
949
950                 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_DELETESTRING,
951                                     i, 0);
952               p = cfg.environmt;
953                 while (i > 0) {
954                     if (!*p)
955                         goto disaster;
956                     while (*p) p++;
957                     p++;
958                     i--;
959                 }
960                 q = p;
961                 if (!*p)
962                     goto disaster;
963                 while (*p) p++;
964                 p++;
965                 while (*p) {
966                     while (*p)
967                         *q++ = *p++;
968                     *q++ = *p++;
969                 }
970                 *q = '\0';
971                 disaster:;
972             }
973             break;
974         }
975         break;
976     }
977     return GeneralPanelProc (hwnd, msg, wParam, lParam);
978 }
979
980 static int CALLBACK SshProc (HWND hwnd, UINT msg,
981                              WPARAM wParam, LPARAM lParam) {
982     OPENFILENAME of;
983     char filename[sizeof(cfg.keyfile)];
984
985     switch (msg) {
986       case WM_INITDIALOG:
987         SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
988         SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
989         CheckDlgButton (hwnd, IDC3_NOPTY, cfg.nopty);
990         CheckDlgButton (hwnd, IDC3_AGENTFWD, cfg.agentfwd);
991         CheckRadioButton (hwnd, IDC3_CIPHER3DES, IDC3_CIPHERDES,
992                           cfg.cipher == CIPHER_BLOWFISH ? IDC3_CIPHERBLOWF :
993                           cfg.cipher == CIPHER_DES ? IDC3_CIPHERDES :
994                           IDC3_CIPHER3DES);
995         CheckRadioButton (hwnd, IDC3_SSHPROT1, IDC3_SSHPROT2,
996                           cfg.sshprot == 1 ? IDC3_SSHPROT1 : IDC3_SSHPROT2);
997         CheckDlgButton (hwnd, IDC3_AUTHTIS, cfg.try_tis_auth);
998         SetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile);
999         break;
1000       case WM_COMMAND:
1001         switch (LOWORD(wParam)) {
1002           case IDC3_TTEDIT:
1003             if (HIWORD(wParam) == EN_CHANGE)
1004             GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
1005                             sizeof(cfg.termtype)-1);
1006             break;
1007           case IDC3_LOGEDIT:
1008             if (HIWORD(wParam) == EN_CHANGE)
1009                 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
1010                                 sizeof(cfg.username)-1);
1011             break;
1012           case IDC3_NOPTY:
1013             if (HIWORD(wParam) == BN_CLICKED ||
1014                 HIWORD(wParam) == BN_DOUBLECLICKED)
1015                 cfg.nopty = IsDlgButtonChecked (hwnd, IDC3_NOPTY);
1016             break;
1017           case IDC3_AGENTFWD:
1018             if (HIWORD(wParam) == BN_CLICKED ||
1019                 HIWORD(wParam) == BN_DOUBLECLICKED)
1020                 cfg.agentfwd = IsDlgButtonChecked (hwnd, IDC3_AGENTFWD);
1021             break;
1022           case IDC3_CIPHER3DES:
1023           case IDC3_CIPHERBLOWF:
1024           case IDC3_CIPHERDES:
1025             if (HIWORD(wParam) == BN_CLICKED ||
1026                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1027                 if (IsDlgButtonChecked (hwnd, IDC3_CIPHER3DES))
1028                     cfg.cipher = CIPHER_3DES;
1029                 else if (IsDlgButtonChecked (hwnd, IDC3_CIPHERBLOWF))
1030                     cfg.cipher = CIPHER_BLOWFISH;
1031                 else if (IsDlgButtonChecked (hwnd, IDC3_CIPHERDES))
1032                     cfg.cipher = CIPHER_DES;
1033             }
1034             break;
1035           case IDC3_SSHPROT1:
1036           case IDC3_SSHPROT2:
1037             if (HIWORD(wParam) == BN_CLICKED ||
1038                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1039                 if (IsDlgButtonChecked (hwnd, IDC3_SSHPROT1))
1040                     cfg.sshprot = 1;
1041                 else if (IsDlgButtonChecked (hwnd, IDC3_SSHPROT2))
1042                     cfg.sshprot = 2;
1043             }
1044             break;
1045           case IDC3_AUTHTIS:
1046             if (HIWORD(wParam) == BN_CLICKED ||
1047                 HIWORD(wParam) == BN_DOUBLECLICKED)
1048                 cfg.try_tis_auth = IsDlgButtonChecked (hwnd, IDC3_AUTHTIS);
1049             break;
1050           case IDC3_PKEDIT:
1051             if (HIWORD(wParam) == EN_CHANGE)
1052                 GetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile,
1053                                 sizeof(cfg.keyfile)-1);
1054             break;
1055           case IDC3_PKBUTTON:
1056             /*
1057              * FIXME: this crashes. Find out why.
1058              */
1059             memset(&of, 0, sizeof(of));
1060 #ifdef OPENFILENAME_SIZE_VERSION_400
1061             of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
1062 #else
1063             of.lStructSize = sizeof(of);
1064 #endif
1065             of.hwndOwner = hwnd;
1066             of.lpstrFilter = "All Files\0*\0\0\0";
1067             of.lpstrCustomFilter = NULL;
1068             of.nFilterIndex = 1;
1069             of.lpstrFile = filename; strcpy(filename, cfg.keyfile);
1070             of.nMaxFile = sizeof(filename);
1071             of.lpstrFileTitle = NULL;
1072             of.lpstrInitialDir = NULL;
1073             of.lpstrTitle = "Select Public Key File";
1074             of.Flags = 0;
1075             if (GetOpenFileName(&of)) {
1076                 strcpy(cfg.keyfile, filename);
1077                 SetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile);
1078             }
1079             break;
1080         }
1081         break;
1082     }
1083     return GeneralPanelProc (hwnd, msg, wParam, lParam);
1084 }
1085
1086 static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
1087                                     WPARAM wParam, LPARAM lParam) {
1088     int i;
1089
1090     switch (msg) {
1091       case WM_INITDIALOG:
1092         CheckRadioButton (hwnd, IDC4_MBWINDOWS, IDC4_MBXTERM,
1093                           cfg.mouse_is_xterm ? IDC4_MBXTERM : IDC4_MBWINDOWS);
1094         {
1095             static int tabs[4] = {25, 61, 96, 128};
1096             SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_SETTABSTOPS, 4,
1097                                 (LPARAM) tabs);
1098         }
1099         for (i=0; i<256; i++) {
1100             char str[100];
1101             sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1102                     (i>=0x21 && i != 0x7F) ? i : ' ',
1103                     cfg.wordness[i]);
1104             SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_ADDSTRING, 0,
1105                                 (LPARAM) str);
1106         }
1107         break;
1108       case WM_COMMAND:
1109         switch (LOWORD(wParam)) {
1110           case IDC4_MBWINDOWS:
1111           case IDC4_MBXTERM:
1112             cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC4_MBXTERM);
1113             break;
1114           case IDC4_CCSET:
1115             {
1116                 BOOL ok;
1117                 int i;
1118                 int n = GetDlgItemInt (hwnd, IDC4_CCEDIT, &ok, FALSE);
1119
1120                 if (!ok)
1121                     MessageBeep (0);
1122                 else {
1123                     for (i=0; i<256; i++)
1124                         if (SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_GETSEL,
1125                                                 i, 0)) {
1126                             char str[100];
1127                             cfg.wordness[i] = n;
1128                             SendDlgItemMessage (hwnd, IDC4_CCLIST,
1129                                                 LB_DELETESTRING, i, 0);
1130                             sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1131                                     (i>=0x21 && i != 0x7F) ? i : ' ',
1132                                     cfg.wordness[i]);
1133                             SendDlgItemMessage (hwnd, IDC4_CCLIST,
1134                                                 LB_INSERTSTRING, i,
1135                                                 (LPARAM)str);
1136                         }
1137                 }
1138             }
1139             break;
1140         }
1141         break;
1142     }
1143     return GeneralPanelProc (hwnd, msg, wParam, lParam);
1144 }
1145
1146 static int CALLBACK ColourProc (HWND hwnd, UINT msg,
1147                                     WPARAM wParam, LPARAM lParam) {
1148     static const char *const colours[] = {
1149         "Default Foreground", "Default Bold Foreground",
1150         "Default Background", "Default Bold Background",
1151         "Cursor Text", "Cursor Colour",
1152         "ANSI Black", "ANSI Black Bold",
1153         "ANSI Red", "ANSI Red Bold",
1154         "ANSI Green", "ANSI Green Bold",
1155         "ANSI Yellow", "ANSI Yellow Bold",
1156         "ANSI Blue", "ANSI Blue Bold",
1157         "ANSI Magenta", "ANSI Magenta Bold",
1158         "ANSI Cyan", "ANSI Cyan Bold",
1159         "ANSI White", "ANSI White Bold"
1160     };
1161     static const int permanent[] = {
1162         TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
1163         TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
1164         TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
1165     };
1166     switch (msg) {
1167       case WM_INITDIALOG:
1168         CheckDlgButton (hwnd, IDC5_BOLDCOLOUR, cfg.bold_colour);
1169         CheckDlgButton (hwnd, IDC5_PALETTE, cfg.try_palette);
1170         {
1171             int i;
1172             for (i=0; i<22; i++)
1173                 if (cfg.bold_colour || permanent[i])
1174                     SendDlgItemMessage (hwnd, IDC5_LIST, LB_ADDSTRING, 0,
1175                                         (LPARAM) colours[i]);
1176         }
1177         SendDlgItemMessage (hwnd, IDC5_LIST, LB_SETCURSEL, 0, 0);
1178         SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[0][0], FALSE);
1179         SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[0][1], FALSE);
1180         SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[0][2], FALSE);
1181         break;
1182       case WM_COMMAND:
1183         switch (LOWORD(wParam)) {
1184           case IDC5_BOLDCOLOUR:
1185             if (HIWORD(wParam) == BN_CLICKED ||
1186                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1187                 int n, i;
1188                 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC5_BOLDCOLOUR);
1189                 n = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCOUNT, 0, 0);
1190                 if (cfg.bold_colour && n!=22) {
1191                     for (i=0; i<22; i++)
1192                         if (!permanent[i])
1193                             SendDlgItemMessage (hwnd, IDC5_LIST,
1194                                                 LB_INSERTSTRING, i,
1195                                                 (LPARAM) colours[i]);
1196                 } else if (!cfg.bold_colour && n!=12) {
1197                     for (i=22; i-- ;)
1198                         if (!permanent[i])
1199                             SendDlgItemMessage (hwnd, IDC5_LIST,
1200                                                 LB_DELETESTRING, i, 0);
1201                 }
1202             }
1203             break;
1204           case IDC5_PALETTE:
1205             if (HIWORD(wParam) == BN_CLICKED ||
1206                 HIWORD(wParam) == BN_DOUBLECLICKED)
1207                 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC5_PALETTE);
1208             break;
1209           case IDC5_LIST:
1210             if (HIWORD(wParam) == LBN_DBLCLK ||
1211                 HIWORD(wParam) == LBN_SELCHANGE) {
1212                 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1213                                             0, 0);
1214                 if (!cfg.bold_colour)
1215                     i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1216                 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0], FALSE);
1217                 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1], FALSE);
1218                 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2], FALSE);
1219             }
1220             break;
1221           case IDC5_CHANGE:
1222             if (HIWORD(wParam) == BN_CLICKED ||
1223                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1224                 static CHOOSECOLOR cc;
1225                 static DWORD custom[16] = {0};   /* zero initialisers */
1226                 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1227                                             0, 0);
1228                 if (!cfg.bold_colour)
1229                     i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1230                 cc.lStructSize = sizeof(cc);
1231                 cc.hwndOwner = hwnd;
1232                 cc.hInstance = (HWND)hinst;
1233                 cc.lpCustColors = custom;
1234                 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
1235                                     cfg.colours[i][2]);
1236                 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
1237                 if (ChooseColor(&cc)) {
1238                     cfg.colours[i][0] =
1239                         (unsigned char) (cc.rgbResult & 0xFF);
1240                     cfg.colours[i][1] =
1241                         (unsigned char) (cc.rgbResult >> 8) & 0xFF;
1242                     cfg.colours[i][2] =
1243                         (unsigned char) (cc.rgbResult >> 16) & 0xFF;
1244                     SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0],
1245                                    FALSE);
1246                     SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1],
1247                                    FALSE);
1248                     SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2],
1249                                    FALSE);
1250                 }
1251             }
1252             break;
1253         }
1254         break;
1255     }
1256     return GeneralPanelProc (hwnd, msg, wParam, lParam);
1257 }
1258
1259 static int CALLBACK TranslationProc (HWND hwnd, UINT msg,
1260                                   WPARAM wParam, LPARAM lParam) {
1261     switch (msg) {
1262       case WM_INITDIALOG:
1263         CheckRadioButton (hwnd, IDC6_NOXLAT, IDC6_88592WIN1250,
1264                           cfg.xlat_88592w1250 ? IDC6_88592WIN1250 :
1265                           cfg.xlat_enablekoiwin ? IDC6_KOI8WIN1251 :
1266                           IDC6_NOXLAT);
1267         CheckDlgButton (hwnd, IDC6_CAPSLOCKCYR, cfg.xlat_capslockcyr);
1268         CheckRadioButton (hwnd, IDC2_VTXWINDOWS, IDC2_VTPOORMAN,
1269                           cfg.vtmode == VT_XWINDOWS ? IDC2_VTXWINDOWS :
1270                           cfg.vtmode == VT_OEMANSI ? IDC2_VTOEMANSI :
1271                           cfg.vtmode == VT_OEMONLY ? IDC2_VTOEMONLY :
1272                           IDC2_VTPOORMAN);
1273       case WM_COMMAND:
1274         switch (LOWORD(wParam)) {
1275           case IDC6_NOXLAT:
1276           case IDC6_KOI8WIN1251:
1277           case IDC6_88592WIN1250:
1278             cfg.xlat_enablekoiwin =
1279                 IsDlgButtonChecked (hwnd, IDC6_KOI8WIN1251);
1280             cfg.xlat_88592w1250 =
1281                 IsDlgButtonChecked (hwnd, IDC6_88592WIN1250);
1282             break;
1283           case IDC6_CAPSLOCKCYR:
1284             if (HIWORD(wParam) == BN_CLICKED ||
1285                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1286                 cfg.xlat_capslockcyr =
1287                     IsDlgButtonChecked (hwnd, IDC6_CAPSLOCKCYR);
1288             }
1289             break;
1290           case IDC2_VTXWINDOWS:
1291           case IDC2_VTOEMANSI:
1292           case IDC2_VTOEMONLY:
1293           case IDC2_VTPOORMAN:
1294             cfg.vtmode =
1295                 (IsDlgButtonChecked (hwnd, IDC2_VTXWINDOWS) ? VT_XWINDOWS :
1296                  IsDlgButtonChecked (hwnd, IDC2_VTOEMANSI) ? VT_OEMANSI :
1297                  IsDlgButtonChecked (hwnd, IDC2_VTOEMONLY) ? VT_OEMONLY :
1298                  VT_POORMAN);
1299             break;
1300         }
1301     }
1302     return GeneralPanelProc (hwnd, msg, wParam, lParam);
1303 }
1304
1305 static DLGPROC panelproc[NPANELS] = {
1306     ConnectionProc, KeyboardProc, TerminalProc, WindowProc,
1307     TelnetProc, SshProc, SelectionProc, ColourProc, TranslationProc
1308 };
1309 static char *panelids[NPANELS] = {
1310     MAKEINTRESOURCE(IDD_PANEL0),
1311     MAKEINTRESOURCE(IDD_PANEL1),
1312     MAKEINTRESOURCE(IDD_PANEL2),
1313     MAKEINTRESOURCE(IDD_PANELW),
1314     MAKEINTRESOURCE(IDD_PANEL3),
1315     MAKEINTRESOURCE(IDD_PANEL35),
1316     MAKEINTRESOURCE(IDD_PANEL4),
1317     MAKEINTRESOURCE(IDD_PANEL5),
1318     MAKEINTRESOURCE(IDD_PANEL6)
1319 };
1320
1321 static char *names[NPANELS] = {
1322     "Connection", "Keyboard", "Terminal", "Window", "Telnet",
1323     "SSH", "Selection", "Colours", "Translation"
1324 };
1325
1326 static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8};
1327 static int reconfp[RECONF_NPANELS] = { 1, 2, 3, 6, 7, 8};
1328
1329 static int GenericMainDlgProc (HWND hwnd, UINT msg,
1330                                WPARAM wParam, LPARAM lParam,
1331                                int npanels, int *panelnums, HWND *page) {
1332     HWND hw;
1333
1334     switch (msg) {
1335       case WM_INITDIALOG:
1336         {                              /* centre the window */
1337             RECT rs, rd;
1338
1339             hw = GetDesktopWindow();
1340             if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
1341                 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
1342                             (rs.bottom + rs.top + rd.top - rd.bottom)/2,
1343                             rd.right-rd.left, rd.bottom-rd.top, TRUE);
1344         }
1345         *page = NULL;
1346         {                              /* initialise the tab control */
1347             TC_ITEMHEADER tab;
1348             int i;
1349
1350             hw = GetDlgItem (hwnd, IDC_TAB);
1351             for (i=0; i<npanels; i++) {
1352                 tab.mask = TCIF_TEXT;
1353                 tab.pszText = names[panelnums[i]];
1354                 TabCtrl_InsertItem (hw, i, &tab);
1355             }
1356 /*          *page = CreateDialogIndirect (hinst, panels[panelnums[0]].temp,
1357                                           hwnd, panelproc[panelnums[0]]);*/
1358             *page = CreateDialog (hinst, panelids[panelnums[0]],
1359                                   hwnd, panelproc[panelnums[0]]);
1360             SetWindowLong (*page, GWL_EXSTYLE,
1361                            GetWindowLong (*page, GWL_EXSTYLE) |
1362                            WS_EX_CONTROLPARENT);
1363         }
1364         SetFocus (*page);
1365         return 0;
1366       case WM_NOTIFY:
1367         if (LOWORD(wParam) == IDC_TAB &&
1368             ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
1369             int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
1370             if (*page)
1371                 DestroyWindow (*page);
1372 /*          *page = CreateDialogIndirect (hinst, panels[panelnums[i]].temp,     
1373                                           hwnd, panelproc[panelnums[i]]);*/
1374             *page = CreateDialog (hinst, panelids[panelnums[i]],
1375                                   hwnd, panelproc[panelnums[i]]);
1376             SetWindowLong (*page, GWL_EXSTYLE,
1377                            GetWindowLong (*page, GWL_EXSTYLE) |
1378                            WS_EX_CONTROLPARENT);
1379             SetFocus (((LPNMHDR)lParam)->hwndFrom);   /* ensure focus stays */
1380             return 0;
1381         }
1382         break;
1383 /*      case WM_CTLCOLORDLG: */
1384 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
1385       case WM_COMMAND:
1386         switch (LOWORD(wParam)) {
1387           case IDOK:
1388             if (*cfg.host)
1389                 EndDialog (hwnd, 1);
1390             else
1391                 MessageBeep (0);
1392             return 0;
1393           case IDCANCEL:
1394             EndDialog (hwnd, 0);
1395             return 0;
1396         }
1397         return 0;
1398       case WM_CLOSE:
1399         EndDialog (hwnd, 0);
1400         return 0;
1401
1402         /* Grrr Explorer will maximize Dialogs! */
1403       case WM_SIZE:
1404         if (wParam == SIZE_MAXIMIZED)
1405            force_normal(hwnd);
1406         return 0;
1407     }
1408     return 0;
1409 }
1410
1411 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
1412                                  WPARAM wParam, LPARAM lParam) {
1413 #if 0
1414     HWND hw;
1415     int i;
1416 #endif
1417     static HWND page = NULL;
1418
1419     if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
1420 #if 0
1421         /*
1422          * If the Connection panel is active and the Session List
1423          * box is selected, we treat a press of Open to have an
1424          * implicit press of Load preceding it.
1425          */
1426         hw = GetDlgItem (hwnd, IDC_TAB);
1427         i = TabCtrl_GetCurSel(hw);
1428         if (panelproc[mainp[i]] == ConnectionProc &&
1429             page && implicit_load_ok) {
1430             SendMessage (page, WM_COMMAND,
1431                          MAKELONG(IDC0_SESSLOAD, BN_CLICKED), 0);
1432         }
1433 #endif
1434     }
1435     if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
1436         EnableWindow(hwnd, 0);
1437         DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1438                   GetParent(hwnd), AboutProc);
1439         EnableWindow(hwnd, 1);
1440         SetActiveWindow(hwnd);
1441     }
1442     return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1443                                MAIN_NPANELS, mainp, &page);
1444 }
1445
1446 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
1447                                    WPARAM wParam, LPARAM lParam) {
1448     static HWND page;
1449     return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1450                                RECONF_NPANELS, reconfp, &page);
1451 }
1452
1453 void get_sesslist(int allocate) {
1454     static char otherbuf[2048];
1455     static char *buffer;
1456     int buflen, bufsize, i;
1457     char *p, *ret;
1458     void *handle;
1459
1460     if (allocate) {
1461         
1462         if ((handle = enum_settings_start()) == NULL)
1463             return;
1464
1465         buflen = bufsize = 0;
1466         buffer = NULL;
1467         do {
1468             ret = enum_settings_next(handle, otherbuf, sizeof(otherbuf));
1469             if (ret) {
1470                 int len = strlen(otherbuf)+1;
1471                 if (bufsize < buflen+len) {
1472                     bufsize = buflen + len + 2048;
1473                     buffer = srealloc(buffer, bufsize);
1474                 }
1475                 strcpy(buffer+buflen, otherbuf);
1476                 buflen += strlen(buffer+buflen)+1;
1477             }
1478         } while (ret);
1479         enum_settings_finish(handle);
1480         buffer = srealloc(buffer, buflen+1);
1481         buffer[buflen] = '\0';
1482
1483         p = buffer;
1484         nsessions = 1;                 /* "Default Settings" counts as one */
1485         while (*p) {
1486             if (strcmp(p, "Default Settings"))
1487                 nsessions++;
1488             while (*p) p++;
1489             p++;
1490         }
1491
1492         sessions = smalloc(nsessions * sizeof(char *));
1493         sessions[0] = "Default Settings";
1494         p = buffer;
1495         i = 1;
1496         while (*p) {
1497             if (strcmp(p, "Default Settings"))
1498                 sessions[i++] = p;
1499             while (*p) p++;
1500             p++;
1501         }
1502     } else {
1503         sfree (buffer);
1504         sfree (sessions);
1505     }
1506 }
1507
1508 int do_config (void) {
1509     int ret;
1510
1511     get_sesslist(TRUE);
1512     savedsession[0] = '\0';
1513     ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
1514     get_sesslist(FALSE);
1515
1516     return ret;
1517 }
1518
1519 int do_reconfig (HWND hwnd) {
1520     Config backup_cfg;
1521     int ret;
1522
1523     backup_cfg = cfg;                  /* structure copy */
1524     ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
1525     if (!ret)
1526         cfg = backup_cfg;              /* structure copy */
1527     else
1528         force_normal(hwnd);
1529
1530     return ret;
1531 }
1532
1533 void do_defaults (char *session) {
1534     if (session)
1535         load_settings (session, TRUE);
1536     else
1537         load_settings ("Default Settings", FALSE);
1538 }
1539
1540 void logevent (char *string) {
1541     if (nevents >= negsize) {
1542         negsize += 64;
1543         events = srealloc (events, negsize * sizeof(*events));
1544     }
1545     events[nevents] = smalloc(1+strlen(string));
1546     strcpy (events[nevents], string);
1547     nevents++;
1548     if (logbox) {
1549         int count;
1550         SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
1551                             0, (LPARAM)string);
1552         count = SendDlgItemMessage (logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
1553         SendDlgItemMessage (logbox, IDN_LIST, LB_SETTOPINDEX, count-1, 0);
1554     }
1555 }
1556
1557 void showeventlog (HWND hwnd) {
1558     if (!logbox) {
1559         logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
1560                                hwnd, LogProc);
1561         ShowWindow (logbox, SW_SHOWNORMAL);
1562     }
1563 }
1564
1565 void showabout (HWND hwnd) {
1566     if (!abtbox) {
1567         abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1568                                hwnd, AboutProc);
1569         ShowWindow (abtbox, SW_SHOWNORMAL);
1570     }
1571 }
1572
1573 void verify_ssh_host_key(char *host, int port, char *keytype,
1574                          char *keystr, char *fingerprint) {
1575     int ret;
1576
1577     static const char absentmsg[] =
1578         "The server's host key is not cached in the registry. You\n"
1579         "have no guarantee that the server is the computer you\n"
1580         "think it is.\n"
1581         "The server's key fingerprint is:\n"
1582         "%s\n"
1583         "If you trust this host, hit Yes to add the key to\n"
1584         "PuTTY's cache and carry on connecting.\n"
1585         "If you do not trust this host, hit No to abandon the\n"
1586         "connection.\n";
1587
1588     static const char wrongmsg[] =
1589         "WARNING - POTENTIAL SECURITY BREACH!\n"
1590         "\n"
1591         "The server's host key does not match the one PuTTY has\n"
1592         "cached in the registry. This means that either the\n"
1593         "server administrator has changed the host key, or you\n"
1594         "have actually connected to another computer pretending\n"
1595         "to be the server.\n"
1596         "The new key fingerprint is:\n"
1597         "%s\n"
1598         "If you were expecting this change and trust the new key,\n"
1599         "hit Yes to update PuTTY's cache and continue connecting.\n"
1600         "If you want to carry on connecting but without updating\n"
1601         "the cache, hit No.\n"
1602         "If you want to abandon the connection completely, hit\n"
1603         "Cancel. Hitting Cancel is the ONLY guaranteed safe\n"
1604         "choice.\n";
1605
1606     static const char mbtitle[] = "PuTTY Security Alert";
1607
1608     
1609     char message[160+                  /* sensible fingerprint max size */
1610                  (sizeof(absentmsg) > sizeof(wrongmsg) ?
1611                   sizeof(absentmsg) : sizeof(wrongmsg))];
1612
1613     /*
1614      * Verify the key against the registry.
1615      */
1616     ret = verify_host_key(host, port, keytype, keystr);
1617
1618     if (ret == 0)                      /* success - key matched OK */
1619         return;
1620     if (ret == 2) {                    /* key was different */
1621         int mbret;
1622         sprintf(message, wrongmsg, fingerprint);
1623         mbret = MessageBox(NULL, message, mbtitle,
1624                            MB_ICONWARNING | MB_YESNOCANCEL);
1625         if (mbret == IDYES)
1626             store_host_key(host, port, keytype, keystr);
1627         if (mbret == IDCANCEL)
1628             exit(0);
1629     }
1630     if (ret == 1) {                    /* key was absent */
1631         int mbret;
1632         sprintf(message, absentmsg, fingerprint);
1633         mbret = MessageBox(NULL, message, mbtitle,
1634                            MB_ICONWARNING | MB_YESNO);
1635         if (mbret == IDNO)
1636             exit(0);
1637         store_host_key(host, port, keytype, keystr);
1638     }
1639 }