]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - windlg.c
Single-DES encryption, patch courtesy of Murphy Lam
[PuTTY.git] / windlg.c
1 #include <windows.h>
2 #include <commctrl.h>
3 #include <commdlg.h>
4 #include <winsock.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7
8 #include "ssh.h"
9 #include "putty.h"
10 #include "win_res.h"
11
12 #define NPANELS 7
13 #define MAIN_NPANELS 7
14 #define RECONF_NPANELS 4
15
16 static const char *const puttystr = PUTTY_REG_POS "\\Sessions";
17
18 static void get_sesslist(int allocate);
19
20 static char **negots = NULL;
21 static int nnegots = 0, negsize = 0;
22 static HWND logbox = NULL, abtbox = NULL;
23
24 static char hex[16] = "0123456789ABCDEF";
25
26 static void mungestr(char *in, char *out) {
27     int candot = 0;
28
29     while (*in) {
30         if (*in == ' ' || *in == '\\' || *in == '*' || *in == '?' ||
31             *in == '%' || *in < ' ' || *in > '~' || (*in == '.' && !candot)) {
32             *out++ = '%';
33             *out++ = hex[((unsigned char)*in) >> 4];
34             *out++ = hex[((unsigned char)*in) & 15];
35         } else
36             *out++ = *in;
37         in++;
38         candot = 1;
39     }
40     *out = '\0';
41     return;
42 }
43
44 static void unmungestr(char *in, char *out) {
45     while (*in) {
46         if (*in == '%' && in[1] && in[2]) {
47             int i, j;
48
49             i = in[1] - '0'; i -= (i > 9 ? 7 : 0);
50             j = in[2] - '0'; j -= (j > 9 ? 7 : 0);
51
52             *out++ = (i<<4) + j;
53             in += 3;
54         } else
55             *out++ = *in++;
56     }
57     *out = '\0';
58     return;
59 }
60
61 static void wpps(HKEY key, LPCTSTR name, LPCTSTR value) {
62     RegSetValueEx(key, name, 0, REG_SZ, value, 1+strlen(value));
63 }
64
65 static void wppi(HKEY key, LPCTSTR name, int value) {
66     RegSetValueEx(key, name, 0, REG_DWORD,
67                   (CONST BYTE *)&value, sizeof(value));
68 }
69
70 static void gpps(HKEY key, LPCTSTR name, LPCTSTR def,
71                  LPTSTR val, int len) {
72     DWORD type, size;
73     size = len;
74
75     if (key == NULL ||
76         RegQueryValueEx(key, name, 0, &type, val, &size) != ERROR_SUCCESS ||
77         type != REG_SZ) {
78         strncpy(val, def, len);
79         val[len-1] = '\0';
80     }
81 }
82
83 static void gppi(HKEY key, LPCTSTR name, int def, int *i) {
84     DWORD type, val, size;
85     size = sizeof(val);
86
87     if (key == NULL ||
88         RegQueryValueEx(key, name, 0, &type,
89                         (BYTE *)&val, &size) != ERROR_SUCCESS ||
90         size != sizeof(val) || type != REG_DWORD)
91         *i = def;
92     else
93         *i = val;
94 }
95
96 static HINSTANCE hinst;
97
98 static char **sessions;
99 static int nsessions;
100
101 static int readytogo;
102
103 static void save_settings (char *section, int do_host) {
104     int i;
105     HKEY subkey1, sesskey;
106     char *p;
107
108     p = malloc(3*strlen(section)+1);
109     mungestr(section, p);
110     
111     if (RegCreateKey(HKEY_CURRENT_USER, puttystr, &subkey1)!=ERROR_SUCCESS ||
112         RegCreateKey(subkey1, p, &sesskey) != ERROR_SUCCESS) {
113         sesskey = NULL;
114     }
115
116     free(p);
117     RegCloseKey(subkey1);
118
119     wppi (sesskey, "Present", 1);
120     if (do_host) {
121         wpps (sesskey, "HostName", cfg.host);
122         wppi (sesskey, "PortNumber", cfg.port);
123         wpps (sesskey, "Protocol",
124               cfg.protocol == PROT_SSH ? "ssh" : "telnet");
125     }
126     wppi (sesskey, "CloseOnExit", !!cfg.close_on_exit);
127     wpps (sesskey, "TerminalType", cfg.termtype);
128     wpps (sesskey, "TerminalSpeed", cfg.termspeed);
129     {
130       char buf[2*sizeof(cfg.environmt)], *p, *q;
131         p = buf;
132       q = cfg.environmt;
133         while (*q) {
134             while (*q) {
135                 int c = *q++;
136                 if (c == '=' || c == ',' || c == '\\')
137                     *p++ = '\\';
138                 if (c == '\t')
139                     c = '=';
140                 *p++ = c;
141             }
142             *p++ = ',';
143             q++;
144         }
145         *p = '\0';
146         wpps (sesskey, "Environment", buf);
147     }
148     wpps (sesskey, "UserName", cfg.username);
149     wppi (sesskey, "NoPTY", cfg.nopty);
150     wpps (sesskey, "Cipher", cfg.cipher == CIPHER_BLOWFISH ? "blowfish" :
151                              cfg.cipher == CIPHER_DES ? "des" : "3des");
152     wppi (sesskey, "RFCEnviron", cfg.rfc_environ);
153     wppi (sesskey, "BackspaceIsDelete", cfg.bksp_is_delete);
154     wppi (sesskey, "RXVTHomeEnd", cfg.rxvt_homeend);
155     wppi (sesskey, "LinuxFunctionKeys", cfg.linux_funkeys);
156     wppi (sesskey, "ApplicationCursorKeys", cfg.app_cursor);
157     wppi (sesskey, "ApplicationKeypad", cfg.app_keypad);
158     wppi (sesskey, "ScrollbackLines", cfg.savelines);
159     wppi (sesskey, "DECOriginMode", cfg.dec_om);
160     wppi (sesskey, "AutoWrapMode", cfg.wrap_mode);
161     wppi (sesskey, "LFImpliesCR", cfg.lfhascr);
162     wppi (sesskey, "WinNameAlways", cfg.win_name_always);
163     wppi (sesskey, "TermWidth", cfg.width);
164     wppi (sesskey, "TermHeight", cfg.height);
165     wpps (sesskey, "Font", cfg.font);
166     wppi (sesskey, "FontIsBold", cfg.fontisbold);
167     wppi (sesskey, "FontHeight", cfg.fontheight);
168     wppi (sesskey, "FontVTMode", cfg.vtmode);
169     wppi (sesskey, "TryPalette", cfg.try_palette);
170     wppi (sesskey, "BoldAsColour", cfg.bold_colour);
171     for (i=0; i<22; i++) {
172         char buf[20], buf2[30];
173         sprintf(buf, "Colour%d", i);
174         sprintf(buf2, "%d,%d,%d", cfg.colours[i][0],
175                 cfg.colours[i][1], cfg.colours[i][2]);
176         wpps (sesskey, buf, buf2);
177     }
178     wppi (sesskey, "MouseIsXterm", cfg.mouse_is_xterm);
179     for (i=0; i<256; i+=32) {
180         char buf[20], buf2[256];
181         int j;
182         sprintf(buf, "Wordness%d", i);
183         *buf2 = '\0';
184         for (j=i; j<i+32; j++) {
185             sprintf(buf2+strlen(buf2), "%s%d",
186                     (*buf2 ? "," : ""), cfg.wordness[j]);
187         }
188         wpps (sesskey, buf, buf2);
189     }
190
191     RegCloseKey(sesskey);
192 }
193
194 static void del_session (char *section) {
195     HKEY subkey1;
196     char *p;
197
198     if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS)
199         return;
200
201     p = malloc(3*strlen(section)+1);
202     mungestr(section, p);
203     RegDeleteKey(subkey1, p);
204     free(p);
205
206     RegCloseKey(subkey1);
207 }
208
209 static void load_settings (char *section, int do_host) {
210     int i;
211     HKEY subkey1, sesskey;
212     char *p;
213
214     p = malloc(3*strlen(section)+1);
215     mungestr(section, p);
216
217     if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS) {
218         sesskey = NULL;
219     } else {
220         if (RegOpenKey(subkey1, p, &sesskey) != ERROR_SUCCESS) {
221             sesskey = NULL;
222         }
223         RegCloseKey(subkey1);
224     }
225
226     free(p);
227
228     if (do_host) {
229         char prot[10];
230         gpps (sesskey, "HostName", "", cfg.host, sizeof(cfg.host));
231         gppi (sesskey, "PortNumber", 23, &cfg.port);
232         gpps (sesskey, "Protocol", "telnet", prot, 10);
233         if (!strcmp(prot, "ssh"))
234             cfg.protocol = PROT_SSH;
235         else
236             cfg.protocol = PROT_TELNET;
237     } else {
238         cfg.protocol = PROT_TELNET;
239         cfg.port = 23;
240         *cfg.host = '\0';
241     }
242     gppi (sesskey, "CloseOnExit", 1, &cfg.close_on_exit);
243     gpps (sesskey, "TerminalType", "xterm", cfg.termtype,
244           sizeof(cfg.termtype));
245     gpps (sesskey, "TerminalSpeed", "38400,38400", cfg.termspeed,
246           sizeof(cfg.termspeed));
247     {
248       char buf[2*sizeof(cfg.environmt)], *p, *q;
249         gpps (sesskey, "Environment", "", buf, sizeof(buf));
250         p = buf;
251       q = cfg.environmt;
252         while (*p) {
253             while (*p && *p != ',') {
254                 int c = *p++;
255                 if (c == '=')
256                     c = '\t';
257                 if (c == '\\')
258                     c = *p++;
259                 *p++ = c;
260             }
261             if (*p == ',') p++;
262             *q++ = '\0';
263         }
264         *q = '\0';
265     }
266     gpps (sesskey, "UserName", "", cfg.username, sizeof(cfg.username));
267     gppi (sesskey, "NoPTY", 0, &cfg.nopty);
268     {
269         char cipher[10];
270         gpps (sesskey, "Cipher", "3des", cipher, 10);
271         if (!strcmp(cipher, "blowfish"))
272             cfg.cipher = CIPHER_BLOWFISH;
273         else if (!strcmp(cipher, "des"))
274             cfg.cipher = CIPHER_DES;
275         else
276             cfg.cipher = CIPHER_3DES;
277     }
278     gppi (sesskey, "RFCEnviron", 0, &cfg.rfc_environ);
279     gppi (sesskey, "BackspaceIsDelete", 1, &cfg.bksp_is_delete);
280     gppi (sesskey, "RXVTHomeEnd", 0, &cfg.rxvt_homeend);
281     gppi (sesskey, "LinuxFunctionKeys", 0, &cfg.linux_funkeys);
282     gppi (sesskey, "ApplicationCursorKeys", 0, &cfg.app_cursor);
283     gppi (sesskey, "ApplicationKeypad", 0, &cfg.app_keypad);
284     gppi (sesskey, "ScrollbackLines", 200, &cfg.savelines);
285     gppi (sesskey, "DECOriginMode", 0, &cfg.dec_om);
286     gppi (sesskey, "AutoWrapMode", 1, &cfg.wrap_mode);
287     gppi (sesskey, "LFImpliesCR", 0, &cfg.lfhascr);
288     gppi (sesskey, "WinNameAlways", 0, &cfg.win_name_always);
289     gppi (sesskey, "TermWidth", 80, &cfg.width);
290     gppi (sesskey, "TermHeight", 24, &cfg.height);
291     gpps (sesskey, "Font", "Courier", cfg.font, sizeof(cfg.font));
292     gppi (sesskey, "FontIsBold", 0, &cfg.fontisbold);
293     gppi (sesskey, "FontHeight", 10, &cfg.fontheight);
294     gppi (sesskey, "FontVTMode", VT_POORMAN, &cfg.vtmode);
295     gppi (sesskey, "TryPalette", 0, &cfg.try_palette);
296     gppi (sesskey, "BoldAsColour", 1, &cfg.bold_colour);
297     for (i=0; i<22; i++) {
298         static char *defaults[] = {
299             "187,187,187", "255,255,255", "0,0,0", "85,85,85", "0,0,0",
300             "0,255,0", "0,0,0", "85,85,85", "187,0,0", "255,85,85",
301             "0,187,0", "85,255,85", "187,187,0", "255,255,85", "0,0,187",
302             "85,85,255", "187,0,187", "255,85,255", "0,187,187",
303             "85,255,255", "187,187,187", "255,255,255"
304         };
305         char buf[20], buf2[30];
306         sprintf(buf, "Colour%d", i);
307         gpps (sesskey, buf, defaults[i], buf2, sizeof(buf2));
308         sscanf(buf2, "%d,%d,%d", &cfg.colours[i][0],
309                &cfg.colours[i][1], &cfg.colours[i][2]);
310     }
311     gppi (sesskey, "MouseIsXterm", 0, &cfg.mouse_is_xterm);
312     for (i=0; i<256; i+=32) {
313         static char *defaults[] = {
314             "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",
315             "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",
316             "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",
317             "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",
318             "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",
319             "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",
320             "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",
321             "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"
322         };
323         char buf[20], buf2[256], *p;
324         int j;
325         sprintf(buf, "Wordness%d", i);
326         gpps (sesskey, buf, defaults[i/32], buf2, sizeof(buf2));
327         p = buf2;
328         for (j=i; j<i+32; j++) {
329             char *q = p;
330             while (*p && *p != ',') p++;
331             if (*p == ',') *p++ = '\0';
332             cfg.wordness[j] = atoi(q);
333         }
334     }
335     RegCloseKey(sesskey);
336 }
337
338 static void MyGetDlgItemInt (HWND hwnd, int id, int *result) {
339     BOOL ok;
340     int n;
341     n = GetDlgItemInt (hwnd, id, &ok, FALSE);
342     if (ok)
343         *result = n;
344 }
345
346 static int CALLBACK LogProc (HWND hwnd, UINT msg,
347                              WPARAM wParam, LPARAM lParam) {
348     int i;
349
350     switch (msg) {
351       case WM_INITDIALOG:
352         for (i=0; i<nnegots; i++)
353             SendDlgItemMessage (hwnd, IDN_LIST, LB_ADDSTRING,
354                                 0, (LPARAM)negots[i]);
355         return 1;
356 /*      case WM_CTLCOLORDLG: */
357 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
358       case WM_COMMAND:
359         switch (LOWORD(wParam)) {
360           case IDOK:
361             logbox = NULL;
362             DestroyWindow (hwnd);
363             return 0;
364         }
365         return 0;
366       case WM_CLOSE:
367         logbox = NULL;
368         DestroyWindow (hwnd);
369         return 0;
370     }
371     return 0;
372 }
373
374 static int CALLBACK LicenceProc (HWND hwnd, UINT msg,
375                                  WPARAM wParam, LPARAM lParam) {
376     switch (msg) {
377       case WM_INITDIALOG:
378         return 1;
379       case WM_COMMAND:
380         switch (LOWORD(wParam)) {
381           case IDOK:
382             abtbox = NULL;
383             DestroyWindow (hwnd);
384             return 0;
385         }
386         return 0;
387       case WM_CLOSE:
388         abtbox = NULL;
389         DestroyWindow (hwnd);
390         return 0;
391     }
392     return 0;
393 }
394
395 static int CALLBACK AboutProc (HWND hwnd, UINT msg,
396                                WPARAM wParam, LPARAM lParam) {
397     switch (msg) {
398       case WM_INITDIALOG:
399         SetDlgItemText (hwnd, IDA_VERSION, ver);
400         return 1;
401 /*      case WM_CTLCOLORDLG: */
402 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
403 /*      case WM_CTLCOLORSTATIC: */
404 /*      SetBkColor ((HDC)wParam, RGB(192,192,192)); */
405 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
406       case WM_COMMAND:
407         switch (LOWORD(wParam)) {
408           case IDOK:
409             abtbox = NULL;
410             DestroyWindow (hwnd);
411             return 0;
412           case IDA_LICENCE:
413             EnableWindow(hwnd, 0);
414             DialogBox (hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
415                        NULL, LicenceProc);
416             EnableWindow(hwnd, 1);
417             return 0;
418         }
419         return 0;
420       case WM_CLOSE:
421         abtbox = NULL;
422         DestroyWindow (hwnd);
423         return 0;
424     }
425     return 0;
426 }
427
428 static int GeneralPanelProc (HWND hwnd, UINT msg,
429                              WPARAM wParam, LPARAM lParam) {
430     switch (msg) {
431       case WM_INITDIALOG:
432         SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
433         return 1;
434 /*      case WM_CTLCOLORDLG: */
435 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
436 /*      case WM_CTLCOLORSTATIC: */
437 /*      case WM_CTLCOLORBTN: */
438 /*      SetBkColor ((HDC)wParam, RGB(192,192,192)); */
439 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
440       case WM_CLOSE:
441         DestroyWindow (hwnd);
442         return 1;
443     }
444     return 0;
445 }
446
447 static int CALLBACK ConnectionProc (HWND hwnd, UINT msg,
448                                     WPARAM wParam, LPARAM lParam) {
449     int i;
450
451     switch (msg) {
452       case WM_INITDIALOG:
453         SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
454         SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
455         for (i = 0; i < nsessions; i++)
456             SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
457                                 0, (LPARAM) (sessions[i]));
458         CheckRadioButton (hwnd, IDC0_PROTTELNET, IDC0_PROTSSH,
459                           cfg.protocol==PROT_SSH ? IDC0_PROTSSH : IDC0_PROTTELNET);
460         CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
461         break;
462       case WM_LBUTTONUP:
463         /*
464          * Button release should trigger WM_OK if there was a
465          * previous double click on the session list.
466          */
467         ReleaseCapture();
468         if (readytogo)
469             SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
470         break;
471       case WM_COMMAND:
472         switch (LOWORD(wParam)) {
473           case IDC0_PROTTELNET:
474           case IDC0_PROTSSH:
475             if (HIWORD(wParam) == BN_CLICKED ||
476                 HIWORD(wParam) == BN_DOUBLECLICKED) {
477                 int i = IsDlgButtonChecked (hwnd, IDC0_PROTSSH);
478                 cfg.protocol = i ? PROT_SSH : PROT_TELNET;
479                 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
480                     (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
481                     cfg.port = i ? 22 : 23;
482                     SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
483                 }
484             }
485             break;
486           case IDC0_HOST:
487             if (HIWORD(wParam) == EN_CHANGE)
488                 GetDlgItemText (hwnd, IDC0_HOST, cfg.host,
489                                 sizeof(cfg.host)-1);
490             break;
491           case IDC0_PORT:
492             if (HIWORD(wParam) == EN_CHANGE)
493                 MyGetDlgItemInt (hwnd, IDC0_PORT, &cfg.port);
494             break;
495           case IDC0_CLOSEEXIT:
496             if (HIWORD(wParam) == BN_CLICKED ||
497                 HIWORD(wParam) == BN_DOUBLECLICKED)
498                 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC0_CLOSEEXIT);
499             break;
500           case IDC0_SESSEDIT:
501             if (HIWORD(wParam) == EN_CHANGE)
502                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
503                                     (WPARAM) -1, 0);
504             break;
505           case IDC0_SESSSAVE:
506             if (HIWORD(wParam) == BN_CLICKED ||
507                 HIWORD(wParam) == BN_DOUBLECLICKED) {
508                 /*
509                  * Save a session
510                  */
511                 char str[2048];
512                 GetDlgItemText (hwnd, IDC0_SESSEDIT, str, sizeof(str)-1);
513                 if (!*str) {
514                     int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
515                                                 LB_GETCURSEL, 0, 0);
516                     if (n == LB_ERR) {
517                         MessageBeep(0);
518                         break;
519                     }
520                     strcpy (str, sessions[n]);
521                 }
522                 save_settings (str, !!strcmp(str, "Default Settings"));
523                 get_sesslist (FALSE);
524                 get_sesslist (TRUE);
525                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
526                                     0, 0);
527                 for (i = 0; i < nsessions; i++)
528                     SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
529                                         0, (LPARAM) (sessions[i]));
530                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
531                                     (WPARAM) -1, 0);
532             }
533             break;
534           case IDC0_SESSLIST:
535           case IDC0_SESSLOAD:
536             if (LOWORD(wParam) == IDC0_SESSLOAD &&
537                 HIWORD(wParam) != BN_CLICKED &&
538                 HIWORD(wParam) != BN_DOUBLECLICKED)
539                 break;
540             if (LOWORD(wParam) == IDC0_SESSLIST &&
541                 HIWORD(wParam) != LBN_DBLCLK)
542                 break;
543             {
544                 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
545                                             LB_GETCURSEL, 0, 0);
546                 if (n == LB_ERR) {
547                     MessageBeep(0);
548                     break;
549                 }
550                 load_settings (sessions[n],
551                                !!strcmp(sessions[n], "Default Settings"));
552                 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
553                 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
554                 CheckRadioButton (hwnd, IDC0_PROTTELNET, IDC0_PROTSSH,
555                                   (cfg.protocol==PROT_SSH ? IDC0_PROTSSH :
556                                    IDC0_PROTTELNET));
557                 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
558                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
559                                     (WPARAM) -1, 0);
560             }
561             if (LOWORD(wParam) == IDC0_SESSLIST) {
562                 /*
563                  * A double-click on a saved session should
564                  * actually start the session, not just load it.
565                  * Unless it's Default Settings or some other
566                  * host-less set of saved settings.
567                  */
568                 if (*cfg.host) {
569                     readytogo = TRUE;
570                     SetCapture(hwnd);
571                 }
572             }
573             break;
574           case IDC0_SESSDEL:
575             if (HIWORD(wParam) == BN_CLICKED ||
576                 HIWORD(wParam) == BN_DOUBLECLICKED) {
577                 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
578                                             LB_GETCURSEL, 0, 0);
579                 if (n == LB_ERR || n == 0) {
580                     MessageBeep(0);
581                     break;
582                 }
583                 del_session(sessions[n]);
584                 get_sesslist (FALSE);
585                 get_sesslist (TRUE);
586                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
587                                     0, 0);
588                 for (i = 0; i < nsessions; i++)
589                     SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
590                                         0, (LPARAM) (sessions[i]));
591                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
592                                     (WPARAM) -1, 0);
593             }
594         }
595     }
596     return GeneralPanelProc (hwnd, msg, wParam, lParam);
597 }
598
599 static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
600                                     WPARAM wParam, LPARAM lParam) {
601     switch (msg) {
602       case WM_INITDIALOG:
603         CheckRadioButton (hwnd, IDC1_DEL008, IDC1_DEL127,
604                           cfg.bksp_is_delete ? IDC1_DEL127 : IDC1_DEL008);
605         CheckRadioButton (hwnd, IDC1_HOMETILDE, IDC1_HOMERXVT,
606                           cfg.rxvt_homeend ? IDC1_HOMERXVT : IDC1_HOMETILDE);
607         CheckRadioButton (hwnd, IDC1_FUNCTILDE, IDC1_FUNCLINUX,
608                           cfg.linux_funkeys ? IDC1_FUNCLINUX : IDC1_FUNCTILDE);
609         CheckRadioButton (hwnd, IDC1_CURNORMAL, IDC1_CURAPPLIC,
610                           cfg.app_cursor ? IDC1_CURAPPLIC : IDC1_CURNORMAL);
611         CheckRadioButton (hwnd, IDC1_KPNORMAL, IDC1_KPAPPLIC,
612                           cfg.app_keypad ? IDC1_KPAPPLIC : IDC1_KPNORMAL);
613         break;
614       case WM_COMMAND:
615         if (HIWORD(wParam) == BN_CLICKED ||
616             HIWORD(wParam) == BN_DOUBLECLICKED)
617             switch (LOWORD(wParam)) {
618               case IDC1_DEL008:
619               case IDC1_DEL127:
620                 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC1_DEL127);
621                 break;
622               case IDC1_HOMETILDE:
623               case IDC1_HOMERXVT:
624                 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC1_HOMERXVT);
625                 break;
626               case IDC1_FUNCTILDE:
627               case IDC1_FUNCLINUX:
628                 cfg.linux_funkeys = IsDlgButtonChecked (hwnd, IDC1_FUNCLINUX);
629                 break;
630               case IDC1_KPNORMAL:
631               case IDC1_KPAPPLIC:
632                 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC1_KPAPPLIC);
633                 break;
634               case IDC1_CURNORMAL:
635               case IDC1_CURAPPLIC:
636                 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC1_CURAPPLIC);
637                 break;
638             }
639     }
640     return GeneralPanelProc (hwnd, msg, wParam, lParam);
641 }
642
643 static void fmtfont (char *buf) {
644     sprintf (buf, "Font: %s, ", cfg.font);
645     if (cfg.fontisbold)
646         strcat(buf, "bold, ");
647     if (cfg.fontheight == 0)
648         strcat (buf, "default height");
649     else
650         sprintf (buf+strlen(buf), "%d-%s",
651                  (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
652                  (cfg.fontheight < 0 ? "pixel" : "point"));
653 }
654
655 static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
656                                     WPARAM wParam, LPARAM lParam) {
657     CHOOSEFONT cf;
658     LOGFONT lf;
659     char fontstatic[256];
660
661     switch (msg) {
662       case WM_INITDIALOG:
663         CheckDlgButton (hwnd, IDC2_WRAPMODE, cfg.wrap_mode);
664         CheckDlgButton (hwnd, IDC2_WINNAME, cfg.win_name_always);
665         CheckDlgButton (hwnd, IDC2_DECOM, cfg.dec_om);
666         CheckDlgButton (hwnd, IDC2_LFHASCR, cfg.lfhascr);
667         SetDlgItemInt (hwnd, IDC2_ROWSEDIT, cfg.height, FALSE);
668         SetDlgItemInt (hwnd, IDC2_COLSEDIT, cfg.width, FALSE);
669         SetDlgItemInt (hwnd, IDC2_SAVEEDIT, cfg.savelines, FALSE);
670         fmtfont (fontstatic);
671         SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
672         CheckRadioButton (hwnd, IDC2_VTXWINDOWS, IDC2_VTPOORMAN,
673                           cfg.vtmode == VT_XWINDOWS ? IDC2_VTXWINDOWS :
674                           cfg.vtmode == VT_OEMANSI ? IDC2_VTOEMANSI :
675                           cfg.vtmode == VT_OEMONLY ? IDC2_VTOEMONLY :
676                           IDC2_VTPOORMAN);
677         break;
678       case WM_COMMAND:
679         switch (LOWORD(wParam)) {
680           case IDC2_WRAPMODE:
681             if (HIWORD(wParam) == BN_CLICKED ||
682                 HIWORD(wParam) == BN_DOUBLECLICKED)
683                 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC2_WRAPMODE);
684             break;
685           case IDC2_WINNAME:
686             if (HIWORD(wParam) == BN_CLICKED ||
687                 HIWORD(wParam) == BN_DOUBLECLICKED)
688                 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC2_WINNAME);
689             break;
690           case IDC2_DECOM:
691             if (HIWORD(wParam) == BN_CLICKED ||
692                 HIWORD(wParam) == BN_DOUBLECLICKED)
693                 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC2_DECOM);
694             break;
695           case IDC2_LFHASCR:
696             if (HIWORD(wParam) == BN_CLICKED ||
697                 HIWORD(wParam) == BN_DOUBLECLICKED)
698                 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC2_LFHASCR);
699             break;
700           case IDC2_ROWSEDIT:
701             if (HIWORD(wParam) == EN_CHANGE)
702                 MyGetDlgItemInt (hwnd, IDC2_ROWSEDIT, &cfg.height);
703             break;
704           case IDC2_COLSEDIT:
705             if (HIWORD(wParam) == EN_CHANGE)
706                 MyGetDlgItemInt (hwnd, IDC2_COLSEDIT, &cfg.width);
707             break;
708           case IDC2_SAVEEDIT:
709             if (HIWORD(wParam) == EN_CHANGE)
710                 MyGetDlgItemInt (hwnd, IDC2_SAVEEDIT, &cfg.savelines);
711             break;
712           case IDC2_CHOOSEFONT:
713             lf.lfHeight = cfg.fontheight;
714             lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
715             lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
716             lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
717             lf.lfCharSet = ANSI_CHARSET;
718             lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
719             lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
720             lf.lfQuality = DEFAULT_QUALITY;
721             lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
722             strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
723             lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
724
725             cf.lStructSize = sizeof(cf);
726             cf.hwndOwner = hwnd;
727             cf.lpLogFont = &lf;
728             cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
729                 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
730
731             if (ChooseFont (&cf)) {
732                 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
733                 cfg.font[sizeof(cfg.font)-1] = '\0';
734                 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
735                 cfg.fontheight = lf.lfHeight;
736                 fmtfont (fontstatic);
737                 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
738             }
739             break;
740           case IDC2_VTXWINDOWS:
741           case IDC2_VTOEMANSI:
742           case IDC2_VTOEMONLY:
743           case IDC2_VTPOORMAN:
744             cfg.vtmode =
745                 (IsDlgButtonChecked (hwnd, IDC2_VTXWINDOWS) ? VT_XWINDOWS :
746                  IsDlgButtonChecked (hwnd, IDC2_VTOEMANSI) ? VT_OEMANSI :
747                  IsDlgButtonChecked (hwnd, IDC2_VTOEMONLY) ? VT_OEMONLY :
748                  VT_POORMAN);
749             break;
750         }
751         break;
752     }
753     return GeneralPanelProc (hwnd, msg, wParam, lParam);
754 }
755
756 static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
757                                     WPARAM wParam, LPARAM lParam) {
758     int i;
759
760     switch (msg) {
761       case WM_INITDIALOG:
762         SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
763         SetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed);
764         SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
765         {
766           char *p = cfg.environmt;
767             while (*p) {
768                 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING, 0,
769                                     (LPARAM) p);
770                 p += strlen(p)+1;
771             }
772         }
773         CheckRadioButton (hwnd, IDC3_EMBSD, IDC3_EMRFC,
774                           cfg.rfc_environ ? IDC3_EMRFC : IDC3_EMBSD);
775         break;
776       case WM_COMMAND:
777         switch (LOWORD(wParam)) {
778           case IDC3_TTEDIT:
779             if (HIWORD(wParam) == EN_CHANGE)
780             GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
781                             sizeof(cfg.termtype)-1);
782             break;
783           case IDC3_TSEDIT:
784             if (HIWORD(wParam) == EN_CHANGE)
785                 GetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed,
786                                 sizeof(cfg.termspeed)-1);
787             break;
788           case IDC3_LOGEDIT:
789             if (HIWORD(wParam) == EN_CHANGE)
790                 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
791                                 sizeof(cfg.username)-1);
792             break;
793           case IDC3_EMBSD:
794           case IDC3_EMRFC:
795             cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC3_EMRFC);
796             break;
797           case IDC3_ENVADD:
798             if (HIWORD(wParam) == BN_CLICKED ||
799                 HIWORD(wParam) == BN_DOUBLECLICKED) {
800               char str[sizeof(cfg.environmt)];
801                 char *p;
802                 GetDlgItemText (hwnd, IDC3_VAREDIT, str, sizeof(str)-1);
803                 if (!*str) {
804                     MessageBeep(0);
805                     break;
806                 }
807                 p = str + strlen(str);
808                 *p++ = '\t';
809                 GetDlgItemText (hwnd, IDC3_VALEDIT, p, sizeof(str)-1-(p-str));
810                 if (!*p) {
811                     MessageBeep(0);
812                     break;
813                 }
814               p = cfg.environmt;
815                 while (*p) {
816                     while (*p) p++;
817                     p++;
818                 }
819               if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
820                     strcpy (p, str);
821                     p[strlen(str)+1] = '\0';
822                     SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING,
823                                         0, (LPARAM)str);
824                     SetDlgItemText (hwnd, IDC3_VAREDIT, "");
825                     SetDlgItemText (hwnd, IDC3_VALEDIT, "");
826                 } else {
827                     MessageBox(hwnd, "Environment too big", "PuTTY Error",
828                                MB_OK | MB_ICONERROR);
829                 }
830             }
831             break;
832           case IDC3_ENVREMOVE:
833             if (HIWORD(wParam) != BN_CLICKED &&
834                 HIWORD(wParam) != BN_DOUBLECLICKED)
835                 break;
836             i = SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_GETCURSEL, 0, 0);
837             if (i == LB_ERR)
838                 MessageBeep (0);
839             else {
840                 char *p, *q;
841
842                 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_DELETESTRING,
843                                     i, 0);
844               p = cfg.environmt;
845                 while (i > 0) {
846                     if (!*p)
847                         goto disaster;
848                     while (*p) p++;
849                     p++;
850                     i--;
851                 }
852                 q = p;
853                 if (!*p)
854                     goto disaster;
855                 while (*p) p++;
856                 p++;
857                 while (*p) {
858                     while (*p)
859                         *q++ = *p++;
860                     *q++ = *p++;
861                 }
862                 *q = '\0';
863                 disaster:;
864             }
865             break;
866         }
867         break;
868     }
869     return GeneralPanelProc (hwnd, msg, wParam, lParam);
870 }
871
872 static int CALLBACK SshProc (HWND hwnd, UINT msg,
873                              WPARAM wParam, LPARAM lParam) {
874     switch (msg) {
875       case WM_INITDIALOG:
876         SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
877         SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
878         CheckDlgButton (hwnd, IDC3_NOPTY, cfg.nopty);
879         CheckRadioButton (hwnd, IDC3_CIPHER3DES, IDC3_CIPHERDES,
880                           cfg.cipher == CIPHER_BLOWFISH ? IDC3_CIPHERBLOWF :
881                           cfg.cipher == CIPHER_DES ? IDC3_CIPHERDES :
882
883                           IDC3_CIPHER3DES);
884         break;
885       case WM_COMMAND:
886         switch (LOWORD(wParam)) {
887           case IDC3_TTEDIT:
888             if (HIWORD(wParam) == EN_CHANGE)
889             GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
890                             sizeof(cfg.termtype)-1);
891             break;
892           case IDC3_LOGEDIT:
893             if (HIWORD(wParam) == EN_CHANGE)
894                 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
895                                 sizeof(cfg.username)-1);
896             break;
897           case IDC3_NOPTY:
898             if (HIWORD(wParam) == BN_CLICKED ||
899                 HIWORD(wParam) == BN_DOUBLECLICKED)
900                 cfg.nopty = IsDlgButtonChecked (hwnd, IDC3_NOPTY);
901             break;
902           case IDC3_CIPHER3DES:
903           case IDC3_CIPHERBLOWF:
904           case IDC3_CIPHERDES:
905             if (HIWORD(wParam) == BN_CLICKED ||
906                 HIWORD(wParam) == BN_DOUBLECLICKED) {
907                 if (IsDlgButtonChecked (hwnd, IDC3_CIPHER3DES))
908                     cfg.cipher = CIPHER_3DES;
909                 else if (IsDlgButtonChecked (hwnd, IDC3_CIPHERBLOWF))
910                     cfg.cipher = CIPHER_BLOWFISH;
911                 else if (IsDlgButtonChecked (hwnd, IDC3_CIPHERDES))
912                     cfg.cipher = CIPHER_DES;
913             }
914             break;
915         }
916         break;
917     }
918     return GeneralPanelProc (hwnd, msg, wParam, lParam);
919 }
920
921 static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
922                                     WPARAM wParam, LPARAM lParam) {
923     int i;
924
925     switch (msg) {
926       case WM_INITDIALOG:
927         CheckRadioButton (hwnd, IDC4_MBWINDOWS, IDC4_MBXTERM,
928                           cfg.mouse_is_xterm ? IDC4_MBXTERM : IDC4_MBWINDOWS);
929         {
930             static int tabs[4] = {25, 61, 96, 128};
931             SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_SETTABSTOPS, 4,
932                                 (LPARAM) tabs);
933         }
934         for (i=0; i<256; i++) {
935             char str[100];
936             sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
937                     (i>=0x21 && i != 0x7F) ? i : ' ',
938                     cfg.wordness[i]);
939             SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_ADDSTRING, 0,
940                                 (LPARAM) str);
941         }
942         break;
943       case WM_COMMAND:
944         switch (LOWORD(wParam)) {
945           case IDC4_MBWINDOWS:
946           case IDC4_MBXTERM:
947             cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC4_MBXTERM);
948             break;
949           case IDC4_CCSET:
950             {
951                 BOOL ok;
952                 int i;
953                 int n = GetDlgItemInt (hwnd, IDC4_CCEDIT, &ok, FALSE);
954
955                 if (!ok)
956                     MessageBeep (0);
957                 else {
958                     for (i=0; i<256; i++)
959                         if (SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_GETSEL,
960                                                 i, 0)) {
961                             char str[100];
962                             cfg.wordness[i] = n;
963                             SendDlgItemMessage (hwnd, IDC4_CCLIST,
964                                                 LB_DELETESTRING, i, 0);
965                             sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
966                                     (i>=0x21 && i != 0x7F) ? i : ' ',
967                                     cfg.wordness[i]);
968                             SendDlgItemMessage (hwnd, IDC4_CCLIST,
969                                                 LB_INSERTSTRING, i,
970                                                 (LPARAM)str);
971                         }
972                 }
973             }
974             break;
975         }
976         break;
977     }
978     return GeneralPanelProc (hwnd, msg, wParam, lParam);
979 }
980
981 static int CALLBACK ColourProc (HWND hwnd, UINT msg,
982                                     WPARAM wParam, LPARAM lParam) {
983     static const char *const colours[] = {
984         "Default Foreground", "Default Bold Foreground",
985         "Default Background", "Default Bold Background",
986         "Cursor Text", "Cursor Colour",
987         "ANSI Black", "ANSI Black Bold",
988         "ANSI Red", "ANSI Red Bold",
989         "ANSI Green", "ANSI Green Bold",
990         "ANSI Yellow", "ANSI Yellow Bold",
991         "ANSI Blue", "ANSI Blue Bold",
992         "ANSI Magenta", "ANSI Magenta Bold",
993         "ANSI Cyan", "ANSI Cyan Bold",
994         "ANSI White", "ANSI White Bold"
995     };
996     static const int permanent[] = {
997         TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
998         TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
999         TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
1000     };
1001     switch (msg) {
1002       case WM_INITDIALOG:
1003         CheckDlgButton (hwnd, IDC5_BOLDCOLOUR, cfg.bold_colour);
1004         CheckDlgButton (hwnd, IDC5_PALETTE, cfg.try_palette);
1005         {
1006             int i;
1007             for (i=0; i<22; i++)
1008                 if (cfg.bold_colour || permanent[i])
1009                     SendDlgItemMessage (hwnd, IDC5_LIST, LB_ADDSTRING, 0,
1010                                         (LPARAM) colours[i]);
1011         }
1012         SendDlgItemMessage (hwnd, IDC5_LIST, LB_SETCURSEL, 0, 0);
1013         SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[0][0], FALSE);
1014         SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[0][1], FALSE);
1015         SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[0][2], FALSE);
1016         break;
1017       case WM_COMMAND:
1018         switch (LOWORD(wParam)) {
1019           case IDC5_BOLDCOLOUR:
1020             if (HIWORD(wParam) == BN_CLICKED ||
1021                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1022                 int n, i;
1023                 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC5_BOLDCOLOUR);
1024                 n = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCOUNT, 0, 0);
1025                 if (cfg.bold_colour && n!=22) {
1026                     for (i=0; i<22; i++)
1027                         if (!permanent[i])
1028                             SendDlgItemMessage (hwnd, IDC5_LIST,
1029                                                 LB_INSERTSTRING, i,
1030                                                 (LPARAM) colours[i]);
1031                 } else if (!cfg.bold_colour && n!=12) {
1032                     for (i=22; i-- ;)
1033                         if (!permanent[i])
1034                             SendDlgItemMessage (hwnd, IDC5_LIST,
1035                                                 LB_DELETESTRING, i, 0);
1036                 }
1037             }
1038             break;
1039           case IDC5_PALETTE:
1040             if (HIWORD(wParam) == BN_CLICKED ||
1041                 HIWORD(wParam) == BN_DOUBLECLICKED)
1042                 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC5_PALETTE);
1043             break;
1044           case IDC5_LIST:
1045             if (HIWORD(wParam) == LBN_DBLCLK ||
1046                 HIWORD(wParam) == LBN_SELCHANGE) {
1047                 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1048                                             0, 0);
1049                 if (!cfg.bold_colour)
1050                     i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1051                 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0], FALSE);
1052                 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1], FALSE);
1053                 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2], FALSE);
1054             }
1055             break;
1056           case IDC5_CHANGE:
1057             if (HIWORD(wParam) == BN_CLICKED ||
1058                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1059                 static CHOOSECOLOR cc;
1060                 static DWORD custom[16] = {0};   /* zero initialisers */
1061                 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1062                                             0, 0);
1063                 if (!cfg.bold_colour)
1064                     i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1065                 cc.lStructSize = sizeof(cc);
1066                 cc.hwndOwner = hwnd;
1067                 cc.hInstance = hinst;
1068                 cc.lpCustColors = custom;
1069                 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
1070                                     cfg.colours[i][2]);
1071                 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
1072                 if (ChooseColor(&cc)) {
1073                     cfg.colours[i][0] =
1074                         (unsigned char) (cc.rgbResult & 0xFF);
1075                     cfg.colours[i][1] =
1076                         (unsigned char) (cc.rgbResult >> 8) & 0xFF;
1077                     cfg.colours[i][2] =
1078                         (unsigned char) (cc.rgbResult >> 16) & 0xFF;
1079                     SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0],
1080                                    FALSE);
1081                     SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1],
1082                                    FALSE);
1083                     SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2],
1084                                    FALSE);
1085                 }
1086             }
1087             break;
1088         }
1089         break;
1090     }
1091     return GeneralPanelProc (hwnd, msg, wParam, lParam);
1092 }
1093
1094 static DLGPROC panelproc[NPANELS] = {
1095     ConnectionProc, KeyboardProc, TerminalProc,
1096     TelnetProc, SshProc, SelectionProc, ColourProc
1097 };
1098 static char *panelids[NPANELS] = {
1099     MAKEINTRESOURCE(IDD_PANEL0),
1100     MAKEINTRESOURCE(IDD_PANEL1),
1101     MAKEINTRESOURCE(IDD_PANEL2),
1102     MAKEINTRESOURCE(IDD_PANEL3),
1103     MAKEINTRESOURCE(IDD_PANEL35),
1104     MAKEINTRESOURCE(IDD_PANEL4),
1105     MAKEINTRESOURCE(IDD_PANEL5)
1106 };
1107 static char *names[NPANELS] = {
1108     "Connection", "Keyboard", "Terminal", "Telnet", "SSH", "Selection", "Colours"
1109 };
1110
1111 static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6 };
1112 static int reconfp[RECONF_NPANELS] = { 1, 2, 5, 6 };
1113
1114 static int GenericMainDlgProc (HWND hwnd, UINT msg,
1115                                WPARAM wParam, LPARAM lParam,
1116                                int npanels, int *panelnums, HWND *page) {
1117     HWND hw;
1118
1119     switch (msg) {
1120       case WM_INITDIALOG:
1121         {                              /* centre the window */
1122             RECT rs, rd;
1123
1124             hw = GetDesktopWindow();
1125             if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
1126                 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
1127                             (rs.bottom + rs.top + rd.top - rd.bottom)/2,
1128                             rd.right-rd.left, rd.bottom-rd.top, TRUE);
1129         }
1130         *page = NULL;
1131         {                              /* initialise the tab control */
1132             TC_ITEMHEADER tab;
1133             int i;
1134
1135             hw = GetDlgItem (hwnd, IDC_TAB);
1136             for (i=0; i<npanels; i++) {
1137                 tab.mask = TCIF_TEXT;
1138                 tab.pszText = names[panelnums[i]];
1139                 TabCtrl_InsertItem (hw, i, &tab);
1140             }
1141 /*          *page = CreateDialogIndirect (hinst, panels[panelnums[0]].temp,
1142                                           hwnd, panelproc[panelnums[0]]);*/
1143             *page = CreateDialog (hinst, panelids[panelnums[0]],
1144                                   hwnd, panelproc[panelnums[0]]);
1145             SetWindowLong (*page, GWL_EXSTYLE,
1146                            GetWindowLong (*page, GWL_EXSTYLE) |
1147                            WS_EX_CONTROLPARENT);
1148         }
1149         SetFocus (*page);
1150         return 0;
1151       case WM_NOTIFY:
1152         if (LOWORD(wParam) == IDC_TAB &&
1153             ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
1154             int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
1155             if (*page)
1156                 DestroyWindow (*page);
1157 /*          *page = CreateDialogIndirect (hinst, panels[panelnums[i]].temp,     
1158                                           hwnd, panelproc[panelnums[i]]);*/
1159             *page = CreateDialog (hinst, panelids[panelnums[i]],
1160                                   hwnd, panelproc[panelnums[i]]);
1161             SetWindowLong (*page, GWL_EXSTYLE,
1162                            GetWindowLong (*page, GWL_EXSTYLE) |
1163                            WS_EX_CONTROLPARENT);
1164             SetFocus (((LPNMHDR)lParam)->hwndFrom);   /* ensure focus stays */
1165             return 0;
1166         }
1167         break;
1168 /*      case WM_CTLCOLORDLG: */
1169 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
1170       case WM_COMMAND:
1171         switch (LOWORD(wParam)) {
1172           case IDOK:
1173             if (*cfg.host)
1174                 EndDialog (hwnd, 1);
1175             else
1176                 MessageBeep (0);
1177             return 0;
1178           case IDCANCEL:
1179             EndDialog (hwnd, 0);
1180             return 0;
1181         }
1182         return 0;
1183       case WM_CLOSE:
1184         EndDialog (hwnd, 0);
1185         return 0;
1186     }
1187     return 0;
1188 }
1189
1190 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
1191                                  WPARAM wParam, LPARAM lParam) {
1192 #if 0
1193     HWND hw;
1194     int i;
1195 #endif
1196     static HWND page = NULL;
1197
1198     if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
1199 #if 0
1200         /*
1201          * If the Connection panel is active and the Session List
1202          * box is selected, we treat a press of Open to have an
1203          * implicit press of Load preceding it.
1204          */
1205         hw = GetDlgItem (hwnd, IDC_TAB);
1206         i = TabCtrl_GetCurSel(hw);
1207         if (panelproc[mainp[i]] == ConnectionProc &&
1208             page && implicit_load_ok) {
1209             SendMessage (page, WM_COMMAND,
1210                          MAKELONG(IDC0_SESSLOAD, BN_CLICKED), 0);
1211         }
1212 #endif
1213     }
1214     if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
1215         EnableWindow(hwnd, 0);
1216         DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1217                   GetParent(hwnd), AboutProc);
1218         EnableWindow(hwnd, 1);
1219     }
1220     return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1221                                MAIN_NPANELS, mainp, &page);
1222 }
1223
1224 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
1225                                    WPARAM wParam, LPARAM lParam) {
1226     static HWND page;
1227     return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1228                                RECONF_NPANELS, reconfp, &page);
1229 }
1230
1231 static void get_sesslist(int allocate) {
1232     static char *buffer;
1233     int buflen, bufsize, i, ret;
1234     char otherbuf[2048];
1235     char *p;
1236     HKEY subkey1;
1237
1238     if (allocate) {
1239         if (RegCreateKey(HKEY_CURRENT_USER,
1240                          puttystr, &subkey1) != ERROR_SUCCESS)
1241             return;
1242
1243         buflen = bufsize = 0;
1244         buffer = NULL;
1245         i = 0;
1246         do {
1247             ret = RegEnumKey(subkey1, i++, otherbuf, sizeof(otherbuf));
1248             if (ret == ERROR_SUCCESS) {
1249                 bufsize = buflen + 2048;
1250                 buffer = srealloc(buffer, bufsize);
1251                 unmungestr(otherbuf, buffer+buflen);
1252                 buflen += strlen(buffer+buflen)+1;
1253             }
1254         } while (ret == ERROR_SUCCESS);
1255         buffer = srealloc(buffer, buflen+1);
1256         buffer[buflen] = '\0';
1257
1258         p = buffer;
1259         nsessions = 1;                 /* "Default Settings" counts as one */
1260         while (*p) {
1261             if (strcmp(p, "Default Settings"))
1262                 nsessions++;
1263             while (*p) p++;
1264             p++;
1265         }
1266
1267         sessions = smalloc(nsessions * sizeof(char *));
1268         sessions[0] = "Default Settings";
1269         p = buffer;
1270         i = 1;
1271         while (*p) {
1272             if (strcmp(p, "Default Settings"))
1273                 sessions[i++] = p;
1274             while (*p) p++;
1275             p++;
1276         }
1277     } else {
1278         sfree (buffer);
1279         sfree (sessions);
1280     }
1281 }
1282
1283 int do_config (void) {
1284     int ret;
1285
1286     get_sesslist(TRUE);
1287     ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
1288     get_sesslist(FALSE);
1289
1290     return ret;
1291 }
1292
1293 int do_reconfig (HWND hwnd) {
1294     Config backup_cfg;
1295     int ret;
1296
1297     backup_cfg = cfg;                  /* structure copy */
1298     ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
1299     if (!ret)
1300         cfg = backup_cfg;              /* structure copy */
1301     return ret;
1302 }
1303
1304 void do_defaults (char *session) {
1305     if (session)
1306         load_settings (session, TRUE);
1307     else
1308         load_settings ("Default Settings", FALSE);
1309 }
1310
1311 void lognegot (char *string) {
1312     if (nnegots >= negsize) {
1313         negsize += 64;
1314         negots = srealloc (negots, negsize * sizeof(*negots));
1315     }
1316     negots[nnegots] = smalloc(1+strlen(string));
1317     strcpy (negots[nnegots], string);
1318     nnegots++;
1319     if (logbox)
1320         SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
1321                             0, (LPARAM)string);
1322 }
1323
1324 void shownegot (HWND hwnd) {
1325     if (!logbox) {
1326         logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
1327                                hwnd, LogProc);
1328         ShowWindow (logbox, SW_SHOWNORMAL);
1329     }
1330 }
1331
1332 void showabout (HWND hwnd) {
1333     if (!abtbox) {
1334         abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1335                                hwnd, AboutProc);
1336         ShowWindow (abtbox, SW_SHOWNORMAL);
1337     }
1338 }
1339
1340 void verify_ssh_host_key(char *host, struct RSAKey *key) {
1341     char *keystr, *otherstr, *mungedhost;
1342     int len;
1343     HKEY rkey;
1344
1345     /*
1346      * Format the key into a string.
1347      */
1348     len = rsastr_len(key);
1349     keystr = malloc(len);
1350     if (!keystr)
1351         fatalbox("Out of memory");
1352     rsastr_fmt(keystr, key);
1353
1354     /*
1355      * Now read a saved key in from the registry and see what it
1356      * says.
1357      */
1358     otherstr = malloc(len);
1359     mungedhost = malloc(3*strlen(host)+1);
1360     if (!otherstr || !mungedhost)
1361         fatalbox("Out of memory");
1362
1363     mungestr(host, mungedhost);
1364
1365     if (RegCreateKey(HKEY_CURRENT_USER, PUTTY_REG_POS "\\SshHostKeys",
1366                      &rkey) != ERROR_SUCCESS) {
1367         if (MessageBox(NULL, "PuTTY was unable to open the host key cache\n"
1368                        "in the registry. There is thus no way to tell\n"
1369                        "if the remote host is what you think it is.\n"
1370                        "Connect anyway?", "PuTTY Problem",
1371                        MB_ICONWARNING | MB_YESNO) == IDNO)
1372             exit(0);
1373     } else {
1374         DWORD readlen = len;
1375         DWORD type;
1376         int ret;
1377
1378         ret = RegQueryValueEx(rkey, mungedhost, NULL,
1379                               &type, otherstr, &readlen);
1380
1381         if (ret == ERROR_MORE_DATA ||
1382             (ret == ERROR_SUCCESS && type == REG_SZ &&
1383              strcmp(otherstr, keystr))) {
1384             if (MessageBox(NULL,
1385                            "This host's host key is different from the\n"
1386                            "one cached in the registry! Someone may be\n"
1387                            "impersonating this host for malicious reasons;\n"
1388                            "alternatively, the host key may have changed\n"
1389                            "due to sloppy system administration.\n"
1390                            "Replace key in registry and connect?",
1391                            "PuTTY: Security Warning",
1392                            MB_ICONWARNING | MB_YESNO) == IDNO)
1393                 exit(0);
1394             RegSetValueEx(rkey, mungedhost, 0, REG_SZ, keystr,
1395                           strlen(keystr)+1);
1396         } else if (ret != ERROR_SUCCESS || type != REG_SZ) {
1397             if (MessageBox(NULL,
1398                            "This host's host key is not cached in the\n"
1399                            "registry. Do you want to add it to the cache\n"
1400                            "and carry on connecting?",
1401                            "PuTTY: New Host",
1402                            MB_ICONWARNING | MB_YESNO) == IDNO)
1403                 exit(0);
1404             RegSetValueEx(rkey, mungedhost, 0, REG_SZ, keystr,
1405                           strlen(keystr)+1);
1406         }
1407
1408         RegCloseKey(rkey);
1409     }
1410 }