13 #define MAIN_NPANELS 7
14 #define RECONF_NPANELS 4
16 static const char *const puttystr = PUTTY_REG_POS "\\Sessions";
18 static void get_sesslist(int allocate);
20 static char **negots = NULL;
21 static int nnegots = 0, negsize = 0;
22 static HWND logbox = NULL, abtbox = NULL;
24 static char hex[16] = "0123456789ABCDEF";
26 static void mungestr(char *in, char *out) {
30 if (*in == ' ' || *in == '\\' || *in == '*' || *in == '?' ||
31 *in == '%' || *in < ' ' || *in > '~' || (*in == '.' && !candot)) {
33 *out++ = hex[((unsigned char)*in) >> 4];
34 *out++ = hex[((unsigned char)*in) & 15];
44 static void unmungestr(char *in, char *out) {
48 if (*in == '%' && in[1] && in[2]) {
51 i = in[1] - '0'; i -= (i > 9 ? 7 : 0);
52 j = in[2] - '0'; j -= (j > 9 ? 7 : 0);
63 static void wpps(HKEY key, LPCTSTR name, LPCTSTR value) {
64 RegSetValueEx(key, name, 0, REG_SZ, value, 1+strlen(value));
67 static void wppi(HKEY key, LPCTSTR name, int value) {
68 RegSetValueEx(key, name, 0, REG_DWORD,
69 (CONST BYTE *)&value, sizeof(value));
72 static void gpps(HKEY key, LPCTSTR name, LPCTSTR def,
73 LPTSTR val, int len) {
78 RegQueryValueEx(key, name, 0, &type, val, &size) != ERROR_SUCCESS ||
80 strncpy(val, def, len);
85 static void gppi(HKEY key, LPCTSTR name, int def, int *i) {
86 DWORD type, val, size;
90 RegQueryValueEx(key, name, 0, &type,
91 (BYTE *)&val, &size) != ERROR_SUCCESS ||
92 size != sizeof(val) || type != REG_DWORD)
98 static HINSTANCE hinst;
100 static char **sessions;
101 static int nsessions;
103 static int readytogo;
105 static void save_settings (char *section, int do_host) {
107 HKEY subkey1, sesskey;
110 p = malloc(3*strlen(section)+1);
111 mungestr(section, p);
113 if (RegCreateKey(HKEY_CURRENT_USER, puttystr, &subkey1)!=ERROR_SUCCESS ||
114 RegCreateKey(subkey1, p, &sesskey) != ERROR_SUCCESS) {
119 RegCloseKey(subkey1);
121 wppi (sesskey, "Present", 1);
123 wpps (sesskey, "HostName", cfg.host);
124 wppi (sesskey, "PortNumber", cfg.port);
125 wpps (sesskey, "Protocol",
126 cfg.protocol == PROT_SSH ? "ssh" : "telnet");
128 wppi (sesskey, "CloseOnExit", !!cfg.close_on_exit);
129 wpps (sesskey, "TerminalType", cfg.termtype);
130 wpps (sesskey, "TerminalSpeed", cfg.termspeed);
132 char buf[2*sizeof(cfg.environmt)], *p, *q;
138 if (c == '=' || c == ',' || c == '\\')
148 wpps (sesskey, "Environment", buf);
150 wpps (sesskey, "UserName", cfg.username);
151 wppi (sesskey, "NoPTY", cfg.nopty);
152 wpps (sesskey, "Cipher", cfg.cipher == CIPHER_BLOWFISH ? "blowfish" :
154 wppi (sesskey, "RFCEnviron", cfg.rfc_environ);
155 wppi (sesskey, "BackspaceIsDelete", cfg.bksp_is_delete);
156 wppi (sesskey, "RXVTHomeEnd", cfg.rxvt_homeend);
157 wppi (sesskey, "LinuxFunctionKeys", cfg.linux_funkeys);
158 wppi (sesskey, "ApplicationCursorKeys", cfg.app_cursor);
159 wppi (sesskey, "ApplicationKeypad", cfg.app_keypad);
160 wppi (sesskey, "ScrollbackLines", cfg.savelines);
161 wppi (sesskey, "DECOriginMode", cfg.dec_om);
162 wppi (sesskey, "AutoWrapMode", cfg.wrap_mode);
163 wppi (sesskey, "LFImpliesCR", cfg.lfhascr);
164 wppi (sesskey, "WinNameAlways", cfg.win_name_always);
165 wppi (sesskey, "TermWidth", cfg.width);
166 wppi (sesskey, "TermHeight", cfg.height);
167 wpps (sesskey, "Font", cfg.font);
168 wppi (sesskey, "FontIsBold", cfg.fontisbold);
169 wppi (sesskey, "FontHeight", cfg.fontheight);
170 wppi (sesskey, "FontVTMode", cfg.vtmode);
171 wppi (sesskey, "TryPalette", cfg.try_palette);
172 wppi (sesskey, "BoldAsColour", cfg.bold_colour);
173 for (i=0; i<22; i++) {
174 char buf[20], buf2[30];
175 sprintf(buf, "Colour%d", i);
176 sprintf(buf2, "%d,%d,%d", cfg.colours[i][0],
177 cfg.colours[i][1], cfg.colours[i][2]);
178 wpps (sesskey, buf, buf2);
180 wppi (sesskey, "MouseIsXterm", cfg.mouse_is_xterm);
181 for (i=0; i<256; i+=32) {
182 char buf[20], buf2[256];
184 sprintf(buf, "Wordness%d", i);
186 for (j=i; j<i+32; j++) {
187 sprintf(buf2+strlen(buf2), "%s%d",
188 (*buf2 ? "," : ""), cfg.wordness[j]);
190 wpps (sesskey, buf, buf2);
193 RegCloseKey(sesskey);
196 static void del_session (char *section) {
200 if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS)
203 p = malloc(3*strlen(section)+1);
204 mungestr(section, p);
205 RegDeleteKey(subkey1, p);
208 RegCloseKey(subkey1);
211 static void load_settings (char *section, int do_host) {
213 HKEY subkey1, sesskey;
216 p = malloc(3*strlen(section)+1);
217 mungestr(section, p);
219 if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS) {
222 if (RegOpenKey(subkey1, p, &sesskey) != ERROR_SUCCESS) {
225 RegCloseKey(subkey1);
229 RegCloseKey(subkey1);
233 gpps (sesskey, "HostName", "", cfg.host, sizeof(cfg.host));
234 gppi (sesskey, "PortNumber", 23, &cfg.port);
235 gpps (sesskey, "Protocol", "telnet", prot, 10);
236 if (!strcmp(prot, "ssh"))
237 cfg.protocol = PROT_SSH;
239 cfg.protocol = PROT_TELNET;
244 gppi (sesskey, "CloseOnExit", 1, &cfg.close_on_exit);
245 gpps (sesskey, "TerminalType", "xterm", cfg.termtype,
246 sizeof(cfg.termtype));
247 gpps (sesskey, "TerminalSpeed", "38400,38400", cfg.termspeed,
248 sizeof(cfg.termspeed));
250 char buf[2*sizeof(cfg.environmt)], *p, *q;
251 gpps (sesskey, "Environment", "", buf, sizeof(buf));
255 while (*p && *p != ',') {
268 gpps (sesskey, "UserName", "", cfg.username, sizeof(cfg.username));
269 gppi (sesskey, "NoPTY", 0, &cfg.nopty);
272 gpps (sesskey, "Cipher", "3des", cipher, 10);
273 if (!strcmp(cipher, "blowfish"))
274 cfg.cipher = CIPHER_BLOWFISH;
276 cfg.cipher = CIPHER_3DES;
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"
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]);
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"
323 char buf[20], buf2[256], *p;
325 sprintf(buf, "Wordness%d", i);
326 gpps (sesskey, buf, defaults[i/32], buf2, sizeof(buf2));
328 for (j=i; j<i+32; j++) {
330 while (*p && *p != ',') p++;
331 if (*p == ',') *p++ = '\0';
332 cfg.wordness[j] = atoi(q);
335 RegCloseKey(sesskey);
338 static void MyGetDlgItemInt (HWND hwnd, int id, int *result) {
341 n = GetDlgItemInt (hwnd, id, &ok, FALSE);
346 static int CALLBACK LogProc (HWND hwnd, UINT msg,
347 WPARAM wParam, LPARAM lParam) {
352 for (i=0; i<nnegots; i++)
353 SendDlgItemMessage (hwnd, IDN_LIST, LB_ADDSTRING,
354 0, (LPARAM)negots[i]);
356 /* case WM_CTLCOLORDLG: */
357 /* return (int) GetStockObject (LTGRAY_BRUSH); */
359 switch (LOWORD(wParam)) {
362 DestroyWindow (hwnd);
368 DestroyWindow (hwnd);
374 static int CALLBACK LicenceProc (HWND hwnd, UINT msg,
375 WPARAM wParam, LPARAM lParam) {
380 switch (LOWORD(wParam)) {
383 DestroyWindow (hwnd);
389 DestroyWindow (hwnd);
395 static int CALLBACK AboutProc (HWND hwnd, UINT msg,
396 WPARAM wParam, LPARAM lParam) {
399 SetDlgItemText (hwnd, IDA_VERSION, ver);
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); */
407 switch (LOWORD(wParam)) {
410 DestroyWindow (hwnd);
413 EnableWindow(hwnd, 0);
414 DialogBox (hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
416 EnableWindow(hwnd, 1);
422 DestroyWindow (hwnd);
428 static int GeneralPanelProc (HWND hwnd, UINT msg,
429 WPARAM wParam, LPARAM lParam) {
432 SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
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); */
441 DestroyWindow (hwnd);
447 static int CALLBACK ConnectionProc (HWND hwnd, UINT msg,
448 WPARAM wParam, LPARAM lParam) {
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);
464 * Button release should trigger WM_OK if there was a
465 * previous double click on the session list.
469 SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
472 switch (LOWORD(wParam)) {
473 case IDC0_PROTTELNET:
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);
487 if (HIWORD(wParam) == EN_CHANGE)
488 GetDlgItemText (hwnd, IDC0_HOST, cfg.host,
492 if (HIWORD(wParam) == EN_CHANGE)
493 MyGetDlgItemInt (hwnd, IDC0_PORT, &cfg.port);
496 if (HIWORD(wParam) == BN_CLICKED ||
497 HIWORD(wParam) == BN_DOUBLECLICKED)
498 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC0_CLOSEEXIT);
501 if (HIWORD(wParam) == EN_CHANGE)
502 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
506 if (HIWORD(wParam) == BN_CLICKED ||
507 HIWORD(wParam) == BN_DOUBLECLICKED) {
512 GetDlgItemText (hwnd, IDC0_SESSEDIT, str, sizeof(str)-1);
514 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
520 strcpy (str, sessions[n]);
522 save_settings (str, !!strcmp(str, "Default Settings"));
523 get_sesslist (FALSE);
525 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
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,
536 if (LOWORD(wParam) == IDC0_SESSLOAD &&
537 HIWORD(wParam) != BN_CLICKED &&
538 HIWORD(wParam) != BN_DOUBLECLICKED)
540 if (LOWORD(wParam) == IDC0_SESSLIST &&
541 HIWORD(wParam) != LBN_DBLCLK)
544 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
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 :
557 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
558 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
561 if (LOWORD(wParam) == IDC0_SESSLIST) {
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.
575 if (HIWORD(wParam) == BN_CLICKED ||
576 HIWORD(wParam) == BN_DOUBLECLICKED) {
577 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
579 if (n == LB_ERR || n == 0) {
583 del_session(sessions[n]);
584 get_sesslist (FALSE);
586 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
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,
596 return GeneralPanelProc (hwnd, msg, wParam, lParam);
599 static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
600 WPARAM wParam, LPARAM lParam) {
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);
615 if (HIWORD(wParam) == BN_CLICKED ||
616 HIWORD(wParam) == BN_DOUBLECLICKED)
617 switch (LOWORD(wParam)) {
620 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC1_DEL127);
624 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC1_HOMERXVT);
628 cfg.linux_funkeys = IsDlgButtonChecked (hwnd, IDC1_FUNCLINUX);
632 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC1_KPAPPLIC);
636 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC1_CURAPPLIC);
640 return GeneralPanelProc (hwnd, msg, wParam, lParam);
643 static void fmtfont (char *buf) {
644 sprintf (buf, "Font: %s, ", cfg.font);
646 strcat(buf, "bold, ");
647 if (cfg.fontheight == 0)
648 strcat (buf, "default height");
650 sprintf (buf+strlen(buf), "%d-%s",
651 (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
652 (cfg.fontheight < 0 ? "pixel" : "point"));
655 static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
656 WPARAM wParam, LPARAM lParam) {
659 char fontstatic[256];
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 :
679 switch (LOWORD(wParam)) {
681 if (HIWORD(wParam) == BN_CLICKED ||
682 HIWORD(wParam) == BN_DOUBLECLICKED)
683 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC2_WRAPMODE);
686 if (HIWORD(wParam) == BN_CLICKED ||
687 HIWORD(wParam) == BN_DOUBLECLICKED)
688 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC2_WINNAME);
691 if (HIWORD(wParam) == BN_CLICKED ||
692 HIWORD(wParam) == BN_DOUBLECLICKED)
693 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC2_DECOM);
696 if (HIWORD(wParam) == BN_CLICKED ||
697 HIWORD(wParam) == BN_DOUBLECLICKED)
698 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC2_LFHASCR);
701 if (HIWORD(wParam) == EN_CHANGE)
702 MyGetDlgItemInt (hwnd, IDC2_ROWSEDIT, &cfg.height);
705 if (HIWORD(wParam) == EN_CHANGE)
706 MyGetDlgItemInt (hwnd, IDC2_COLSEDIT, &cfg.width);
709 if (HIWORD(wParam) == EN_CHANGE)
710 MyGetDlgItemInt (hwnd, IDC2_SAVEEDIT, &cfg.savelines);
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';
725 cf.lStructSize = sizeof(cf);
728 cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
729 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
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);
740 case IDC2_VTXWINDOWS:
745 (IsDlgButtonChecked (hwnd, IDC2_VTXWINDOWS) ? VT_XWINDOWS :
746 IsDlgButtonChecked (hwnd, IDC2_VTOEMANSI) ? VT_OEMANSI :
747 IsDlgButtonChecked (hwnd, IDC2_VTOEMONLY) ? VT_OEMONLY :
753 return GeneralPanelProc (hwnd, msg, wParam, lParam);
756 static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
757 WPARAM wParam, LPARAM lParam) {
762 SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
763 SetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed);
764 SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
766 char *p = cfg.environmt;
768 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING, 0,
773 CheckRadioButton (hwnd, IDC3_EMBSD, IDC3_EMRFC,
774 cfg.rfc_environ ? IDC3_EMRFC : IDC3_EMBSD);
777 switch (LOWORD(wParam)) {
779 if (HIWORD(wParam) == EN_CHANGE)
780 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
781 sizeof(cfg.termtype)-1);
784 if (HIWORD(wParam) == EN_CHANGE)
785 GetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed,
786 sizeof(cfg.termspeed)-1);
789 if (HIWORD(wParam) == EN_CHANGE)
790 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
791 sizeof(cfg.username)-1);
795 cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC3_EMRFC);
798 if (HIWORD(wParam) == BN_CLICKED ||
799 HIWORD(wParam) == BN_DOUBLECLICKED) {
800 char str[sizeof(cfg.environmt)];
802 GetDlgItemText (hwnd, IDC3_VAREDIT, str, sizeof(str)-1);
807 p = str + strlen(str);
809 GetDlgItemText (hwnd, IDC3_VALEDIT, p, sizeof(str)-1-(p-str));
819 if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
821 p[strlen(str)+1] = '\0';
822 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING,
824 SetDlgItemText (hwnd, IDC3_VAREDIT, "");
825 SetDlgItemText (hwnd, IDC3_VALEDIT, "");
827 MessageBox(hwnd, "Environment too big", "PuTTY Error",
828 MB_OK | MB_ICONERROR);
833 if (HIWORD(wParam) != BN_CLICKED &&
834 HIWORD(wParam) != BN_DOUBLECLICKED)
836 i = SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_GETCURSEL, 0, 0);
842 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_DELETESTRING,
869 return GeneralPanelProc (hwnd, msg, wParam, lParam);
872 static int CALLBACK SshProc (HWND hwnd, UINT msg,
873 WPARAM wParam, LPARAM lParam) {
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_CIPHERBLOWF,
880 cfg.cipher == CIPHER_BLOWFISH ? IDC3_CIPHERBLOWF :
884 switch (LOWORD(wParam)) {
886 if (HIWORD(wParam) == EN_CHANGE)
887 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
888 sizeof(cfg.termtype)-1);
891 if (HIWORD(wParam) == EN_CHANGE)
892 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
893 sizeof(cfg.username)-1);
896 if (HIWORD(wParam) == BN_CLICKED ||
897 HIWORD(wParam) == BN_DOUBLECLICKED)
898 cfg.nopty = IsDlgButtonChecked (hwnd, IDC3_NOPTY);
900 case IDC3_CIPHER3DES:
901 case IDC3_CIPHERBLOWF:
902 if (HIWORD(wParam) == BN_CLICKED ||
903 HIWORD(wParam) == BN_DOUBLECLICKED) {
904 if (IsDlgButtonChecked (hwnd, IDC3_CIPHER3DES))
905 cfg.cipher = CIPHER_3DES;
906 else if (IsDlgButtonChecked (hwnd, IDC3_CIPHERBLOWF))
907 cfg.cipher = CIPHER_BLOWFISH;
913 return GeneralPanelProc (hwnd, msg, wParam, lParam);
916 static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
917 WPARAM wParam, LPARAM lParam) {
922 CheckRadioButton (hwnd, IDC4_MBWINDOWS, IDC4_MBXTERM,
923 cfg.mouse_is_xterm ? IDC4_MBXTERM : IDC4_MBWINDOWS);
925 static int tabs[4] = {25, 61, 96, 128};
926 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_SETTABSTOPS, 4,
929 for (i=0; i<256; i++) {
931 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
932 (i>=0x21 && i != 0x7F) ? i : ' ',
934 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_ADDSTRING, 0,
939 switch (LOWORD(wParam)) {
942 cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC4_MBXTERM);
948 int n = GetDlgItemInt (hwnd, IDC4_CCEDIT, &ok, FALSE);
953 for (i=0; i<256; i++)
954 if (SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_GETSEL,
958 SendDlgItemMessage (hwnd, IDC4_CCLIST,
959 LB_DELETESTRING, i, 0);
960 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
961 (i>=0x21 && i != 0x7F) ? i : ' ',
963 SendDlgItemMessage (hwnd, IDC4_CCLIST,
973 return GeneralPanelProc (hwnd, msg, wParam, lParam);
976 static int CALLBACK ColourProc (HWND hwnd, UINT msg,
977 WPARAM wParam, LPARAM lParam) {
978 static const char *const colours[] = {
979 "Default Foreground", "Default Bold Foreground",
980 "Default Background", "Default Bold Background",
981 "Cursor Text", "Cursor Colour",
982 "ANSI Black", "ANSI Black Bold",
983 "ANSI Red", "ANSI Red Bold",
984 "ANSI Green", "ANSI Green Bold",
985 "ANSI Yellow", "ANSI Yellow Bold",
986 "ANSI Blue", "ANSI Blue Bold",
987 "ANSI Magenta", "ANSI Magenta Bold",
988 "ANSI Cyan", "ANSI Cyan Bold",
989 "ANSI White", "ANSI White Bold"
991 static const int permanent[] = {
992 TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
993 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
994 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
998 CheckDlgButton (hwnd, IDC5_BOLDCOLOUR, cfg.bold_colour);
999 CheckDlgButton (hwnd, IDC5_PALETTE, cfg.try_palette);
1002 for (i=0; i<22; i++)
1003 if (cfg.bold_colour || permanent[i])
1004 SendDlgItemMessage (hwnd, IDC5_LIST, LB_ADDSTRING, 0,
1005 (LPARAM) colours[i]);
1007 SendDlgItemMessage (hwnd, IDC5_LIST, LB_SETCURSEL, 0, 0);
1008 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[0][0], FALSE);
1009 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[0][1], FALSE);
1010 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[0][2], FALSE);
1013 switch (LOWORD(wParam)) {
1014 case IDC5_BOLDCOLOUR:
1015 if (HIWORD(wParam) == BN_CLICKED ||
1016 HIWORD(wParam) == BN_DOUBLECLICKED) {
1018 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC5_BOLDCOLOUR);
1019 n = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCOUNT, 0, 0);
1020 if (cfg.bold_colour && n!=22) {
1021 for (i=0; i<22; i++)
1023 SendDlgItemMessage (hwnd, IDC5_LIST,
1025 (LPARAM) colours[i]);
1026 } else if (!cfg.bold_colour && n!=12) {
1029 SendDlgItemMessage (hwnd, IDC5_LIST,
1030 LB_DELETESTRING, i, 0);
1035 if (HIWORD(wParam) == BN_CLICKED ||
1036 HIWORD(wParam) == BN_DOUBLECLICKED)
1037 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC5_PALETTE);
1040 if (HIWORD(wParam) == LBN_DBLCLK ||
1041 HIWORD(wParam) == LBN_SELCHANGE) {
1042 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1044 if (!cfg.bold_colour)
1045 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1046 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0], FALSE);
1047 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1], FALSE);
1048 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2], FALSE);
1052 if (HIWORD(wParam) == BN_CLICKED ||
1053 HIWORD(wParam) == BN_DOUBLECLICKED) {
1054 static CHOOSECOLOR cc;
1055 static DWORD custom[16] = {0}; /* zero initialisers */
1056 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1058 if (!cfg.bold_colour)
1059 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1060 cc.lStructSize = sizeof(cc);
1061 cc.hwndOwner = hwnd;
1062 cc.hInstance = hinst;
1063 cc.lpCustColors = custom;
1064 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
1066 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
1067 if (ChooseColor(&cc)) {
1069 (unsigned char) (cc.rgbResult & 0xFF);
1071 (unsigned char) (cc.rgbResult >> 8) & 0xFF;
1073 (unsigned char) (cc.rgbResult >> 16) & 0xFF;
1074 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0],
1076 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1],
1078 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2],
1086 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1089 static DLGPROC panelproc[NPANELS] = {
1090 ConnectionProc, KeyboardProc, TerminalProc,
1091 TelnetProc, SshProc, SelectionProc, ColourProc
1093 static char *panelids[NPANELS] = {
1094 MAKEINTRESOURCE(IDD_PANEL0),
1095 MAKEINTRESOURCE(IDD_PANEL1),
1096 MAKEINTRESOURCE(IDD_PANEL2),
1097 MAKEINTRESOURCE(IDD_PANEL3),
1098 MAKEINTRESOURCE(IDD_PANEL35),
1099 MAKEINTRESOURCE(IDD_PANEL4),
1100 MAKEINTRESOURCE(IDD_PANEL5)
1102 static char *names[NPANELS] = {
1103 "Connection", "Keyboard", "Terminal", "Telnet", "SSH", "Selection", "Colours"
1106 static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6 };
1107 static int reconfp[RECONF_NPANELS] = { 1, 2, 5, 6 };
1109 static int GenericMainDlgProc (HWND hwnd, UINT msg,
1110 WPARAM wParam, LPARAM lParam,
1111 int npanels, int *panelnums, HWND *page) {
1116 { /* centre the window */
1119 hw = GetDesktopWindow();
1120 if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
1121 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
1122 (rs.bottom + rs.top + rd.top - rd.bottom)/2,
1123 rd.right-rd.left, rd.bottom-rd.top, TRUE);
1126 { /* initialise the tab control */
1130 hw = GetDlgItem (hwnd, IDC_TAB);
1131 for (i=0; i<npanels; i++) {
1132 tab.mask = TCIF_TEXT;
1133 tab.pszText = names[panelnums[i]];
1134 TabCtrl_InsertItem (hw, i, &tab);
1136 /* *page = CreateDialogIndirect (hinst, panels[panelnums[0]].temp,
1137 hwnd, panelproc[panelnums[0]]);*/
1138 *page = CreateDialog (hinst, panelids[panelnums[0]],
1139 hwnd, panelproc[panelnums[0]]);
1140 SetWindowLong (*page, GWL_EXSTYLE,
1141 GetWindowLong (*page, GWL_EXSTYLE) |
1142 WS_EX_CONTROLPARENT);
1147 if (LOWORD(wParam) == IDC_TAB &&
1148 ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
1149 int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
1151 DestroyWindow (*page);
1152 /* *page = CreateDialogIndirect (hinst, panels[panelnums[i]].temp,
1153 hwnd, panelproc[panelnums[i]]);*/
1154 *page = CreateDialog (hinst, panelids[panelnums[i]],
1155 hwnd, panelproc[panelnums[i]]);
1156 SetWindowLong (*page, GWL_EXSTYLE,
1157 GetWindowLong (*page, GWL_EXSTYLE) |
1158 WS_EX_CONTROLPARENT);
1159 SetFocus (((LPNMHDR)lParam)->hwndFrom); /* ensure focus stays */
1163 /* case WM_CTLCOLORDLG: */
1164 /* return (int) GetStockObject (LTGRAY_BRUSH); */
1166 switch (LOWORD(wParam)) {
1169 EndDialog (hwnd, 1);
1174 EndDialog (hwnd, 0);
1179 EndDialog (hwnd, 0);
1185 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
1186 WPARAM wParam, LPARAM lParam) {
1191 static HWND page = NULL;
1193 if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
1196 * If the Connection panel is active and the Session List
1197 * box is selected, we treat a press of Open to have an
1198 * implicit press of Load preceding it.
1200 hw = GetDlgItem (hwnd, IDC_TAB);
1201 i = TabCtrl_GetCurSel(hw);
1202 if (panelproc[mainp[i]] == ConnectionProc &&
1203 page && implicit_load_ok) {
1204 SendMessage (page, WM_COMMAND,
1205 MAKELONG(IDC0_SESSLOAD, BN_CLICKED), 0);
1209 if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
1210 EnableWindow(hwnd, 0);
1211 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1212 GetParent(hwnd), AboutProc);
1213 EnableWindow(hwnd, 1);
1215 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1216 MAIN_NPANELS, mainp, &page);
1219 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
1220 WPARAM wParam, LPARAM lParam) {
1222 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1223 RECONF_NPANELS, reconfp, &page);
1226 static void get_sesslist(int allocate) {
1227 static char *buffer;
1228 int buflen, bufsize, i, ret;
1229 char otherbuf[2048];
1234 if (RegCreateKey(HKEY_CURRENT_USER,
1235 puttystr, &subkey1) != ERROR_SUCCESS)
1238 buflen = bufsize = 0;
1242 ret = RegEnumKey(subkey1, i++, otherbuf, sizeof(otherbuf));
1243 if (ret == ERROR_SUCCESS) {
1244 bufsize = buflen + 2048;
1245 buffer = srealloc(buffer, bufsize);
1246 unmungestr(otherbuf, buffer+buflen);
1247 buflen += strlen(buffer+buflen)+1;
1249 } while (ret == ERROR_SUCCESS);
1250 buffer = srealloc(buffer, buflen+1);
1251 buffer[buflen] = '\0';
1254 nsessions = 1; /* "Default Settings" counts as one */
1256 if (strcmp(p, "Default Settings"))
1262 sessions = smalloc(nsessions * sizeof(char *));
1263 sessions[0] = "Default Settings";
1267 if (strcmp(p, "Default Settings"))
1278 int do_config (void) {
1282 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
1283 get_sesslist(FALSE);
1288 int do_reconfig (HWND hwnd) {
1292 backup_cfg = cfg; /* structure copy */
1293 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
1295 cfg = backup_cfg; /* structure copy */
1299 void do_defaults (char *session) {
1301 load_settings (session, TRUE);
1303 load_settings ("Default Settings", FALSE);
1306 void lognegot (char *string) {
1307 if (nnegots >= negsize) {
1309 negots = srealloc (negots, negsize * sizeof(*negots));
1311 negots[nnegots] = smalloc(1+strlen(string));
1312 strcpy (negots[nnegots], string);
1315 SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
1319 void shownegot (HWND hwnd) {
1321 logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
1323 ShowWindow (logbox, SW_SHOWNORMAL);
1327 void showabout (HWND hwnd) {
1329 abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1331 ShowWindow (abtbox, SW_SHOWNORMAL);
1335 void verify_ssh_host_key(char *host, struct RSAKey *key) {
1336 char *keystr, *otherstr, *mungedhost;
1341 * Format the key into a string.
1343 len = rsastr_len(key);
1344 keystr = malloc(len);
1346 fatalbox("Out of memory");
1347 rsastr_fmt(keystr, key);
1350 * Now read a saved key in from the registry and see what it
1353 otherstr = malloc(len);
1354 mungedhost = malloc(3*strlen(host)+1);
1355 if (!otherstr || !mungedhost)
1356 fatalbox("Out of memory");
1358 mungestr(host, mungedhost);
1360 if (RegCreateKey(HKEY_CURRENT_USER, PUTTY_REG_POS "\\SshHostKeys",
1361 &rkey) != ERROR_SUCCESS) {
1362 if (MessageBox(NULL, "PuTTY was unable to open the host key cache\n"
1363 "in the registry. There is thus no way to tell\n"
1364 "if the remote host is what you think it is.\n"
1365 "Connect anyway?", "PuTTY Problem",
1366 MB_ICONWARNING | MB_YESNO) == IDNO)
1369 DWORD readlen = len;
1373 ret = RegQueryValueEx(rkey, mungedhost, NULL,
1374 &type, otherstr, &readlen);
1376 if (ret == ERROR_MORE_DATA ||
1377 (ret == ERROR_SUCCESS && type == REG_SZ &&
1378 strcmp(otherstr, keystr))) {
1379 if (MessageBox(NULL,
1380 "This host's host key is different from the\n"
1381 "one cached in the registry! Someone may be\n"
1382 "impersonating this host for malicious reasons;\n"
1383 "alternatively, the host key may have changed\n"
1384 "due to sloppy system administration.\n"
1385 "Replace key in registry and connect?",
1386 "PuTTY: Security Warning",
1387 MB_ICONWARNING | MB_YESNO) == IDNO)
1389 RegSetValueEx(rkey, mungedhost, 0, REG_SZ, keystr,
1391 } else if (ret != ERROR_SUCCESS || type != REG_SZ) {
1392 if (MessageBox(NULL,
1393 "This host's host key is not cached in the\n"
1394 "registry. Do you want to add it to the cache\n"
1395 "and carry on connecting?",
1397 MB_ICONWARNING | MB_YESNO) == IDNO)
1399 RegSetValueEx(rkey, mungedhost, 0, REG_SZ, keystr,