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 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);
178 wppi (sesskey, "MouseIsXterm", cfg.mouse_is_xterm);
179 for (i=0; i<256; i+=32) {
180 char buf[20], buf2[256];
182 sprintf(buf, "Wordness%d", i);
184 for (j=i; j<i+32; j++) {
185 sprintf(buf2+strlen(buf2), "%s%d",
186 (*buf2 ? "," : ""), cfg.wordness[j]);
188 wpps (sesskey, buf, buf2);
191 RegCloseKey(sesskey);
194 static void del_session (char *section) {
198 if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS)
201 p = malloc(3*strlen(section)+1);
202 mungestr(section, p);
203 RegDeleteKey(subkey1, p);
206 RegCloseKey(subkey1);
209 static void load_settings (char *section, int do_host) {
211 HKEY subkey1, sesskey;
214 p = malloc(3*strlen(section)+1);
215 mungestr(section, p);
217 if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS ||
218 RegOpenKey(subkey1, p, &sesskey) != ERROR_SUCCESS) {
223 RegCloseKey(subkey1);
227 gpps (sesskey, "HostName", "", cfg.host, sizeof(cfg.host));
228 gppi (sesskey, "PortNumber", 23, &cfg.port);
229 gpps (sesskey, "Protocol", "telnet", prot, 10);
230 if (!strcmp(prot, "ssh"))
231 cfg.protocol = PROT_SSH;
233 cfg.protocol = PROT_TELNET;
238 gppi (sesskey, "CloseOnExit", 1, &cfg.close_on_exit);
239 gpps (sesskey, "TerminalType", "xterm", cfg.termtype,
240 sizeof(cfg.termtype));
241 gpps (sesskey, "TerminalSpeed", "38400,38400", cfg.termspeed,
242 sizeof(cfg.termspeed));
244 char buf[2*sizeof(cfg.environmt)], *p, *q;
245 gpps (sesskey, "Environment", "", buf, sizeof(buf));
249 while (*p && *p != ',') {
262 gpps (sesskey, "UserName", "", cfg.username, sizeof(cfg.username));
263 gppi (sesskey, "NoPTY", 0, &cfg.nopty);
264 gppi (sesskey, "RFCEnviron", 0, &cfg.rfc_environ);
265 gppi (sesskey, "BackspaceIsDelete", 1, &cfg.bksp_is_delete);
266 gppi (sesskey, "RXVTHomeEnd", 0, &cfg.rxvt_homeend);
267 gppi (sesskey, "LinuxFunctionKeys", 0, &cfg.linux_funkeys);
268 gppi (sesskey, "ApplicationCursorKeys", 0, &cfg.app_cursor);
269 gppi (sesskey, "ApplicationKeypad", 0, &cfg.app_keypad);
270 gppi (sesskey, "ScrollbackLines", 200, &cfg.savelines);
271 gppi (sesskey, "DECOriginMode", 0, &cfg.dec_om);
272 gppi (sesskey, "AutoWrapMode", 1, &cfg.wrap_mode);
273 gppi (sesskey, "LFImpliesCR", 0, &cfg.lfhascr);
274 gppi (sesskey, "WinNameAlways", 0, &cfg.win_name_always);
275 gppi (sesskey, "TermWidth", 80, &cfg.width);
276 gppi (sesskey, "TermHeight", 24, &cfg.height);
277 gpps (sesskey, "Font", "Courier", cfg.font, sizeof(cfg.font));
278 gppi (sesskey, "FontIsBold", 0, &cfg.fontisbold);
279 gppi (sesskey, "FontHeight", 10, &cfg.fontheight);
280 gppi (sesskey, "FontVTMode", VT_POORMAN, &cfg.vtmode);
281 gppi (sesskey, "TryPalette", 0, &cfg.try_palette);
282 gppi (sesskey, "BoldAsColour", 1, &cfg.bold_colour);
283 for (i=0; i<22; i++) {
284 static char *defaults[] = {
285 "187,187,187", "255,255,255", "0,0,0", "85,85,85", "0,0,0",
286 "0,255,0", "0,0,0", "85,85,85", "187,0,0", "255,85,85",
287 "0,187,0", "85,255,85", "187,187,0", "255,255,85", "0,0,187",
288 "85,85,255", "187,0,187", "255,85,255", "0,187,187",
289 "85,255,255", "187,187,187", "255,255,255"
291 char buf[20], buf2[30];
292 sprintf(buf, "Colour%d", i);
293 gpps (sesskey, buf, defaults[i], buf2, sizeof(buf2));
294 sscanf(buf2, "%d,%d,%d", &cfg.colours[i][0],
295 &cfg.colours[i][1], &cfg.colours[i][2]);
297 gppi (sesskey, "MouseIsXterm", 0, &cfg.mouse_is_xterm);
298 for (i=0; i<256; i+=32) {
299 static char *defaults[] = {
300 "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",
301 "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",
302 "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",
303 "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",
304 "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",
305 "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",
306 "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",
307 "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"
309 char buf[20], buf2[256], *p;
311 sprintf(buf, "Wordness%d", i);
312 gpps (sesskey, buf, defaults[i/32], buf2, sizeof(buf2));
314 for (j=i; j<i+32; j++) {
316 while (*p && *p != ',') p++;
317 if (*p == ',') *p++ = '\0';
318 cfg.wordness[j] = atoi(q);
321 RegCloseKey(sesskey);
324 static void MyGetDlgItemInt (HWND hwnd, int id, int *result) {
327 n = GetDlgItemInt (hwnd, id, &ok, FALSE);
332 static int CALLBACK LogProc (HWND hwnd, UINT msg,
333 WPARAM wParam, LPARAM lParam) {
338 for (i=0; i<nnegots; i++)
339 SendDlgItemMessage (hwnd, IDN_LIST, LB_ADDSTRING,
340 0, (LPARAM)negots[i]);
342 /* case WM_CTLCOLORDLG: */
343 /* return (int) GetStockObject (LTGRAY_BRUSH); */
345 switch (LOWORD(wParam)) {
348 DestroyWindow (hwnd);
354 DestroyWindow (hwnd);
360 static int CALLBACK LicenceProc (HWND hwnd, UINT msg,
361 WPARAM wParam, LPARAM lParam) {
366 switch (LOWORD(wParam)) {
369 DestroyWindow (hwnd);
375 DestroyWindow (hwnd);
381 static int CALLBACK AboutProc (HWND hwnd, UINT msg,
382 WPARAM wParam, LPARAM lParam) {
385 SetDlgItemText (hwnd, IDA_VERSION, ver);
387 /* case WM_CTLCOLORDLG: */
388 /* return (int) GetStockObject (LTGRAY_BRUSH); */
389 /* case WM_CTLCOLORSTATIC: */
390 /* SetBkColor ((HDC)wParam, RGB(192,192,192)); */
391 /* return (int) GetStockObject (LTGRAY_BRUSH); */
393 switch (LOWORD(wParam)) {
396 DestroyWindow (hwnd);
399 EnableWindow(hwnd, 0);
400 DialogBox (hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
402 EnableWindow(hwnd, 1);
408 DestroyWindow (hwnd);
414 static int GeneralPanelProc (HWND hwnd, UINT msg,
415 WPARAM wParam, LPARAM lParam) {
418 SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
420 /* case WM_CTLCOLORDLG: */
421 /* return (int) GetStockObject (LTGRAY_BRUSH); */
422 /* case WM_CTLCOLORSTATIC: */
423 /* case WM_CTLCOLORBTN: */
424 /* SetBkColor ((HDC)wParam, RGB(192,192,192)); */
425 /* return (int) GetStockObject (LTGRAY_BRUSH); */
427 DestroyWindow (hwnd);
433 static int CALLBACK ConnectionProc (HWND hwnd, UINT msg,
434 WPARAM wParam, LPARAM lParam) {
439 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
440 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
441 for (i = 0; i < nsessions; i++)
442 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
443 0, (LPARAM) (sessions[i]));
444 CheckRadioButton (hwnd, IDC0_PROTTELNET, IDC0_PROTSSH,
445 cfg.protocol==PROT_SSH ? IDC0_PROTSSH : IDC0_PROTTELNET);
446 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
450 * Button release should trigger WM_OK if there was a
451 * previous double click on the session list.
455 SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
458 switch (LOWORD(wParam)) {
459 case IDC0_PROTTELNET:
461 if (HIWORD(wParam) == BN_CLICKED ||
462 HIWORD(wParam) == BN_DOUBLECLICKED) {
463 int i = IsDlgButtonChecked (hwnd, IDC0_PROTSSH);
464 cfg.protocol = i ? PROT_SSH : PROT_TELNET;
465 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
466 (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
467 cfg.port = i ? 22 : 23;
468 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
473 if (HIWORD(wParam) == EN_CHANGE)
474 GetDlgItemText (hwnd, IDC0_HOST, cfg.host,
478 if (HIWORD(wParam) == EN_CHANGE)
479 MyGetDlgItemInt (hwnd, IDC0_PORT, &cfg.port);
482 if (HIWORD(wParam) == BN_CLICKED ||
483 HIWORD(wParam) == BN_DOUBLECLICKED)
484 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC0_CLOSEEXIT);
487 if (HIWORD(wParam) == EN_CHANGE)
488 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
492 if (HIWORD(wParam) == BN_CLICKED ||
493 HIWORD(wParam) == BN_DOUBLECLICKED) {
498 GetDlgItemText (hwnd, IDC0_SESSEDIT, str, sizeof(str)-1);
500 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
506 strcpy (str, sessions[n]);
508 save_settings (str, !!strcmp(str, "Default Settings"));
509 get_sesslist (FALSE);
511 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
513 for (i = 0; i < nsessions; i++)
514 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
515 0, (LPARAM) (sessions[i]));
516 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
522 if (LOWORD(wParam) == IDC0_SESSLOAD &&
523 HIWORD(wParam) != BN_CLICKED &&
524 HIWORD(wParam) != BN_DOUBLECLICKED)
526 if (LOWORD(wParam) == IDC0_SESSLIST &&
527 HIWORD(wParam) != LBN_DBLCLK)
530 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
536 load_settings (sessions[n],
537 !!strcmp(sessions[n], "Default Settings"));
538 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
539 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
540 CheckRadioButton (hwnd, IDC0_PROTTELNET, IDC0_PROTSSH,
541 (cfg.protocol==PROT_SSH ? IDC0_PROTSSH :
543 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
544 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
547 if (LOWORD(wParam) == IDC0_SESSLIST) {
549 * A double-click on a saved session should
550 * actually start the session, not just load it.
551 * Unless it's Default Settings or some other
552 * host-less set of saved settings.
561 if (HIWORD(wParam) == BN_CLICKED ||
562 HIWORD(wParam) == BN_DOUBLECLICKED) {
563 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
565 if (n == LB_ERR || n == 0) {
569 del_session(sessions[n]);
570 get_sesslist (FALSE);
572 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
574 for (i = 0; i < nsessions; i++)
575 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
576 0, (LPARAM) (sessions[i]));
577 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
582 return GeneralPanelProc (hwnd, msg, wParam, lParam);
585 static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
586 WPARAM wParam, LPARAM lParam) {
589 CheckRadioButton (hwnd, IDC1_DEL008, IDC1_DEL127,
590 cfg.bksp_is_delete ? IDC1_DEL127 : IDC1_DEL008);
591 CheckRadioButton (hwnd, IDC1_HOMETILDE, IDC1_HOMERXVT,
592 cfg.rxvt_homeend ? IDC1_HOMERXVT : IDC1_HOMETILDE);
593 CheckRadioButton (hwnd, IDC1_FUNCTILDE, IDC1_FUNCLINUX,
594 cfg.linux_funkeys ? IDC1_FUNCLINUX : IDC1_FUNCTILDE);
595 CheckRadioButton (hwnd, IDC1_CURNORMAL, IDC1_CURAPPLIC,
596 cfg.app_cursor ? IDC1_CURAPPLIC : IDC1_CURNORMAL);
597 CheckRadioButton (hwnd, IDC1_KPNORMAL, IDC1_KPAPPLIC,
598 cfg.app_keypad ? IDC1_KPAPPLIC : IDC1_KPNORMAL);
601 if (HIWORD(wParam) == BN_CLICKED ||
602 HIWORD(wParam) == BN_DOUBLECLICKED)
603 switch (LOWORD(wParam)) {
606 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC1_DEL127);
610 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC1_HOMERXVT);
614 cfg.linux_funkeys = IsDlgButtonChecked (hwnd, IDC1_FUNCLINUX);
618 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC1_KPAPPLIC);
622 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC1_CURAPPLIC);
626 return GeneralPanelProc (hwnd, msg, wParam, lParam);
629 static void fmtfont (char *buf) {
630 sprintf (buf, "Font: %s, ", cfg.font);
632 strcat(buf, "bold, ");
633 if (cfg.fontheight == 0)
634 strcat (buf, "default height");
636 sprintf (buf+strlen(buf), "%d-%s",
637 (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
638 (cfg.fontheight < 0 ? "pixel" : "point"));
641 static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
642 WPARAM wParam, LPARAM lParam) {
645 char fontstatic[256];
649 CheckDlgButton (hwnd, IDC2_WRAPMODE, cfg.wrap_mode);
650 CheckDlgButton (hwnd, IDC2_WINNAME, cfg.win_name_always);
651 CheckDlgButton (hwnd, IDC2_DECOM, cfg.dec_om);
652 CheckDlgButton (hwnd, IDC2_LFHASCR, cfg.lfhascr);
653 SetDlgItemInt (hwnd, IDC2_ROWSEDIT, cfg.height, FALSE);
654 SetDlgItemInt (hwnd, IDC2_COLSEDIT, cfg.width, FALSE);
655 SetDlgItemInt (hwnd, IDC2_SAVEEDIT, cfg.savelines, FALSE);
656 fmtfont (fontstatic);
657 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
658 CheckRadioButton (hwnd, IDC2_VTXWINDOWS, IDC2_VTPOORMAN,
659 cfg.vtmode == VT_XWINDOWS ? IDC2_VTXWINDOWS :
660 cfg.vtmode == VT_OEMANSI ? IDC2_VTOEMANSI :
661 cfg.vtmode == VT_OEMONLY ? IDC2_VTOEMONLY :
665 switch (LOWORD(wParam)) {
667 if (HIWORD(wParam) == BN_CLICKED ||
668 HIWORD(wParam) == BN_DOUBLECLICKED)
669 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC2_WRAPMODE);
672 if (HIWORD(wParam) == BN_CLICKED ||
673 HIWORD(wParam) == BN_DOUBLECLICKED)
674 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC2_WINNAME);
677 if (HIWORD(wParam) == BN_CLICKED ||
678 HIWORD(wParam) == BN_DOUBLECLICKED)
679 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC2_DECOM);
682 if (HIWORD(wParam) == BN_CLICKED ||
683 HIWORD(wParam) == BN_DOUBLECLICKED)
684 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC2_LFHASCR);
687 if (HIWORD(wParam) == EN_CHANGE)
688 MyGetDlgItemInt (hwnd, IDC2_ROWSEDIT, &cfg.height);
691 if (HIWORD(wParam) == EN_CHANGE)
692 MyGetDlgItemInt (hwnd, IDC2_COLSEDIT, &cfg.width);
695 if (HIWORD(wParam) == EN_CHANGE)
696 MyGetDlgItemInt (hwnd, IDC2_SAVEEDIT, &cfg.savelines);
698 case IDC2_CHOOSEFONT:
699 lf.lfHeight = cfg.fontheight;
700 lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
701 lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
702 lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
703 lf.lfCharSet = ANSI_CHARSET;
704 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
705 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
706 lf.lfQuality = DEFAULT_QUALITY;
707 lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
708 strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
709 lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
711 cf.lStructSize = sizeof(cf);
714 cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
715 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
717 if (ChooseFont (&cf)) {
718 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
719 cfg.font[sizeof(cfg.font)-1] = '\0';
720 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
721 cfg.fontheight = lf.lfHeight;
722 fmtfont (fontstatic);
723 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
726 case IDC2_VTXWINDOWS:
731 (IsDlgButtonChecked (hwnd, IDC2_VTXWINDOWS) ? VT_XWINDOWS :
732 IsDlgButtonChecked (hwnd, IDC2_VTOEMANSI) ? VT_OEMANSI :
733 IsDlgButtonChecked (hwnd, IDC2_VTOEMONLY) ? VT_OEMONLY :
739 return GeneralPanelProc (hwnd, msg, wParam, lParam);
742 static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
743 WPARAM wParam, LPARAM lParam) {
748 SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
749 SetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed);
750 SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
752 char *p = cfg.environmt;
754 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING, 0,
759 CheckRadioButton (hwnd, IDC3_EMBSD, IDC3_EMRFC,
760 cfg.rfc_environ ? IDC3_EMRFC : IDC3_EMBSD);
763 switch (LOWORD(wParam)) {
765 if (HIWORD(wParam) == EN_CHANGE)
766 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
767 sizeof(cfg.termtype)-1);
770 if (HIWORD(wParam) == EN_CHANGE)
771 GetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed,
772 sizeof(cfg.termspeed)-1);
775 if (HIWORD(wParam) == EN_CHANGE)
776 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
777 sizeof(cfg.username)-1);
781 cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC3_EMRFC);
784 if (HIWORD(wParam) == BN_CLICKED ||
785 HIWORD(wParam) == BN_DOUBLECLICKED) {
786 char str[sizeof(cfg.environmt)];
788 GetDlgItemText (hwnd, IDC3_VAREDIT, str, sizeof(str)-1);
793 p = str + strlen(str);
795 GetDlgItemText (hwnd, IDC3_VALEDIT, p, sizeof(str)-1-(p-str));
805 if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
807 p[strlen(str)+1] = '\0';
808 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING,
810 SetDlgItemText (hwnd, IDC3_VAREDIT, "");
811 SetDlgItemText (hwnd, IDC3_VALEDIT, "");
813 MessageBox(hwnd, "Environment too big", "PuTTY Error",
814 MB_OK | MB_ICONERROR);
819 if (HIWORD(wParam) != BN_CLICKED &&
820 HIWORD(wParam) != BN_DOUBLECLICKED)
822 i = SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_GETCURSEL, 0, 0);
828 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_DELETESTRING,
855 return GeneralPanelProc (hwnd, msg, wParam, lParam);
858 static int CALLBACK SshProc (HWND hwnd, UINT msg,
859 WPARAM wParam, LPARAM lParam) {
862 SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
863 SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
864 CheckDlgButton (hwnd, IDC3_NOPTY, cfg.nopty);
867 switch (LOWORD(wParam)) {
869 if (HIWORD(wParam) == EN_CHANGE)
870 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
871 sizeof(cfg.termtype)-1);
874 if (HIWORD(wParam) == EN_CHANGE)
875 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
876 sizeof(cfg.username)-1);
879 if (HIWORD(wParam) == BN_CLICKED ||
880 HIWORD(wParam) == BN_DOUBLECLICKED)
881 cfg.nopty = IsDlgButtonChecked (hwnd, IDC3_NOPTY);
886 return GeneralPanelProc (hwnd, msg, wParam, lParam);
889 static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
890 WPARAM wParam, LPARAM lParam) {
895 CheckRadioButton (hwnd, IDC4_MBWINDOWS, IDC4_MBXTERM,
896 cfg.mouse_is_xterm ? IDC4_MBXTERM : IDC4_MBWINDOWS);
898 static int tabs[4] = {25, 61, 96, 128};
899 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_SETTABSTOPS, 4,
902 for (i=0; i<256; i++) {
904 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
905 (i>=0x21 && i != 0x7F) ? i : ' ',
907 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_ADDSTRING, 0,
912 switch (LOWORD(wParam)) {
915 cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC4_MBXTERM);
921 int n = GetDlgItemInt (hwnd, IDC4_CCEDIT, &ok, FALSE);
926 for (i=0; i<256; i++)
927 if (SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_GETSEL,
931 SendDlgItemMessage (hwnd, IDC4_CCLIST,
932 LB_DELETESTRING, i, 0);
933 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
934 (i>=0x21 && i != 0x7F) ? i : ' ',
936 SendDlgItemMessage (hwnd, IDC4_CCLIST,
946 return GeneralPanelProc (hwnd, msg, wParam, lParam);
949 static int CALLBACK ColourProc (HWND hwnd, UINT msg,
950 WPARAM wParam, LPARAM lParam) {
951 static const char *const colours[] = {
952 "Default Foreground", "Default Bold Foreground",
953 "Default Background", "Default Bold Background",
954 "Cursor Text", "Cursor Colour",
955 "ANSI Black", "ANSI Black Bold",
956 "ANSI Red", "ANSI Red Bold",
957 "ANSI Green", "ANSI Green Bold",
958 "ANSI Yellow", "ANSI Yellow Bold",
959 "ANSI Blue", "ANSI Blue Bold",
960 "ANSI Magenta", "ANSI Magenta Bold",
961 "ANSI Cyan", "ANSI Cyan Bold",
962 "ANSI White", "ANSI White Bold"
964 static const int permanent[] = {
965 TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
966 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
967 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
971 CheckDlgButton (hwnd, IDC5_BOLDCOLOUR, cfg.bold_colour);
972 CheckDlgButton (hwnd, IDC5_PALETTE, cfg.try_palette);
976 if (cfg.bold_colour || permanent[i])
977 SendDlgItemMessage (hwnd, IDC5_LIST, LB_ADDSTRING, 0,
978 (LPARAM) colours[i]);
980 SendDlgItemMessage (hwnd, IDC5_LIST, LB_SETCURSEL, 0, 0);
981 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[0][0], FALSE);
982 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[0][1], FALSE);
983 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[0][2], FALSE);
986 switch (LOWORD(wParam)) {
987 case IDC5_BOLDCOLOUR:
988 if (HIWORD(wParam) == BN_CLICKED ||
989 HIWORD(wParam) == BN_DOUBLECLICKED) {
991 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC5_BOLDCOLOUR);
992 n = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCOUNT, 0, 0);
993 if (cfg.bold_colour && n!=22) {
996 SendDlgItemMessage (hwnd, IDC5_LIST,
998 (LPARAM) colours[i]);
999 } else if (!cfg.bold_colour && n!=12) {
1002 SendDlgItemMessage (hwnd, IDC5_LIST,
1003 LB_DELETESTRING, i, 0);
1008 if (HIWORD(wParam) == BN_CLICKED ||
1009 HIWORD(wParam) == BN_DOUBLECLICKED)
1010 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC5_PALETTE);
1013 if (HIWORD(wParam) == LBN_DBLCLK ||
1014 HIWORD(wParam) == LBN_SELCHANGE) {
1015 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1017 if (!cfg.bold_colour)
1018 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1019 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0], FALSE);
1020 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1], FALSE);
1021 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2], FALSE);
1025 if (HIWORD(wParam) == BN_CLICKED ||
1026 HIWORD(wParam) == BN_DOUBLECLICKED) {
1027 static CHOOSECOLOR cc;
1028 static DWORD custom[16] = {0}; /* zero initialisers */
1029 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1031 if (!cfg.bold_colour)
1032 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1033 cc.lStructSize = sizeof(cc);
1034 cc.hwndOwner = hwnd;
1035 cc.hInstance = hinst;
1036 cc.lpCustColors = custom;
1037 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
1039 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
1040 if (ChooseColor(&cc)) {
1042 (unsigned char) (cc.rgbResult & 0xFF);
1044 (unsigned char) (cc.rgbResult >> 8) & 0xFF;
1046 (unsigned char) (cc.rgbResult >> 16) & 0xFF;
1047 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0],
1049 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1],
1051 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2],
1059 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1062 static DLGPROC panelproc[NPANELS] = {
1063 ConnectionProc, KeyboardProc, TerminalProc,
1064 TelnetProc, SshProc, SelectionProc, ColourProc
1066 static char *panelids[NPANELS] = {
1067 MAKEINTRESOURCE(IDD_PANEL0),
1068 MAKEINTRESOURCE(IDD_PANEL1),
1069 MAKEINTRESOURCE(IDD_PANEL2),
1070 MAKEINTRESOURCE(IDD_PANEL3),
1071 MAKEINTRESOURCE(IDD_PANEL35),
1072 MAKEINTRESOURCE(IDD_PANEL4),
1073 MAKEINTRESOURCE(IDD_PANEL5)
1075 static char *names[NPANELS] = {
1076 "Connection", "Keyboard", "Terminal", "Telnet", "SSH", "Selection", "Colours"
1079 static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6 };
1080 static int reconfp[RECONF_NPANELS] = { 1, 2, 5, 6 };
1082 static int GenericMainDlgProc (HWND hwnd, UINT msg,
1083 WPARAM wParam, LPARAM lParam,
1084 int npanels, int *panelnums, HWND *page) {
1089 { /* centre the window */
1092 hw = GetDesktopWindow();
1093 if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
1094 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
1095 (rs.bottom + rs.top + rd.top - rd.bottom)/2,
1096 rd.right-rd.left, rd.bottom-rd.top, TRUE);
1099 { /* initialise the tab control */
1103 hw = GetDlgItem (hwnd, IDC_TAB);
1104 for (i=0; i<npanels; i++) {
1105 tab.mask = TCIF_TEXT;
1106 tab.pszText = names[panelnums[i]];
1107 TabCtrl_InsertItem (hw, i, &tab);
1109 /* *page = CreateDialogIndirect (hinst, panels[panelnums[0]].temp,
1110 hwnd, panelproc[panelnums[0]]);*/
1111 *page = CreateDialog (hinst, panelids[panelnums[0]],
1112 hwnd, panelproc[panelnums[0]]);
1113 SetWindowLong (*page, GWL_EXSTYLE,
1114 GetWindowLong (*page, GWL_EXSTYLE) |
1115 WS_EX_CONTROLPARENT);
1120 if (LOWORD(wParam) == IDC_TAB &&
1121 ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
1122 int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
1124 DestroyWindow (*page);
1125 /* *page = CreateDialogIndirect (hinst, panels[panelnums[i]].temp,
1126 hwnd, panelproc[panelnums[i]]);*/
1127 *page = CreateDialog (hinst, panelids[panelnums[i]],
1128 hwnd, panelproc[panelnums[i]]);
1129 SetWindowLong (*page, GWL_EXSTYLE,
1130 GetWindowLong (*page, GWL_EXSTYLE) |
1131 WS_EX_CONTROLPARENT);
1132 SetFocus (((LPNMHDR)lParam)->hwndFrom); /* ensure focus stays */
1136 /* case WM_CTLCOLORDLG: */
1137 /* return (int) GetStockObject (LTGRAY_BRUSH); */
1139 switch (LOWORD(wParam)) {
1142 EndDialog (hwnd, 1);
1147 EndDialog (hwnd, 0);
1152 EndDialog (hwnd, 0);
1158 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
1159 WPARAM wParam, LPARAM lParam) {
1164 static HWND page = NULL;
1166 if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
1169 * If the Connection panel is active and the Session List
1170 * box is selected, we treat a press of Open to have an
1171 * implicit press of Load preceding it.
1173 hw = GetDlgItem (hwnd, IDC_TAB);
1174 i = TabCtrl_GetCurSel(hw);
1175 if (panelproc[mainp[i]] == ConnectionProc &&
1176 page && implicit_load_ok) {
1177 SendMessage (page, WM_COMMAND,
1178 MAKELONG(IDC0_SESSLOAD, BN_CLICKED), 0);
1182 if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
1183 EnableWindow(hwnd, 0);
1184 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1185 GetParent(hwnd), AboutProc);
1186 EnableWindow(hwnd, 1);
1188 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1189 MAIN_NPANELS, mainp, &page);
1192 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
1193 WPARAM wParam, LPARAM lParam) {
1195 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1196 RECONF_NPANELS, reconfp, &page);
1199 static void get_sesslist(int allocate) {
1200 static char *buffer;
1201 int buflen, bufsize, i, ret;
1202 char otherbuf[2048];
1207 if (RegCreateKey(HKEY_CURRENT_USER,
1208 puttystr, &subkey1) != ERROR_SUCCESS)
1211 buflen = bufsize = 0;
1215 ret = RegEnumKey(subkey1, i++, otherbuf, sizeof(otherbuf));
1216 if (ret == ERROR_SUCCESS) {
1217 bufsize = buflen + 2048;
1218 buffer = srealloc(buffer, bufsize);
1219 unmungestr(otherbuf, buffer+buflen);
1220 buflen += strlen(buffer+buflen)+1;
1222 } while (ret == ERROR_SUCCESS);
1223 buffer = srealloc(buffer, buflen+1);
1224 buffer[buflen] = '\0';
1227 nsessions = 1; /* "Default Settings" counts as one */
1229 if (strcmp(p, "Default Settings"))
1235 sessions = smalloc(nsessions * sizeof(char *));
1236 sessions[0] = "Default Settings";
1240 if (strcmp(p, "Default Settings"))
1251 int do_config (void) {
1255 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
1256 get_sesslist(FALSE);
1261 int do_reconfig (HWND hwnd) {
1265 backup_cfg = cfg; /* structure copy */
1266 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
1268 cfg = backup_cfg; /* structure copy */
1272 void do_defaults (char *session) {
1274 load_settings (session, TRUE);
1276 load_settings ("Default Settings", FALSE);
1279 void lognegot (char *string) {
1280 if (nnegots >= negsize) {
1282 negots = srealloc (negots, negsize * sizeof(*negots));
1284 negots[nnegots] = smalloc(1+strlen(string));
1285 strcpy (negots[nnegots], string);
1288 SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
1292 void shownegot (HWND hwnd) {
1294 logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
1296 ShowWindow (logbox, SW_SHOWNORMAL);
1300 void showabout (HWND hwnd) {
1302 abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1304 ShowWindow (abtbox, SW_SHOWNORMAL);
1308 void verify_ssh_host_key(char *host, struct RSAKey *key) {
1309 char *keystr, *otherstr, *mungedhost;
1314 * Format the key into a string.
1316 len = rsastr_len(key);
1317 keystr = malloc(len);
1319 fatalbox("Out of memory");
1320 rsastr_fmt(keystr, key);
1323 * Now read a saved key in from the registry and see what it
1326 otherstr = malloc(len);
1327 mungedhost = malloc(3*strlen(host)+1);
1328 if (!otherstr || !mungedhost)
1329 fatalbox("Out of memory");
1331 mungestr(host, mungedhost);
1333 if (RegCreateKey(HKEY_CURRENT_USER, PUTTY_REG_POS "\\SshHostKeys",
1334 &rkey) != ERROR_SUCCESS) {
1335 if (MessageBox(NULL, "PuTTY was unable to open the host key cache\n"
1336 "in the registry. There is thus no way to tell\n"
1337 "if the remote host is what you think it is.\n"
1338 "Connect anyway?", "PuTTY Problem",
1339 MB_ICONWARNING | MB_YESNO) == IDNO)
1342 DWORD readlen = len;
1346 ret = RegQueryValueEx(rkey, mungedhost, NULL,
1347 &type, otherstr, &readlen);
1349 if (ret == ERROR_MORE_DATA ||
1350 (ret == ERROR_SUCCESS && type == REG_SZ &&
1351 strcmp(otherstr, keystr))) {
1352 if (MessageBox(NULL,
1353 "This host's host key is different from the\n"
1354 "one cached in the registry! Someone may be\n"
1355 "impersonating this host for malicious reasons;\n"
1356 "alternatively, the host key may have changed\n"
1357 "due to sloppy system administration.\n"
1358 "Replace key in registry and connect?",
1359 "PuTTY: Security Warning",
1360 MB_ICONWARNING | MB_YESNO) == IDNO)
1362 RegSetValueEx(rkey, mungedhost, 0, REG_SZ, keystr,
1364 } else if (ret != ERROR_SUCCESS || type != REG_SZ) {
1365 if (MessageBox(NULL,
1366 "This host's host key is not cached in the\n"
1367 "registry. Do you want to add it to the cache\n"
1368 "and carry on connecting?",
1370 MB_ICONWARNING | MB_YESNO) == IDNO)
1372 RegSetValueEx(rkey, mungedhost, 0, REG_SZ, keystr,