Localise control IDs in each dialog procedure, for maintainability
[u/mdw/putty] / windlg.c
CommitLineData
374330e2 1#include <windows.h>
2#include <commctrl.h>
3#include <commdlg.h>
4d331a77 4#ifndef AUTO_WINSOCK
5#ifdef WINSOCK_TWO
6#include <winsock2.h>
7#else
374330e2 8#include <winsock.h>
4d331a77 9#endif
10#endif
374330e2 11#include <stdio.h>
12#include <stdlib.h>
13
374330e2 14#include "ssh.h"
bea1ef5f 15#include "putty.h"
374330e2 16#include "win_res.h"
d5859615 17#include "storage.h"
374330e2 18
9ca5da42 19#define NPANELS 9
20#define MAIN_NPANELS 9
21#define RECONF_NPANELS 6
374330e2 22
c5e9c988 23static char **events = NULL;
24static int nevents = 0, negsize = 0;
25
374330e2 26static HWND logbox = NULL, abtbox = NULL;
27
d1622aed 28static void gpps(void *handle, char *name, char *def, char *val, int len) {
29 if (!read_setting_s(handle, name, val, len)) {
374330e2 30 strncpy(val, def, len);
31 val[len-1] = '\0';
32 }
33}
34
d1622aed 35static void gppi(void *handle, char *name, int def, int *i) {
36 *i = read_setting_i(handle, name, def);
374330e2 37}
38
374330e2 39static HINSTANCE hinst;
40
1cd246bb 41static int readytogo;
42
374330e2 43static void save_settings (char *section, int do_host) {
44 int i;
374330e2 45 char *p;
d1622aed 46 void *sesskey;
374330e2 47
d1622aed 48 sesskey = open_settings_w(section);
49 if (!sesskey)
50 return;
374330e2 51
d1622aed 52 write_setting_i (sesskey, "Present", 1);
374330e2 53 if (do_host) {
d1622aed 54 write_setting_s (sesskey, "HostName", cfg.host);
55 write_setting_i (sesskey, "PortNumber", cfg.port);
89ee5268 56 p = "raw";
a721b9eb 57 for (i = 0; backends[i].name != NULL; i++)
89ee5268 58 if (backends[i].protocol == cfg.protocol) {
59 p = backends[i].name;
60 break;
61 }
d1622aed 62 write_setting_s (sesskey, "Protocol", p);
374330e2 63 }
d1622aed 64 write_setting_i (sesskey, "CloseOnExit", !!cfg.close_on_exit);
65 write_setting_i (sesskey, "WarnOnClose", !!cfg.warn_on_close);
66 write_setting_s (sesskey, "TerminalType", cfg.termtype);
67 write_setting_s (sesskey, "TerminalSpeed", cfg.termspeed);
374330e2 68 {
37508af4 69 char buf[2*sizeof(cfg.environmt)], *p, *q;
374330e2 70 p = buf;
37508af4 71 q = cfg.environmt;
374330e2 72 while (*q) {
73 while (*q) {
74 int c = *q++;
75 if (c == '=' || c == ',' || c == '\\')
76 *p++ = '\\';
77 if (c == '\t')
78 c = '=';
79 *p++ = c;
80 }
81 *p++ = ',';
82 q++;
83 }
84 *p = '\0';
d1622aed 85 write_setting_s (sesskey, "Environment", buf);
374330e2 86 }
d1622aed 87 write_setting_s (sesskey, "UserName", cfg.username);
88 write_setting_i (sesskey, "NoPTY", cfg.nopty);
89 write_setting_i (sesskey, "AgentFwd", cfg.agentfwd);
90 write_setting_s (sesskey, "RemoteCmd", cfg.remote_cmd);
91 write_setting_s (sesskey, "Cipher", cfg.cipher == CIPHER_BLOWFISH ? "blowfish" :
9697bfd2 92 cfg.cipher == CIPHER_DES ? "des" : "3des");
d1622aed 93 write_setting_i (sesskey, "AuthTIS", cfg.try_tis_auth);
94 write_setting_i (sesskey, "SshProt", cfg.sshprot);
95 write_setting_s (sesskey, "PublicKeyFile", cfg.keyfile);
4c73ca1f 96 write_setting_s (sesskey, "RemoteCommand", cfg.remote_cmd);
d1622aed 97 write_setting_i (sesskey, "RFCEnviron", cfg.rfc_environ);
98 write_setting_i (sesskey, "BackspaceIsDelete", cfg.bksp_is_delete);
99 write_setting_i (sesskey, "RXVTHomeEnd", cfg.rxvt_homeend);
100 write_setting_i (sesskey, "LinuxFunctionKeys", cfg.funky_type);
101 write_setting_i (sesskey, "ApplicationCursorKeys", cfg.app_cursor);
102 write_setting_i (sesskey, "ApplicationKeypad", cfg.app_keypad);
103 write_setting_i (sesskey, "NetHackKeypad", cfg.nethack_keypad);
104 write_setting_i (sesskey, "AltF4", cfg.alt_f4);
105 write_setting_i (sesskey, "AltSpace", cfg.alt_space);
106 write_setting_i (sesskey, "LdiscTerm", cfg.ldisc_term);
107 write_setting_i (sesskey, "BlinkCur", cfg.blink_cur);
108 write_setting_i (sesskey, "Beep", cfg.beep);
109 write_setting_i (sesskey, "ScrollbackLines", cfg.savelines);
110 write_setting_i (sesskey, "DECOriginMode", cfg.dec_om);
111 write_setting_i (sesskey, "AutoWrapMode", cfg.wrap_mode);
112 write_setting_i (sesskey, "LFImpliesCR", cfg.lfhascr);
113 write_setting_i (sesskey, "WinNameAlways", cfg.win_name_always);
9ca5da42 114 write_setting_s (sesskey, "WinTitle", cfg.wintitle);
d1622aed 115 write_setting_i (sesskey, "TermWidth", cfg.width);
116 write_setting_i (sesskey, "TermHeight", cfg.height);
117 write_setting_s (sesskey, "Font", cfg.font);
118 write_setting_i (sesskey, "FontIsBold", cfg.fontisbold);
119 write_setting_i (sesskey, "FontCharSet", cfg.fontcharset);
120 write_setting_i (sesskey, "FontHeight", cfg.fontheight);
121 write_setting_i (sesskey, "FontVTMode", cfg.vtmode);
122 write_setting_i (sesskey, "TryPalette", cfg.try_palette);
123 write_setting_i (sesskey, "BoldAsColour", cfg.bold_colour);
374330e2 124 for (i=0; i<22; i++) {
125 char buf[20], buf2[30];
126 sprintf(buf, "Colour%d", i);
127 sprintf(buf2, "%d,%d,%d", cfg.colours[i][0],
128 cfg.colours[i][1], cfg.colours[i][2]);
d1622aed 129 write_setting_s (sesskey, buf, buf2);
374330e2 130 }
d1622aed 131 write_setting_i (sesskey, "MouseIsXterm", cfg.mouse_is_xterm);
374330e2 132 for (i=0; i<256; i+=32) {
133 char buf[20], buf2[256];
134 int j;
135 sprintf(buf, "Wordness%d", i);
136 *buf2 = '\0';
137 for (j=i; j<i+32; j++) {
138 sprintf(buf2+strlen(buf2), "%s%d",
139 (*buf2 ? "," : ""), cfg.wordness[j]);
140 }
d1622aed 141 write_setting_s (sesskey, buf, buf2);
374330e2 142 }
d1622aed 143 write_setting_i (sesskey, "KoiWinXlat", cfg.xlat_enablekoiwin);
144 write_setting_i (sesskey, "88592Xlat", cfg.xlat_88592w1250);
145 write_setting_i (sesskey, "CapsLockCyr", cfg.xlat_capslockcyr);
146 write_setting_i (sesskey, "ScrollBar", cfg.scrollbar);
147 write_setting_i (sesskey, "ScrollOnKey", cfg.scroll_on_key);
148 write_setting_i (sesskey, "LockSize", cfg.locksize);
149 write_setting_i (sesskey, "BCE", cfg.bce);
150 write_setting_i (sesskey, "BlinkText", cfg.blinktext);
151
152 close_settings_w(sesskey);
374330e2 153}
154
155static void load_settings (char *section, int do_host) {
156 int i;
e277c42d 157 char prot[10];
d1622aed 158 void *sesskey;
374330e2 159
d1622aed 160 sesskey = open_settings_r(section);
374330e2 161
e277c42d 162 gpps (sesskey, "HostName", "", cfg.host, sizeof(cfg.host));
163 gppi (sesskey, "PortNumber", default_port, &cfg.port);
89ee5268 164
e277c42d 165 gpps (sesskey, "Protocol", "default", prot, 10);
89ee5268 166 cfg.protocol = default_protocol;
a721b9eb 167 for (i = 0; backends[i].name != NULL; i++)
89ee5268 168 if (!strcmp(prot, backends[i].name)) {
169 cfg.protocol = backends[i].protocol;
170 break;
171 }
e277c42d 172
374330e2 173 gppi (sesskey, "CloseOnExit", 1, &cfg.close_on_exit);
9ef49106 174 gppi (sesskey, "WarnOnClose", 1, &cfg.warn_on_close);
374330e2 175 gpps (sesskey, "TerminalType", "xterm", cfg.termtype,
176 sizeof(cfg.termtype));
177 gpps (sesskey, "TerminalSpeed", "38400,38400", cfg.termspeed,
178 sizeof(cfg.termspeed));
179 {
37508af4 180 char buf[2*sizeof(cfg.environmt)], *p, *q;
374330e2 181 gpps (sesskey, "Environment", "", buf, sizeof(buf));
182 p = buf;
29b611b7 183 q = cfg.environmt;
374330e2 184 while (*p) {
185 while (*p && *p != ',') {
186 int c = *p++;
187 if (c == '=')
188 c = '\t';
189 if (c == '\\')
190 c = *p++;
29b611b7 191 *q++ = c;
374330e2 192 }
193 if (*p == ',') p++;
194 *q++ = '\0';
195 }
196 *q = '\0';
197 }
198 gpps (sesskey, "UserName", "", cfg.username, sizeof(cfg.username));
fef97f43 199 gppi (sesskey, "NoPTY", 0, &cfg.nopty);
979310f1 200 gppi (sesskey, "AgentFwd", 0, &cfg.agentfwd);
6abbf9e3 201 gpps (sesskey, "RemoteCmd", "", cfg.remote_cmd, sizeof(cfg.remote_cmd));
bea1ef5f 202 {
203 char cipher[10];
204 gpps (sesskey, "Cipher", "3des", cipher, 10);
205 if (!strcmp(cipher, "blowfish"))
206 cfg.cipher = CIPHER_BLOWFISH;
9697bfd2 207 else if (!strcmp(cipher, "des"))
208 cfg.cipher = CIPHER_DES;
bea1ef5f 209 else
210 cfg.cipher = CIPHER_3DES;
211 }
adf799dd 212 gppi (sesskey, "SshProt", 1, &cfg.sshprot);
ccbfb941 213 gppi (sesskey, "AuthTIS", 0, &cfg.try_tis_auth);
7cca0d81 214 gpps (sesskey, "PublicKeyFile", "", cfg.keyfile, sizeof(cfg.keyfile));
4c73ca1f 215 gpps (sesskey, "RemoteCommand", "", cfg.remote_cmd,
216 sizeof(cfg.remote_cmd));
374330e2 217 gppi (sesskey, "RFCEnviron", 0, &cfg.rfc_environ);
218 gppi (sesskey, "BackspaceIsDelete", 1, &cfg.bksp_is_delete);
219 gppi (sesskey, "RXVTHomeEnd", 0, &cfg.rxvt_homeend);
c9def1b8 220 gppi (sesskey, "LinuxFunctionKeys", 0, &cfg.funky_type);
374330e2 221 gppi (sesskey, "ApplicationCursorKeys", 0, &cfg.app_cursor);
222 gppi (sesskey, "ApplicationKeypad", 0, &cfg.app_keypad);
c5e9c988 223 gppi (sesskey, "NetHackKeypad", 0, &cfg.nethack_keypad);
224 gppi (sesskey, "AltF4", 1, &cfg.alt_f4);
225 gppi (sesskey, "AltSpace", 0, &cfg.alt_space);
5bc238bb 226 gppi (sesskey, "LdiscTerm", 0, &cfg.ldisc_term);
217dceef 227 gppi (sesskey, "BlinkCur", 0, &cfg.blink_cur);
2a25a1b4 228 gppi (sesskey, "Beep", 1, &cfg.beep);
374330e2 229 gppi (sesskey, "ScrollbackLines", 200, &cfg.savelines);
230 gppi (sesskey, "DECOriginMode", 0, &cfg.dec_om);
231 gppi (sesskey, "AutoWrapMode", 1, &cfg.wrap_mode);
fef97f43 232 gppi (sesskey, "LFImpliesCR", 0, &cfg.lfhascr);
374330e2 233 gppi (sesskey, "WinNameAlways", 0, &cfg.win_name_always);
9ca5da42 234 gpps (sesskey, "WinTitle", "", cfg.wintitle, sizeof(cfg.wintitle));
374330e2 235 gppi (sesskey, "TermWidth", 80, &cfg.width);
236 gppi (sesskey, "TermHeight", 24, &cfg.height);
237 gpps (sesskey, "Font", "Courier", cfg.font, sizeof(cfg.font));
238 gppi (sesskey, "FontIsBold", 0, &cfg.fontisbold);
14963b8f 239 gppi (sesskey, "FontCharSet", ANSI_CHARSET, &cfg.fontcharset);
374330e2 240 gppi (sesskey, "FontHeight", 10, &cfg.fontheight);
2a7bfc6e 241 gppi (sesskey, "FontVTMode", VT_OEMANSI, (int *)&cfg.vtmode);
374330e2 242 gppi (sesskey, "TryPalette", 0, &cfg.try_palette);
243 gppi (sesskey, "BoldAsColour", 1, &cfg.bold_colour);
244 for (i=0; i<22; i++) {
245 static char *defaults[] = {
246 "187,187,187", "255,255,255", "0,0,0", "85,85,85", "0,0,0",
247 "0,255,0", "0,0,0", "85,85,85", "187,0,0", "255,85,85",
248 "0,187,0", "85,255,85", "187,187,0", "255,255,85", "0,0,187",
249 "85,85,255", "187,0,187", "255,85,255", "0,187,187",
250 "85,255,255", "187,187,187", "255,255,255"
251 };
252 char buf[20], buf2[30];
1d470ad2 253 int c0, c1, c2;
374330e2 254 sprintf(buf, "Colour%d", i);
255 gpps (sesskey, buf, defaults[i], buf2, sizeof(buf2));
1d470ad2 256 if(sscanf(buf2, "%d,%d,%d", &c0, &c1, &c2) == 3) {
257 cfg.colours[i][0] = c0;
258 cfg.colours[i][1] = c1;
259 cfg.colours[i][2] = c2;
260 }
374330e2 261 }
262 gppi (sesskey, "MouseIsXterm", 0, &cfg.mouse_is_xterm);
263 for (i=0; i<256; i+=32) {
264 static char *defaults[] = {
265 "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",
266 "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",
267 "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",
268 "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",
269 "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",
270 "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",
271 "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",
272 "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"
273 };
274 char buf[20], buf2[256], *p;
275 int j;
276 sprintf(buf, "Wordness%d", i);
277 gpps (sesskey, buf, defaults[i/32], buf2, sizeof(buf2));
278 p = buf2;
279 for (j=i; j<i+32; j++) {
280 char *q = p;
281 while (*p && *p != ',') p++;
282 if (*p == ',') *p++ = '\0';
283 cfg.wordness[j] = atoi(q);
284 }
285 }
14963b8f 286 gppi (sesskey, "KoiWinXlat", 0, &cfg.xlat_enablekoiwin);
d3d16feb 287 gppi (sesskey, "88592Xlat", 0, &cfg.xlat_88592w1250);
14963b8f 288 gppi (sesskey, "CapsLockCyr", 0, &cfg.xlat_capslockcyr);
c9def1b8 289 gppi (sesskey, "ScrollBar", 1, &cfg.scrollbar);
290 gppi (sesskey, "ScrollOnKey", 0, &cfg.scroll_on_key);
291 gppi (sesskey, "LockSize", 0, &cfg.locksize);
292 gppi (sesskey, "BCE", 0, &cfg.bce);
293 gppi (sesskey, "BlinkText", 0, &cfg.blinktext);
14963b8f 294
d1622aed 295 close_settings_r(sesskey);
374330e2 296}
297
c9def1b8 298static void force_normal(HWND hwnd)
299{
300static int recurse = 0;
301
302 WINDOWPLACEMENT wp;
303
304 if(recurse) return;
305 recurse = 1;
306
307 wp.length = sizeof(wp);
308 if (GetWindowPlacement(hwnd, &wp))
309 {
310 wp.showCmd = SW_SHOWNORMAL;
311 SetWindowPlacement(hwnd, &wp);
312 }
313 recurse = 0;
314}
315
374330e2 316static void MyGetDlgItemInt (HWND hwnd, int id, int *result) {
317 BOOL ok;
318 int n;
319 n = GetDlgItemInt (hwnd, id, &ok, FALSE);
320 if (ok)
321 *result = n;
322}
323
324static int CALLBACK LogProc (HWND hwnd, UINT msg,
325 WPARAM wParam, LPARAM lParam) {
326 int i;
327
328 switch (msg) {
329 case WM_INITDIALOG:
c5e9c988 330 for (i=0; i<nevents; i++)
374330e2 331 SendDlgItemMessage (hwnd, IDN_LIST, LB_ADDSTRING,
c5e9c988 332 0, (LPARAM)events[i]);
374330e2 333 return 1;
374330e2 334 case WM_COMMAND:
335 switch (LOWORD(wParam)) {
336 case IDOK:
337 logbox = NULL;
338 DestroyWindow (hwnd);
339 return 0;
989b10e9 340 case IDN_COPY:
341 if (HIWORD(wParam) == BN_CLICKED ||
342 HIWORD(wParam) == BN_DOUBLECLICKED) {
343 int selcount;
344 int *selitems;
345 selcount = SendDlgItemMessage(hwnd, IDN_LIST,
346 LB_GETSELCOUNT, 0, 0);
347 selitems = malloc(selcount * sizeof(int));
348 if (selitems) {
349 int count = SendDlgItemMessage(hwnd, IDN_LIST,
350 LB_GETSELITEMS,
351 selcount, (LPARAM)selitems);
352 int i;
353 int size;
354 char *clipdata;
355 static unsigned char sel_nl[] = SEL_NL;
356
357 size = 0;
358 for (i = 0; i < count; i++)
359 size += strlen(events[selitems[i]]) + sizeof(sel_nl);
360
361 clipdata = malloc(size);
362 if (clipdata) {
363 char *p = clipdata;
364 for (i = 0; i < count; i++) {
365 char *q = events[selitems[i]];
366 int qlen = strlen(q);
367 memcpy(p, q, qlen);
368 p += qlen;
369 memcpy(p, sel_nl, sizeof(sel_nl));
370 p += sizeof(sel_nl);
371 }
372 write_clip(clipdata, size);
373 term_deselect();
374 free(clipdata);
375 }
376 free(selitems);
377 }
378 }
379 return 0;
374330e2 380 }
381 return 0;
382 case WM_CLOSE:
383 logbox = NULL;
384 DestroyWindow (hwnd);
385 return 0;
386 }
387 return 0;
388}
389
d57835ab 390static int CALLBACK LicenceProc (HWND hwnd, UINT msg,
391 WPARAM wParam, LPARAM lParam) {
392 switch (msg) {
393 case WM_INITDIALOG:
394 return 1;
395 case WM_COMMAND:
396 switch (LOWORD(wParam)) {
397 case IDOK:
97749503 398 EndDialog(hwnd, 1);
d57835ab 399 return 0;
400 }
401 return 0;
402 case WM_CLOSE:
97749503 403 EndDialog(hwnd, 1);
d57835ab 404 return 0;
405 }
406 return 0;
407}
408
374330e2 409static int CALLBACK AboutProc (HWND hwnd, UINT msg,
410 WPARAM wParam, LPARAM lParam) {
411 switch (msg) {
412 case WM_INITDIALOG:
067a15ea 413 SetDlgItemText (hwnd, IDA_VERSION, ver);
374330e2 414 return 1;
374330e2 415 case WM_COMMAND:
416 switch (LOWORD(wParam)) {
417 case IDOK:
418 abtbox = NULL;
419 DestroyWindow (hwnd);
420 return 0;
421 case IDA_LICENCE:
422 EnableWindow(hwnd, 0);
423 DialogBox (hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
d57835ab 424 NULL, LicenceProc);
374330e2 425 EnableWindow(hwnd, 1);
9a70ac47 426 SetActiveWindow(hwnd);
374330e2 427 return 0;
428 }
429 return 0;
430 case WM_CLOSE:
431 abtbox = NULL;
432 DestroyWindow (hwnd);
433 return 0;
434 }
435 return 0;
436}
437
d4dcbf56 438/* ----------------------------------------------------------------------
439 * Routines to self-manage the controls in a dialog box.
440 */
441
442#define GAPBETWEEN 3
443#define GAPWITHIN 1
444#define DLGWIDTH 168
445#define STATICHEIGHT 8
446#define CHECKBOXHEIGHT 8
447#define RADIOHEIGHT 8
448#define EDITHEIGHT 12
449#define COMBOHEIGHT 12
450#define PUSHBTNHEIGHT 14
451
452struct ctlpos {
453 HWND hwnd;
454 LONG units;
455 WPARAM font;
456 int ypos, width;
457};
458
459/* Used on self-constructed dialogs. */
460void ctlposinit(struct ctlpos *cp, HWND hwnd) {
461 RECT r;
462 cp->hwnd = hwnd;
463 cp->units = GetWindowLong(hwnd, GWL_USERDATA);
464 cp->font = GetWindowLong(hwnd, DWL_USER);
465 cp->ypos = GAPBETWEEN;
466 GetClientRect(hwnd, &r);
467 cp->width = (r.right * 4) / (cp->units & 0xFFFF) - 2*GAPBETWEEN;
468}
469
470/* Used on kosher dialogs. */
471void ctlposinit2(struct ctlpos *cp, HWND hwnd) {
472 RECT r;
473 cp->hwnd = hwnd;
474 r.left = r.top = 0;
475 r.right = 4;
476 r.bottom = 8;
477 MapDialogRect(hwnd, &r);
478 cp->units = (r.bottom << 16) | r.right;
479 cp->font = SendMessage(hwnd, WM_GETFONT, 0, 0);
480 cp->ypos = GAPBETWEEN;
481 GetClientRect(hwnd, &r);
482 cp->width = (r.right * 4) / (cp->units & 0xFFFF) - 2*GAPBETWEEN;
483}
484
485void doctl(struct ctlpos *cp, RECT r, char *wclass, int wstyle, int exstyle,
486 char *wtext, int wid) {
487 HWND ctl;
488 /*
489 * Note nonstandard use of RECT. This is deliberate: by
490 * transforming the width and height directly we arrange to
491 * have all supposedly same-sized controls really same-sized.
492 */
493
494 /* MapDialogRect, or its near equivalent. */
495 r.left = (r.left * (cp->units & 0xFFFF)) / 4;
496 r.right = (r.right * (cp->units & 0xFFFF)) / 4;
497 r.top = (r.top * ((cp->units>>16) & 0xFFFF)) / 8;
498 r.bottom = (r.bottom * ((cp->units>>16) & 0xFFFF)) / 8;
499
500 ctl = CreateWindowEx(exstyle, wclass, wtext, wstyle,
501 r.left, r.top, r.right, r.bottom,
502 cp->hwnd, (HMENU)wid, hinst, NULL);
503 SendMessage(ctl, WM_SETFONT, cp->font, MAKELPARAM(TRUE, 0));
504}
505
506/*
507 * Some edit boxes. Each one has a static above it. The percentages
508 * of the horizontal space are provided.
509 */
510void multiedit(struct ctlpos *cp, ...) {
511 RECT r;
512 va_list ap;
513 int percent, xpos;
514
515 percent = xpos = 0;
516 va_start(ap, cp);
517 while (1) {
518 char *text;
519 int staticid, editid, pcwidth;
520 text = va_arg(ap, char *);
521 if (!text)
522 break;
523 staticid = va_arg(ap, int);
524 editid = va_arg(ap, int);
525 pcwidth = va_arg(ap, int);
526
527 r.left = xpos + GAPBETWEEN;
528 percent += pcwidth;
529 xpos = (cp->width + GAPBETWEEN) * percent / 100;
530 r.right = xpos - r.left;
531
532 r.top = cp->ypos; r.bottom = STATICHEIGHT;
533 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0,
534 text, staticid);
535 r.top = cp->ypos + 8 + GAPWITHIN; r.bottom = EDITHEIGHT;
536 doctl(cp, r, "EDIT",
537 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
538 WS_EX_CLIENTEDGE,
539 "", editid);
540 }
541 va_end(ap);
542 cp->ypos += 8+GAPWITHIN+12+GAPBETWEEN;
543}
544
545/*
546 * A set of radio buttons on the same line, with a static above
547 * them. `nacross' dictates how many parts the line is divided into
548 * (you might want this not to equal the number of buttons if you
549 * needed to line up some 2s and some 3s to look good in the same
550 * panel).
551 */
552void radioline(struct ctlpos *cp, char *text, int id, int nacross, ...) {
553 RECT r;
554 va_list ap;
555 int group;
556 int i;
557
558 r.left = GAPBETWEEN; r.top = cp->ypos;
559 r.right = cp->width; r.bottom = STATICHEIGHT;
560 cp->ypos += r.bottom + GAPWITHIN;
561 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
562 va_start(ap, nacross);
563 group = WS_GROUP;
564 i = 0;
565 while (1) {
566 char *btext;
567 int bid;
568 btext = va_arg(ap, char *);
569 if (!btext)
570 break;
571 bid = va_arg(ap, int);
572 r.left = GAPBETWEEN + i * (cp->width+GAPBETWEEN)/nacross;
573 r.right = (i+1) * (cp->width+GAPBETWEEN)/nacross - r.left;
574 r.top = cp->ypos; r.bottom = RADIOHEIGHT;
575 doctl(cp, r, "BUTTON",
576 BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP | group,
577 0,
578 btext, bid);
579 group = 0;
580 i++;
581 }
582 va_end(ap);
583 cp->ypos += r.bottom + GAPBETWEEN;
584}
585
586/*
587 * A set of radio buttons on multiple lines, with a static above
588 * them.
589 */
590void radiobig(struct ctlpos *cp, char *text, int id, ...) {
591 RECT r;
592 va_list ap;
593 int group;
594
595 r.left = GAPBETWEEN; r.top = cp->ypos;
596 r.right = cp->width; r.bottom = STATICHEIGHT;
597 cp->ypos += r.bottom + GAPWITHIN;
598 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
599 va_start(ap, id);
600 group = WS_GROUP;
601 while (1) {
602 char *btext;
603 int bid;
604 btext = va_arg(ap, char *);
605 if (!btext)
606 break;
607 bid = va_arg(ap, int);
608 r.left = GAPBETWEEN; r.top = cp->ypos;
609 r.right = cp->width; r.bottom = STATICHEIGHT;
610 cp->ypos += r.bottom + GAPWITHIN;
611 doctl(cp, r, "BUTTON",
612 BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP | group,
613 0,
614 btext, bid);
615 group = 0;
616 }
617 va_end(ap);
618 cp->ypos += GAPBETWEEN - GAPWITHIN;
619}
620
621/*
622 * A single standalone checkbox.
623 */
624void checkbox(struct ctlpos *cp, char *text, int id) {
625 RECT r;
626
627 r.left = GAPBETWEEN; r.top = cp->ypos;
628 r.right = cp->width; r.bottom = CHECKBOXHEIGHT;
629 cp->ypos += r.bottom + GAPBETWEEN;
630 doctl(cp, r, "BUTTON",
631 BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0,
632 text, id);
633}
634
635/*
636 * A button on the right hand side, with a static to its left.
637 */
638void staticbtn(struct ctlpos *cp, char *stext, int sid, char *btext, int bid) {
639 const int height = (PUSHBTNHEIGHT > STATICHEIGHT ?
640 PUSHBTNHEIGHT : STATICHEIGHT);
641 RECT r;
642 int lwid, rwid, rpos;
643
644 rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
645 lwid = rpos - 2*GAPBETWEEN;
646 rwid = cp->width + GAPBETWEEN - rpos;
647
648 r.left = GAPBETWEEN; r.top = cp->ypos + (height-STATICHEIGHT)/2;
649 r.right = lwid; r.bottom = STATICHEIGHT;
650 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
651
652 r.left = rpos; r.top = cp->ypos + (height-PUSHBTNHEIGHT)/2;
653 r.right = rwid; r.bottom = PUSHBTNHEIGHT;
654 doctl(cp, r, "BUTTON",
655 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
656 0,
657 btext, bid);
658
659 cp->ypos += height + GAPBETWEEN;
660}
661
662/*
663 * An edit control on the right hand side, with a static to its left.
664 */
665void staticedit(struct ctlpos *cp, char *stext, int sid, int eid) {
666 const int height = (EDITHEIGHT > STATICHEIGHT ?
667 EDITHEIGHT : STATICHEIGHT);
668 RECT r;
669 int lwid, rwid, rpos;
670
671 rpos = GAPBETWEEN + (cp->width + GAPBETWEEN) / 2;
672 lwid = rpos - 2*GAPBETWEEN;
673 rwid = cp->width + GAPBETWEEN - rpos;
674
675 r.left = GAPBETWEEN; r.top = cp->ypos + (height-STATICHEIGHT)/2;
676 r.right = lwid; r.bottom = STATICHEIGHT;
677 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
678
679 r.left = rpos; r.top = cp->ypos + (height-EDITHEIGHT)/2;
680 r.right = rwid; r.bottom = EDITHEIGHT;
681 doctl(cp, r, "EDIT",
682 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
683 WS_EX_CLIENTEDGE,
684 "", eid);
685
686 cp->ypos += height + GAPBETWEEN;
687}
688
689/*
690 * A tab-control substitute when a real tab control is unavailable.
691 */
692void ersatztab(struct ctlpos *cp, char *stext, int sid, int lid, int s2id) {
693 const int height = (COMBOHEIGHT > STATICHEIGHT ?
694 COMBOHEIGHT : STATICHEIGHT);
695 RECT r;
696 int bigwid, lwid, rwid, rpos;
697 static const int BIGGAP = 15;
698 static const int MEDGAP = 3;
699
700 bigwid = cp->width + 2*GAPBETWEEN - 2*BIGGAP;
701 cp->ypos += MEDGAP;
702 rpos = BIGGAP + (bigwid + BIGGAP) / 2;
703 lwid = rpos - 2*BIGGAP;
704 rwid = bigwid + BIGGAP - rpos;
705
706 r.left = BIGGAP; r.top = cp->ypos + (height-STATICHEIGHT)/2;
707 r.right = lwid; r.bottom = STATICHEIGHT;
708 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
709
710 r.left = rpos; r.top = cp->ypos + (height-COMBOHEIGHT)/2;
711 r.right = rwid; r.bottom = COMBOHEIGHT*10;
712 doctl(cp, r, "COMBOBOX",
713 WS_CHILD | WS_VISIBLE | WS_TABSTOP |
714 CBS_DROPDOWNLIST | CBS_HASSTRINGS,
715 WS_EX_CLIENTEDGE,
716 "", lid);
717
718 cp->ypos += height + MEDGAP + GAPBETWEEN;
719
720 r.left = GAPBETWEEN; r.top = cp->ypos;
721 r.right = cp->width; r.bottom = 2;
722 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ,
723 0, "", s2id);
724}
725
726/*
727 * A static line, followed by an edit control on the left hand side
728 * and a button on the right.
729 */
730void editbutton(struct ctlpos *cp, char *stext, int sid,
731 int eid, char *btext, int bid) {
732 const int height = (EDITHEIGHT > PUSHBTNHEIGHT ?
733 EDITHEIGHT : PUSHBTNHEIGHT);
734 RECT r;
735 int lwid, rwid, rpos;
736
737 r.left = GAPBETWEEN; r.top = cp->ypos;
738 r.right = cp->width; r.bottom = STATICHEIGHT;
739 cp->ypos += r.bottom + GAPWITHIN;
740 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
741
742 rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
743 lwid = rpos - 2*GAPBETWEEN;
744 rwid = cp->width + GAPBETWEEN - rpos;
745
746 r.left = GAPBETWEEN; r.top = cp->ypos + (height-EDITHEIGHT)/2;
747 r.right = lwid; r.bottom = EDITHEIGHT;
748 doctl(cp, r, "EDIT",
749 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
750 WS_EX_CLIENTEDGE,
751 "", eid);
752
753 r.left = rpos; r.top = cp->ypos + (height-PUSHBTNHEIGHT)/2;
754 r.right = rwid; r.bottom = PUSHBTNHEIGHT;
755 doctl(cp, r, "BUTTON",
756 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
757 0,
758 btext, bid);
759
760 cp->ypos += height + GAPBETWEEN;
761}
762
763/*
764 * Special control which was hard to describe generically: the
765 * session-saver assembly. A static; below that an edit box; below
766 * that a list box. To the right of the list box, a column of
767 * buttons.
768 */
769void sesssaver(struct ctlpos *cp, char *text,
770 int staticid, int editid, int listid, ...) {
771 RECT r;
772 va_list ap;
773 int lwid, rwid, rpos;
774 int y;
775 const int LISTDEFHEIGHT = 66;
776
777 rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
778 lwid = rpos - 2*GAPBETWEEN;
779 rwid = cp->width + GAPBETWEEN - rpos;
780
781 /* The static control. */
782 r.left = GAPBETWEEN; r.top = cp->ypos;
783 r.right = lwid; r.bottom = STATICHEIGHT;
784 cp->ypos += r.bottom + GAPWITHIN;
785 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, staticid);
786
787 /* The edit control. */
788 r.left = GAPBETWEEN; r.top = cp->ypos;
789 r.right = lwid; r.bottom = EDITHEIGHT;
790 cp->ypos += r.bottom + GAPWITHIN;
791 doctl(cp, r, "EDIT",
792 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
793 WS_EX_CLIENTEDGE,
794 "", staticid);
795
796 /*
797 * The buttons (we should hold off on the list box until we
798 * know how big the buttons are).
799 */
800 va_start(ap, listid);
801 y = cp->ypos;
802 while (1) {
803 char *btext = va_arg(ap, char *);
804 int bid;
805 if (!btext) break;
806 bid = va_arg(ap, int);
807 r.left = rpos; r.top = y;
808 r.right = rwid; r.bottom = PUSHBTNHEIGHT;
809 y += r.bottom + GAPWITHIN;
810 doctl(cp, r, "BUTTON",
811 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
812 0,
813 btext, bid);
814 }
815
816 /* Compute list box height. LISTDEFHEIGHT, or height of buttons. */
817 y -= cp->ypos;
818 y -= GAPWITHIN;
819 if (y < LISTDEFHEIGHT) y = LISTDEFHEIGHT;
820 r.left = GAPBETWEEN; r.top = cp->ypos;
821 r.right = lwid; r.bottom = y;
822 cp->ypos += y + GAPBETWEEN;
823 doctl(cp, r, "LISTBOX",
d57a8a6d 824 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
825 LBS_STANDARD | LBS_HASSTRINGS,
d4dcbf56 826 WS_EX_CLIENTEDGE,
827 "", listid);
828}
829
830/*
831 * Another special control: the environment-variable setter. A
832 * static line first; then a pair of edit boxes with associated
833 * statics, and two buttons; then a list box.
834 */
835void envsetter(struct ctlpos *cp, char *stext, int sid,
836 char *e1stext, int e1sid, int e1id,
837 char *e2stext, int e2sid, int e2id,
838 int listid, char *b1text, int b1id, char *b2text, int b2id) {
839 RECT r;
840 const int height = (STATICHEIGHT > EDITHEIGHT && STATICHEIGHT > PUSHBTNHEIGHT ?
841 STATICHEIGHT :
842 EDITHEIGHT > PUSHBTNHEIGHT ?
843 EDITHEIGHT : PUSHBTNHEIGHT);
844 const static int percents[] = { 20, 35, 10, 25 };
845 int i, j, xpos, percent;
846 const int LISTHEIGHT = 42;
847
848 /* The static control. */
849 r.left = GAPBETWEEN; r.top = cp->ypos;
850 r.right = cp->width; r.bottom = STATICHEIGHT;
851 cp->ypos += r.bottom + GAPWITHIN;
852 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
853
854 /* The statics+edits+buttons. */
855 for (j = 0; j < 2; j++) {
856 percent = 10;
857 for (i = 0; i < 4; i++) {
858 xpos = (cp->width + GAPBETWEEN) * percent / 100;
859 r.left = xpos + GAPBETWEEN;
860 percent += percents[i];
861 xpos = (cp->width + GAPBETWEEN) * percent / 100;
862 r.right = xpos - r.left;
863 r.top = cp->ypos;
864 r.bottom = (i==0 ? STATICHEIGHT :
865 i==1 ? EDITHEIGHT :
866 PUSHBTNHEIGHT);
867 r.top += (height-r.bottom)/2;
868 if (i==0) {
869 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0,
870 j==0 ? e1stext : e2stext, j==0 ? e1sid : e2sid);
871 } else if (i==1) {
872 doctl(cp, r, "EDIT",
873 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
874 WS_EX_CLIENTEDGE,
875 "", j==0 ? e1id : e2id);
876 } else if (i==3) {
877 doctl(cp, r, "BUTTON",
878 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
879 0,
880 j==0 ? b1text : b2text, j==0 ? b1id : b2id);
881 }
882 }
883 cp->ypos += height + GAPWITHIN;
884 }
885
886 /* The list box. */
887 r.left = GAPBETWEEN; r.top = cp->ypos;
888 r.right = cp->width; r.bottom = LISTHEIGHT;
889 cp->ypos += r.bottom + GAPBETWEEN;
890 doctl(cp, r, "LISTBOX",
891 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
892 LBS_USETABSTOPS,
893 WS_EX_CLIENTEDGE,
894 "", listid);
895}
896
897/*
898 * Yet another special control: the character-class setter. A
899 * static, then a list, then a line containing a
900 * button-and-static-and-edit.
901 */
902void charclass(struct ctlpos *cp, char *stext, int sid, int listid,
903 char *btext, int bid, int eid, char *s2text, int s2id) {
904 RECT r;
905 const int height = (STATICHEIGHT > EDITHEIGHT && STATICHEIGHT > PUSHBTNHEIGHT ?
906 STATICHEIGHT :
907 EDITHEIGHT > PUSHBTNHEIGHT ?
908 EDITHEIGHT : PUSHBTNHEIGHT);
909 const static int percents[] = { 30, 40, 30 };
910 int i, xpos, percent;
911 const int LISTHEIGHT = 66;
912
913 /* The static control. */
914 r.left = GAPBETWEEN; r.top = cp->ypos;
915 r.right = cp->width; r.bottom = STATICHEIGHT;
916 cp->ypos += r.bottom + GAPWITHIN;
917 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
918
919 /* The list box. */
920 r.left = GAPBETWEEN; r.top = cp->ypos;
921 r.right = cp->width; r.bottom = LISTHEIGHT;
922 cp->ypos += r.bottom + GAPWITHIN;
923 doctl(cp, r, "LISTBOX",
924 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
925 LBS_USETABSTOPS,
926 WS_EX_CLIENTEDGE,
927 "", listid);
928
929 /* The button+static+edit. */
930 percent = xpos = 0;
931 for (i = 0; i < 3; i++) {
932 r.left = xpos + GAPBETWEEN;
933 percent += percents[i];
934 xpos = (cp->width + GAPBETWEEN) * percent / 100;
935 r.right = xpos - r.left;
936 r.top = cp->ypos;
937 r.bottom = (i==0 ? PUSHBTNHEIGHT :
938 i==1 ? STATICHEIGHT :
939 EDITHEIGHT);
940 r.top += (height-r.bottom)/2;
941 if (i==0) {
942 doctl(cp, r, "BUTTON",
943 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
944 0, btext, bid);
945 } else if (i==1) {
946 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_CENTER,
947 0, s2text, s2id);
948 } else if (i==2) {
949 doctl(cp, r, "EDIT",
950 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
951 WS_EX_CLIENTEDGE, "", eid);
952 }
953 }
954 cp->ypos += height + GAPBETWEEN;
955}
956
957/*
958 * A special control (horrors!). The colour editor. A static line;
959 * then on the left, a list box, and on the right, a sequence of
960 * two-part statics followed by a button.
961 */
962void colouredit(struct ctlpos *cp, char *stext, int sid, int listid,
963 char *btext, int bid, ...) {
964 RECT r;
965 int y;
966 va_list ap;
967 int lwid, rwid, rpos;
968 const int LISTHEIGHT = 66;
969
970 /* The static control. */
971 r.left = GAPBETWEEN; r.top = cp->ypos;
972 r.right = cp->width; r.bottom = STATICHEIGHT;
973 cp->ypos += r.bottom + GAPWITHIN;
974 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
975
976 rpos = GAPBETWEEN + 2 * (cp->width + GAPBETWEEN) / 3;
977 lwid = rpos - 2*GAPBETWEEN;
978 rwid = cp->width + GAPBETWEEN - rpos;
979
980 /* The list box. */
981 r.left = GAPBETWEEN; r.top = cp->ypos;
982 r.right = lwid; r.bottom = LISTHEIGHT;
983 doctl(cp, r, "LISTBOX",
984 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
985 LBS_USETABSTOPS,
986 WS_EX_CLIENTEDGE,
987 "", listid);
988
989 /* The statics. */
990 y = cp->ypos;
991 va_start(ap, bid);
992 while (1) {
993 char *ltext;
994 int lid, rid;
995 ltext = va_arg(ap, char *);
996 if (!ltext) break;
997 lid = va_arg(ap, int);
998 rid = va_arg(ap, int);
999 r.top = y; r.bottom = STATICHEIGHT;
1000 y += r.bottom + GAPWITHIN;
1001 r.left = rpos; r.right = rwid/2;
1002 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, ltext, lid);
1003 r.left = rpos + r.right; r.right = rwid - r.right;
1004 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_RIGHT, 0, "", rid);
1005 }
1006 va_end(ap);
1007
1008 /* The button. */
1009 r.top = y + 2*GAPWITHIN; r.bottom = PUSHBTNHEIGHT;
1010 r.left = rpos; r.right = rwid;
1011 doctl(cp, r, "BUTTON",
1012 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
1013 0, btext, bid);
1014
1015 cp->ypos += LISTHEIGHT + GAPBETWEEN;
1016}
1017
374330e2 1018static int GeneralPanelProc (HWND hwnd, UINT msg,
1019 WPARAM wParam, LPARAM lParam) {
1020 switch (msg) {
d4dcbf56 1021 case WM_SETFONT:
1022 {
1023 HFONT hfont = (HFONT)wParam;
1024 HFONT oldfont;
1025 HDC hdc;
1026 TEXTMETRIC tm;
1027 LONG units;
1028
1029 hdc = GetDC(hwnd);
1030 oldfont = SelectObject(hdc, hfont);
1031 GetTextMetrics(hdc, &tm);
1032 units = (tm.tmHeight << 16) | tm.tmAveCharWidth;
1033 SelectObject(hdc, oldfont);
1034 DeleteDC(hdc);
1035 SetWindowLong(hwnd, GWL_USERDATA, units);
1036 SetWindowLong(hwnd, DWL_USER, wParam);
1037 }
1038 return 0;
374330e2 1039 case WM_INITDIALOG:
1040 SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
1041 return 1;
374330e2 1042 case WM_CLOSE:
1043 DestroyWindow (hwnd);
1044 return 1;
1045 }
1046 return 0;
1047}
1048
6584031a 1049static char savedsession[2048];
1050
374330e2 1051static int CALLBACK ConnectionProc (HWND hwnd, UINT msg,
1052 WPARAM wParam, LPARAM lParam) {
1053 int i;
d4dcbf56 1054 struct ctlpos cp;
22b26f24 1055 enum { controlstartvalue = 1000,
1056 IDC_HOSTSTATIC,
1057 IDC_HOST,
1058 IDC_PORTSTATIC,
1059 IDC_PORT,
1060 IDC_PROTSTATIC,
1061 IDC_PROTRAW,
1062 IDC_PROTTELNET,
1063 IDC_PROTSSH,
1064 IDC_SESSSTATIC,
1065 IDC_SESSEDIT,
1066 IDC_SESSLIST,
1067 IDC_SESSLOAD,
1068 IDC_SESSSAVE,
1069 IDC_SESSDEL,
1070 IDC_CLOSEEXIT,
1071 IDC_CLOSEWARN
1072 };
374330e2 1073
1074 switch (msg) {
1075 case WM_INITDIALOG:
d4dcbf56 1076 /* Accelerators used: [aco] dehlnprstwx */
1077 ctlposinit(&cp, hwnd);
1078 multiedit(&cp,
22b26f24 1079 "Host &Name", IDC_HOSTSTATIC, IDC_HOST, 75,
1080 "&Port", IDC_PORTSTATIC, IDC_PORT, 25, NULL);
1081 radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
1082 "&Raw", IDC_PROTRAW,
1083 "&Telnet", IDC_PROTTELNET,
d4dcbf56 1084#ifdef FWHACK
1085 "SS&H/hack",
1086#else
1087 "SS&H",
1088#endif
22b26f24 1089 IDC_PROTSSH, NULL);
d4dcbf56 1090 sesssaver(&cp, "Stor&ed Sessions",
22b26f24 1091 IDC_SESSSTATIC, IDC_SESSEDIT, IDC_SESSLIST,
1092 "&Load", IDC_SESSLOAD,
1093 "&Save", IDC_SESSSAVE,
1094 "&Delete", IDC_SESSDEL, NULL);
1095 checkbox(&cp, "Close Window on E&xit", IDC_CLOSEEXIT);
1096 checkbox(&cp, "&Warn on Close", IDC_CLOSEWARN);
1097
1098 SetDlgItemText (hwnd, IDC_HOST, cfg.host);
1099 SetDlgItemText (hwnd, IDC_SESSEDIT, savedsession);
1100 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
374330e2 1101 for (i = 0; i < nsessions; i++)
22b26f24 1102 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
374330e2 1103 0, (LPARAM) (sessions[i]));
22b26f24 1104 CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH,
1105 cfg.protocol==PROT_SSH ? IDC_PROTSSH :
1106 cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW );
1107 CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit);
1108 CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close);
374330e2 1109 break;
1cd246bb 1110 case WM_LBUTTONUP:
1111 /*
1112 * Button release should trigger WM_OK if there was a
1113 * previous double click on the session list.
1114 */
1115 ReleaseCapture();
1116 if (readytogo)
1117 SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
1118 break;
374330e2 1119 case WM_COMMAND:
1120 switch (LOWORD(wParam)) {
22b26f24 1121 case IDC_PROTTELNET:
1122 case IDC_PROTSSH:
1123 case IDC_PROTRAW:
374330e2 1124 if (HIWORD(wParam) == BN_CLICKED ||
1125 HIWORD(wParam) == BN_DOUBLECLICKED) {
22b26f24 1126 int i = IsDlgButtonChecked (hwnd, IDC_PROTSSH);
1127 int j = IsDlgButtonChecked (hwnd, IDC_PROTTELNET);
5e1a8e27 1128 cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ;
374330e2 1129 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
1130 (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
1131 cfg.port = i ? 22 : 23;
22b26f24 1132 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
374330e2 1133 }
1134 }
1135 break;
22b26f24 1136 case IDC_HOST:
374330e2 1137 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1138 GetDlgItemText (hwnd, IDC_HOST, cfg.host,
374330e2 1139 sizeof(cfg.host)-1);
1140 break;
22b26f24 1141 case IDC_PORT:
374330e2 1142 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1143 MyGetDlgItemInt (hwnd, IDC_PORT, &cfg.port);
374330e2 1144 break;
22b26f24 1145 case IDC_CLOSEEXIT:
374330e2 1146 if (HIWORD(wParam) == BN_CLICKED ||
1147 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1148 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC_CLOSEEXIT);
374330e2 1149 break;
22b26f24 1150 case IDC_CLOSEWARN:
9ef49106 1151 if (HIWORD(wParam) == BN_CLICKED ||
1152 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1153 cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC_CLOSEWARN);
9ef49106 1154 break;
22b26f24 1155 case IDC_SESSEDIT:
6584031a 1156 if (HIWORD(wParam) == EN_CHANGE) {
22b26f24 1157 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
374330e2 1158 (WPARAM) -1, 0);
22b26f24 1159 GetDlgItemText (hwnd, IDC_SESSEDIT,
6584031a 1160 savedsession, sizeof(savedsession)-1);
1161 savedsession[sizeof(savedsession)-1] = '\0';
1162 }
374330e2 1163 break;
22b26f24 1164 case IDC_SESSSAVE:
374330e2 1165 if (HIWORD(wParam) == BN_CLICKED ||
1166 HIWORD(wParam) == BN_DOUBLECLICKED) {
1167 /*
1168 * Save a session
1169 */
1170 char str[2048];
22b26f24 1171 GetDlgItemText (hwnd, IDC_SESSEDIT, str, sizeof(str)-1);
374330e2 1172 if (!*str) {
22b26f24 1173 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
374330e2 1174 LB_GETCURSEL, 0, 0);
1175 if (n == LB_ERR) {
1176 MessageBeep(0);
1177 break;
1178 }
1179 strcpy (str, sessions[n]);
1180 }
1181 save_settings (str, !!strcmp(str, "Default Settings"));
1182 get_sesslist (FALSE);
1183 get_sesslist (TRUE);
22b26f24 1184 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
374330e2 1185 0, 0);
1186 for (i = 0; i < nsessions; i++)
22b26f24 1187 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
374330e2 1188 0, (LPARAM) (sessions[i]));
22b26f24 1189 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
374330e2 1190 (WPARAM) -1, 0);
1191 }
1192 break;
22b26f24 1193 case IDC_SESSLIST:
1194 case IDC_SESSLOAD:
1195 if (LOWORD(wParam) == IDC_SESSLOAD &&
374330e2 1196 HIWORD(wParam) != BN_CLICKED &&
1197 HIWORD(wParam) != BN_DOUBLECLICKED)
1198 break;
22b26f24 1199 if (LOWORD(wParam) == IDC_SESSLIST &&
374330e2 1200 HIWORD(wParam) != LBN_DBLCLK)
1201 break;
1202 {
22b26f24 1203 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
374330e2 1204 LB_GETCURSEL, 0, 0);
1205 if (n == LB_ERR) {
1206 MessageBeep(0);
1207 break;
1208 }
1209 load_settings (sessions[n],
1210 !!strcmp(sessions[n], "Default Settings"));
22b26f24 1211 SetDlgItemText (hwnd, IDC_HOST, cfg.host);
1212 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1213 CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH,
1214 (cfg.protocol==PROT_SSH ? IDC_PROTSSH :
1215 cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW));
1216 CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit);
1217 CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close);
1218 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
374330e2 1219 (WPARAM) -1, 0);
1220 }
22b26f24 1221 if (LOWORD(wParam) == IDC_SESSLIST) {
374330e2 1222 /*
1223 * A double-click on a saved session should
1224 * actually start the session, not just load it.
1225 * Unless it's Default Settings or some other
1226 * host-less set of saved settings.
1227 */
1cd246bb 1228 if (*cfg.host) {
1229 readytogo = TRUE;
1230 SetCapture(hwnd);
1231 }
374330e2 1232 }
1233 break;
22b26f24 1234 case IDC_SESSDEL:
374330e2 1235 if (HIWORD(wParam) == BN_CLICKED ||
1236 HIWORD(wParam) == BN_DOUBLECLICKED) {
22b26f24 1237 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
374330e2 1238 LB_GETCURSEL, 0, 0);
1239 if (n == LB_ERR || n == 0) {
1240 MessageBeep(0);
1241 break;
1242 }
d1622aed 1243 del_settings(sessions[n]);
374330e2 1244 get_sesslist (FALSE);
1245 get_sesslist (TRUE);
22b26f24 1246 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
374330e2 1247 0, 0);
1248 for (i = 0; i < nsessions; i++)
22b26f24 1249 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
374330e2 1250 0, (LPARAM) (sessions[i]));
22b26f24 1251 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
374330e2 1252 (WPARAM) -1, 0);
1253 }
1254 }
1255 }
1256 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1257}
1258
1259static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
d4dcbf56 1260 WPARAM wParam, LPARAM lParam) {
1261 struct ctlpos cp;
22b26f24 1262 enum { controlstartvalue = 1000,
1263 IDC_DELSTATIC,
1264 IDC_DEL008,
1265 IDC_DEL127,
1266 IDC_HOMESTATIC,
1267 IDC_HOMETILDE,
1268 IDC_HOMERXVT,
1269 IDC_FUNCSTATIC,
1270 IDC_FUNCTILDE,
1271 IDC_FUNCLINUX,
1272 IDC_FUNCXTERM,
1273 IDC_KPSTATIC,
1274 IDC_KPNORMAL,
1275 IDC_KPAPPLIC,
1276 IDC_KPNH,
1277 IDC_CURSTATIC,
1278 IDC_CURNORMAL,
1279 IDC_CURAPPLIC,
1280 IDC_ALTF4,
1281 IDC_ALTSPACE,
1282 IDC_LDISCTERM,
1283 IDC_SCROLLKEY
1284 };
1285
374330e2 1286 switch (msg) {
1287 case WM_INITDIALOG:
d4dcbf56 1288 /* Accelerators used: [aco] 4?ehiklmnprsuvxy */
1289 ctlposinit(&cp, hwnd);
22b26f24 1290 radioline(&cp, "Action of Backspace:", IDC_DELSTATIC, 2,
1291 "Control-&H", IDC_DEL008,
1292 "Control-&? (127)", IDC_DEL127, NULL);
1293 radioline(&cp, "Action of Home and End:", IDC_HOMESTATIC, 2,
1294 "&Standard", IDC_HOMETILDE,
1295 "&rxvt", IDC_HOMERXVT, NULL);
1296 radioline(&cp, "Function key and keypad layout:", IDC_FUNCSTATIC, 3,
1297 "&VT400", IDC_FUNCTILDE,
1298 "&Linux", IDC_FUNCLINUX,
1299 "&Xterm R6", IDC_FUNCXTERM, NULL);
1300 radioline(&cp, "Initial state of cursor keys:", IDC_CURSTATIC, 2,
1301 "&Normal", IDC_CURNORMAL,
1302 "A&pplication", IDC_CURAPPLIC, NULL);
1303 radioline(&cp, "Initial state of numeric keypad:", IDC_KPSTATIC, 3,
1304 "Nor&mal", IDC_KPNORMAL,
1305 "Appl&ication", IDC_KPAPPLIC,
1306 "N&etHack", IDC_KPNH, NULL);
1307 checkbox(&cp, "ALT-F&4 is special (closes window)", IDC_ALTF4);
1308 checkbox(&cp, "ALT-Space is special (S&ystem menu)", IDC_ALTSPACE);
1309 checkbox(&cp, "&Use local terminal line discipline", IDC_LDISCTERM);
1310 checkbox(&cp, "Reset scrollback on &keypress", IDC_SCROLLKEY);
1311
1312 CheckRadioButton (hwnd, IDC_DEL008, IDC_DEL127,
1313 cfg.bksp_is_delete ? IDC_DEL127 : IDC_DEL008);
1314 CheckRadioButton (hwnd, IDC_HOMETILDE, IDC_HOMERXVT,
1315 cfg.rxvt_homeend ? IDC_HOMERXVT : IDC_HOMETILDE);
1316 CheckRadioButton (hwnd, IDC_FUNCTILDE, IDC_FUNCXTERM,
c9def1b8 1317 cfg.funky_type ?
22b26f24 1318 (cfg.funky_type==2 ? IDC_FUNCXTERM
1319 : IDC_FUNCLINUX )
1320 : IDC_FUNCTILDE);
1321 CheckRadioButton (hwnd, IDC_CURNORMAL, IDC_CURAPPLIC,
1322 cfg.app_cursor ? IDC_CURAPPLIC : IDC_CURNORMAL);
1323 CheckRadioButton (hwnd, IDC_KPNORMAL, IDC_KPNH,
1324 cfg.nethack_keypad ? IDC_KPNH :
1325 cfg.app_keypad ? IDC_KPAPPLIC : IDC_KPNORMAL);
1326 CheckDlgButton (hwnd, IDC_ALTF4, cfg.alt_f4);
1327 CheckDlgButton (hwnd, IDC_ALTSPACE, cfg.alt_space);
1328 CheckDlgButton (hwnd, IDC_LDISCTERM, cfg.ldisc_term);
1329 CheckDlgButton (hwnd, IDC_SCROLLKEY, cfg.scroll_on_key);
374330e2 1330 break;
1331 case WM_COMMAND:
1332 if (HIWORD(wParam) == BN_CLICKED ||
1333 HIWORD(wParam) == BN_DOUBLECLICKED)
1334 switch (LOWORD(wParam)) {
22b26f24 1335 case IDC_DEL008:
1336 case IDC_DEL127:
1337 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC_DEL127);
374330e2 1338 break;
22b26f24 1339 case IDC_HOMETILDE:
1340 case IDC_HOMERXVT:
1341 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC_HOMERXVT);
374330e2 1342 break;
22b26f24 1343 case IDC_FUNCXTERM:
c9def1b8 1344 cfg.funky_type = 2;
1345 break;
22b26f24 1346 case IDC_FUNCTILDE:
1347 case IDC_FUNCLINUX:
1348 cfg.funky_type = IsDlgButtonChecked (hwnd, IDC_FUNCLINUX);
374330e2 1349 break;
22b26f24 1350 case IDC_KPNORMAL:
1351 case IDC_KPAPPLIC:
1352 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC_KPAPPLIC);
c5e9c988 1353 cfg.nethack_keypad = FALSE;
1354 break;
22b26f24 1355 case IDC_KPNH:
c5e9c988 1356 cfg.app_keypad = FALSE;
1357 cfg.nethack_keypad = TRUE;
374330e2 1358 break;
22b26f24 1359 case IDC_CURNORMAL:
1360 case IDC_CURAPPLIC:
1361 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC_CURAPPLIC);
374330e2 1362 break;
22b26f24 1363 case IDC_ALTF4:
c5e9c988 1364 if (HIWORD(wParam) == BN_CLICKED ||
1365 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1366 cfg.alt_f4 = IsDlgButtonChecked (hwnd, IDC_ALTF4);
c5e9c988 1367 break;
22b26f24 1368 case IDC_ALTSPACE:
c5e9c988 1369 if (HIWORD(wParam) == BN_CLICKED ||
1370 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1371 cfg.alt_space = IsDlgButtonChecked (hwnd, IDC_ALTSPACE);
c5e9c988 1372 break;
22b26f24 1373 case IDC_LDISCTERM:
5bc238bb 1374 if (HIWORD(wParam) == BN_CLICKED ||
1375 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1376 cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC_LDISCTERM);
5bc238bb 1377 break;
22b26f24 1378 case IDC_SCROLLKEY:
217dceef 1379 if (HIWORD(wParam) == BN_CLICKED ||
1380 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1381 cfg.scroll_on_key = IsDlgButtonChecked (hwnd, IDC_SCROLLKEY);
217dceef 1382 break;
374330e2 1383 }
1384 }
1385 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1386}
1387
1388static void fmtfont (char *buf) {
1389 sprintf (buf, "Font: %s, ", cfg.font);
1390 if (cfg.fontisbold)
1391 strcat(buf, "bold, ");
1392 if (cfg.fontheight == 0)
1393 strcat (buf, "default height");
1394 else
1395 sprintf (buf+strlen(buf), "%d-%s",
1396 (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
1397 (cfg.fontheight < 0 ? "pixel" : "point"));
1398}
1399
1400static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
1401 WPARAM wParam, LPARAM lParam) {
d4dcbf56 1402 struct ctlpos cp;
374330e2 1403 CHOOSEFONT cf;
1404 LOGFONT lf;
1405 char fontstatic[256];
22b26f24 1406 enum { controlstartvalue = 1000,
1407 IDC_WRAPMODE,
1408 IDC_DECOM,
1409 IDC_DIMSTATIC,
1410 IDC_ROWSSTATIC,
1411 IDC_ROWSEDIT,
1412 IDC_COLSSTATIC,
1413 IDC_COLSEDIT,
1414 IDC_SAVESTATIC,
1415 IDC_SAVEEDIT,
1416 IDC_FONTSTATIC,
1417 IDC_CHOOSEFONT,
1418 IDC_LFHASCR,
1419 IDC_BEEP,
1420 IDC_BCE,
1421 IDC_BLINKTEXT
1422 };
374330e2 1423
1424 switch (msg) {
1425 case WM_INITDIALOG:
d4dcbf56 1426 /* Accelerators used: [aco] dghlmnprsw */
1427 ctlposinit(&cp, hwnd);
1428 multiedit(&cp,
22b26f24 1429 "&Rows", IDC_ROWSSTATIC, IDC_ROWSEDIT, 33,
1430 "Colu&mns", IDC_COLSSTATIC, IDC_COLSEDIT, 33,
1431 "&Scrollback", IDC_SAVESTATIC, IDC_SAVEEDIT, 33,
d4dcbf56 1432 NULL);
22b26f24 1433 staticbtn(&cp, "", IDC_FONTSTATIC, "C&hange...", IDC_CHOOSEFONT);
1434 checkbox(&cp, "Auto &wrap mode initially on", IDC_WRAPMODE);
1435 checkbox(&cp, "&DEC Origin Mode initially on", IDC_DECOM);
1436 checkbox(&cp, "Implicit CR in every &LF", IDC_LFHASCR);
1437 checkbox(&cp, "Bee&p enabled", IDC_BEEP);
1438 checkbox(&cp, "Use Back&ground colour erase", IDC_BCE);
1439 checkbox(&cp, "Enable bli&nking text", IDC_BLINKTEXT);
1440
1441 CheckDlgButton (hwnd, IDC_WRAPMODE, cfg.wrap_mode);
1442 CheckDlgButton (hwnd, IDC_DECOM, cfg.dec_om);
1443 CheckDlgButton (hwnd, IDC_LFHASCR, cfg.lfhascr);
1444 SetDlgItemInt (hwnd, IDC_ROWSEDIT, cfg.height, FALSE);
1445 SetDlgItemInt (hwnd, IDC_COLSEDIT, cfg.width, FALSE);
1446 SetDlgItemInt (hwnd, IDC_SAVEEDIT, cfg.savelines, FALSE);
374330e2 1447 fmtfont (fontstatic);
22b26f24 1448 SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
1449 CheckDlgButton (hwnd, IDC_BEEP, cfg.beep);
1450 CheckDlgButton (hwnd, IDC_BCE, cfg.bce);
1451 CheckDlgButton (hwnd, IDC_BLINKTEXT, cfg.blinktext);
374330e2 1452 break;
1453 case WM_COMMAND:
1454 switch (LOWORD(wParam)) {
22b26f24 1455 case IDC_WRAPMODE:
374330e2 1456 if (HIWORD(wParam) == BN_CLICKED ||
1457 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1458 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC_WRAPMODE);
374330e2 1459 break;
22b26f24 1460 case IDC_DECOM:
374330e2 1461 if (HIWORD(wParam) == BN_CLICKED ||
1462 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1463 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC_DECOM);
374330e2 1464 break;
22b26f24 1465 case IDC_LFHASCR:
fef97f43 1466 if (HIWORD(wParam) == BN_CLICKED ||
1467 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1468 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC_LFHASCR);
fef97f43 1469 break;
22b26f24 1470 case IDC_ROWSEDIT:
374330e2 1471 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1472 MyGetDlgItemInt (hwnd, IDC_ROWSEDIT, &cfg.height);
374330e2 1473 break;
22b26f24 1474 case IDC_COLSEDIT:
374330e2 1475 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1476 MyGetDlgItemInt (hwnd, IDC_COLSEDIT, &cfg.width);
374330e2 1477 break;
22b26f24 1478 case IDC_SAVEEDIT:
374330e2 1479 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1480 MyGetDlgItemInt (hwnd, IDC_SAVEEDIT, &cfg.savelines);
374330e2 1481 break;
22b26f24 1482 case IDC_CHOOSEFONT:
374330e2 1483 lf.lfHeight = cfg.fontheight;
1484 lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
1485 lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
1486 lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
14963b8f 1487 lf.lfCharSet = cfg.fontcharset;
374330e2 1488 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
1489 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1490 lf.lfQuality = DEFAULT_QUALITY;
1491 lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
1492 strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
1493 lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
1494
1495 cf.lStructSize = sizeof(cf);
1496 cf.hwndOwner = hwnd;
1497 cf.lpLogFont = &lf;
1498 cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
1499 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
1500
1501 if (ChooseFont (&cf)) {
1502 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
1503 cfg.font[sizeof(cfg.font)-1] = '\0';
1504 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
14963b8f 1505 cfg.fontcharset = lf.lfCharSet;
374330e2 1506 cfg.fontheight = lf.lfHeight;
1507 fmtfont (fontstatic);
22b26f24 1508 SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
374330e2 1509 }
1510 break;
22b26f24 1511 case IDC_BEEP:
c9def1b8 1512 if (HIWORD(wParam) == BN_CLICKED ||
1513 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1514 cfg.beep = IsDlgButtonChecked (hwnd, IDC_BEEP);
c9def1b8 1515 break;
22b26f24 1516 case IDC_BLINKTEXT:
c9def1b8 1517 if (HIWORD(wParam) == BN_CLICKED ||
1518 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1519 cfg.blinktext = IsDlgButtonChecked (hwnd, IDC_BLINKTEXT);
c9def1b8 1520 break;
22b26f24 1521 case IDC_BCE:
c9def1b8 1522 if (HIWORD(wParam) == BN_CLICKED ||
1523 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1524 cfg.bce = IsDlgButtonChecked (hwnd, IDC_BCE);
c9def1b8 1525 break;
374330e2 1526 }
1527 break;
1528 }
1529 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1530}
1531
9ca5da42 1532static int CALLBACK WindowProc (HWND hwnd, UINT msg,
1533 WPARAM wParam, LPARAM lParam) {
d4dcbf56 1534 struct ctlpos cp;
22b26f24 1535 enum { controlstartvalue = 1000,
1536 IDC_WINNAME,
1537 IDC_BLINKCUR,
1538 IDC_SCROLLBAR,
1539 IDC_LOCKSIZE,
1540 IDC_WINTITLE,
1541 IDC_WINEDIT
1542 };
1543
9ca5da42 1544 switch (msg) {
1545 case WM_INITDIALOG:
d4dcbf56 1546 /* Accelerators used: [aco] bikty */
1547 ctlposinit(&cp, hwnd);
1548 multiedit(&cp,
22b26f24 1549 "Initial window &title:", IDC_WINTITLE, IDC_WINEDIT, 100,
d4dcbf56 1550 NULL);
22b26f24 1551 checkbox(&cp, "Avoid ever using &icon title", IDC_WINNAME);
1552 checkbox(&cp, "&Blinking cursor", IDC_BLINKCUR);
1553 checkbox(&cp, "Displa&y scrollbar", IDC_SCROLLBAR);
1554 checkbox(&cp, "Loc&k Window size", IDC_LOCKSIZE);
1555
1556 SetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle);
1557 CheckDlgButton (hwnd, IDC_WINNAME, cfg.win_name_always);
1558 CheckDlgButton (hwnd, IDC_BLINKCUR, cfg.blink_cur);
1559 CheckDlgButton (hwnd, IDC_SCROLLBAR, cfg.scrollbar);
1560 CheckDlgButton (hwnd, IDC_LOCKSIZE, cfg.locksize);
9ca5da42 1561 break;
1562 case WM_COMMAND:
1563 switch (LOWORD(wParam)) {
22b26f24 1564 case IDC_WINNAME:
9ca5da42 1565 if (HIWORD(wParam) == BN_CLICKED ||
1566 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1567 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC_WINNAME);
9ca5da42 1568 break;
22b26f24 1569 case IDC_BLINKCUR:
9ca5da42 1570 if (HIWORD(wParam) == BN_CLICKED ||
1571 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1572 cfg.blink_cur = IsDlgButtonChecked (hwnd, IDC_BLINKCUR);
9ca5da42 1573 break;
22b26f24 1574 case IDC_SCROLLBAR:
9ca5da42 1575 if (HIWORD(wParam) == BN_CLICKED ||
1576 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1577 cfg.scrollbar = IsDlgButtonChecked (hwnd, IDC_SCROLLBAR);
9ca5da42 1578 break;
22b26f24 1579 case IDC_LOCKSIZE:
9ca5da42 1580 if (HIWORD(wParam) == BN_CLICKED ||
1581 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1582 cfg.locksize = IsDlgButtonChecked (hwnd, IDC_LOCKSIZE);
9ca5da42 1583 break;
22b26f24 1584 case IDC_WINEDIT:
9ca5da42 1585 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1586 GetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle,
9ca5da42 1587 sizeof(cfg.wintitle)-1);
1588 break;
1589 }
1590 break;
1591 }
1592 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1593}
1594
374330e2 1595static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
1596 WPARAM wParam, LPARAM lParam) {
1597 int i;
d4dcbf56 1598 struct ctlpos cp;
22b26f24 1599 enum { controlstartvalue = 1000,
1600 IDC_TTSTATIC,
1601 IDC_TTEDIT,
1602 IDC_TSSTATIC,
1603 IDC_TSEDIT,
1604 IDC_LOGSTATIC,
1605 IDC_LOGEDIT,
1606 IDC_ENVSTATIC,
1607 IDC_VARSTATIC,
1608 IDC_VAREDIT,
1609 IDC_VALSTATIC,
1610 IDC_VALEDIT,
1611 IDC_ENVLIST,
1612 IDC_ENVADD,
1613 IDC_ENVREMOVE,
1614 IDC_EMSTATIC,
1615 IDC_EMBSD,
1616 IDC_EMRFC
1617 };
374330e2 1618
1619 switch (msg) {
1620 case WM_INITDIALOG:
d4dcbf56 1621 /* Accelerators used: [aco] bdflrstuv */
1622 ctlposinit(&cp, hwnd);
22b26f24 1623 staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT);
1624 staticedit(&cp, "Terminal-&speed string", IDC_TSSTATIC, IDC_TSEDIT);
1625 staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT);
1626 envsetter(&cp, "Environment variables:", IDC_ENVSTATIC,
1627 "&Variable", IDC_VARSTATIC, IDC_VAREDIT,
1628 "Va&lue", IDC_VALSTATIC, IDC_VALEDIT,
1629 IDC_ENVLIST,
1630 "A&dd", IDC_ENVADD, "&Remove", IDC_ENVREMOVE);
1631 radioline(&cp, "Handling of OLD_ENVIRON ambiguity:", IDC_EMSTATIC, 2,
1632 "&BSD (commonplace)", IDC_EMBSD,
1633 "R&FC 1408 (unusual)", IDC_EMRFC, NULL);
1634
1635 SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1636 SetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed);
1637 SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
374330e2 1638 {
37508af4 1639 char *p = cfg.environmt;
374330e2 1640 while (*p) {
22b26f24 1641 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING, 0,
374330e2 1642 (LPARAM) p);
1643 p += strlen(p)+1;
1644 }
1645 }
22b26f24 1646 CheckRadioButton (hwnd, IDC_EMBSD, IDC_EMRFC,
1647 cfg.rfc_environ ? IDC_EMRFC : IDC_EMBSD);
374330e2 1648 break;
1649 case WM_COMMAND:
1650 switch (LOWORD(wParam)) {
22b26f24 1651 case IDC_TTEDIT:
374330e2 1652 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1653 GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype,
374330e2 1654 sizeof(cfg.termtype)-1);
1655 break;
22b26f24 1656 case IDC_TSEDIT:
374330e2 1657 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1658 GetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed,
374330e2 1659 sizeof(cfg.termspeed)-1);
1660 break;
22b26f24 1661 case IDC_LOGEDIT:
374330e2 1662 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1663 GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username,
374330e2 1664 sizeof(cfg.username)-1);
1665 break;
22b26f24 1666 case IDC_EMBSD:
1667 case IDC_EMRFC:
1668 cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC_EMRFC);
374330e2 1669 break;
22b26f24 1670 case IDC_ENVADD:
374330e2 1671 if (HIWORD(wParam) == BN_CLICKED ||
1672 HIWORD(wParam) == BN_DOUBLECLICKED) {
37508af4 1673 char str[sizeof(cfg.environmt)];
374330e2 1674 char *p;
22b26f24 1675 GetDlgItemText (hwnd, IDC_VAREDIT, str, sizeof(str)-1);
374330e2 1676 if (!*str) {
1677 MessageBeep(0);
1678 break;
1679 }
1680 p = str + strlen(str);
1681 *p++ = '\t';
22b26f24 1682 GetDlgItemText (hwnd, IDC_VALEDIT, p, sizeof(str)-1-(p-str));
374330e2 1683 if (!*p) {
1684 MessageBeep(0);
1685 break;
1686 }
37508af4 1687 p = cfg.environmt;
374330e2 1688 while (*p) {
1689 while (*p) p++;
1690 p++;
1691 }
37508af4 1692 if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
374330e2 1693 strcpy (p, str);
1694 p[strlen(str)+1] = '\0';
22b26f24 1695 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING,
374330e2 1696 0, (LPARAM)str);
22b26f24 1697 SetDlgItemText (hwnd, IDC_VAREDIT, "");
1698 SetDlgItemText (hwnd, IDC_VALEDIT, "");
374330e2 1699 } else {
1700 MessageBox(hwnd, "Environment too big", "PuTTY Error",
1701 MB_OK | MB_ICONERROR);
1702 }
1703 }
1704 break;
22b26f24 1705 case IDC_ENVREMOVE:
374330e2 1706 if (HIWORD(wParam) != BN_CLICKED &&
1707 HIWORD(wParam) != BN_DOUBLECLICKED)
1708 break;
22b26f24 1709 i = SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_GETCURSEL, 0, 0);
374330e2 1710 if (i == LB_ERR)
1711 MessageBeep (0);
1712 else {
1713 char *p, *q;
1714
22b26f24 1715 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_DELETESTRING,
374330e2 1716 i, 0);
37508af4 1717 p = cfg.environmt;
374330e2 1718 while (i > 0) {
1719 if (!*p)
1720 goto disaster;
1721 while (*p) p++;
1722 p++;
1723 i--;
1724 }
1725 q = p;
1726 if (!*p)
1727 goto disaster;
1728 while (*p) p++;
1729 p++;
1730 while (*p) {
1731 while (*p)
1732 *q++ = *p++;
1733 *q++ = *p++;
1734 }
1735 *q = '\0';
1736 disaster:;
1737 }
1738 break;
1739 }
1740 break;
1741 }
1742 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1743}
1744
1745static int CALLBACK SshProc (HWND hwnd, UINT msg,
1746 WPARAM wParam, LPARAM lParam) {
d4dcbf56 1747 struct ctlpos cp;
7cca0d81 1748 OPENFILENAME of;
1749 char filename[sizeof(cfg.keyfile)];
22b26f24 1750 enum { controlstartvalue = 1000,
1751 IDC_TTSTATIC,
1752 IDC_TTEDIT,
1753 IDC_LOGSTATIC,
1754 IDC_LOGEDIT,
1755 IDC_NOPTY,
1756 IDC_CIPHERSTATIC,
1757 IDC_CIPHER3DES,
1758 IDC_CIPHERBLOWF,
1759 IDC_CIPHERDES,
1760 IDC_AUTHTIS,
1761 IDC_PKSTATIC,
1762 IDC_PKEDIT,
1763 IDC_PKBUTTON,
1764 IDC_SSHPROTSTATIC,
1765 IDC_SSHPROT1,
1766 IDC_SSHPROT2,
1767 IDC_AGENTFWD,
1768 IDC_CMDSTATIC,
1769 IDC_CMDEDIT
1770 };
7cca0d81 1771
374330e2 1772 switch (msg) {
1773 case WM_INITDIALOG:
d4dcbf56 1774 /* Accelerators used: [aco] 123abdkmprtuw */
1775 ctlposinit(&cp, hwnd);
22b26f24 1776 staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT);
1777 staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT);
d4dcbf56 1778 multiedit(&cp,
22b26f24 1779 "&Remote command:", IDC_CMDSTATIC, IDC_CMDEDIT, 100,
d4dcbf56 1780 NULL);
22b26f24 1781 checkbox(&cp, "Don't allocate a &pseudo-terminal", IDC_NOPTY);
d4dcbf56 1782 checkbox(&cp, "Atte&mpt TIS or CryptoCard authentication",
22b26f24 1783 IDC_AUTHTIS);
1784 checkbox(&cp, "Allow &agent forwarding", IDC_AGENTFWD);
d4dcbf56 1785 editbutton(&cp, "Private &key file for authentication:",
22b26f24 1786 IDC_PKSTATIC, IDC_PKEDIT, "Bro&wse...", IDC_PKBUTTON);
d4dcbf56 1787 radioline(&cp, "Preferred SSH protocol version:",
22b26f24 1788 IDC_SSHPROTSTATIC, 2,
1789 "&1", IDC_SSHPROT1, "&2", IDC_SSHPROT2, NULL);
1790 radioline(&cp, "Preferred encryption algorithm:", IDC_CIPHERSTATIC, 3,
1791 "&3DES", IDC_CIPHER3DES,
1792 "&Blowfish", IDC_CIPHERBLOWF,
1793 "&DES", IDC_CIPHERDES, NULL);
1794
1795 SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1796 SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
1797 CheckDlgButton (hwnd, IDC_NOPTY, cfg.nopty);
1798 CheckDlgButton (hwnd, IDC_AGENTFWD, cfg.agentfwd);
1799 CheckRadioButton (hwnd, IDC_CIPHER3DES, IDC_CIPHERDES,
1800 cfg.cipher == CIPHER_BLOWFISH ? IDC_CIPHERBLOWF :
1801 cfg.cipher == CIPHER_DES ? IDC_CIPHERDES :
1802 IDC_CIPHER3DES);
1803 CheckRadioButton (hwnd, IDC_SSHPROT1, IDC_SSHPROT2,
1804 cfg.sshprot == 1 ? IDC_SSHPROT1 : IDC_SSHPROT2);
1805 CheckDlgButton (hwnd, IDC_AUTHTIS, cfg.try_tis_auth);
1806 SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
1807 SetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd);
374330e2 1808 break;
1809 case WM_COMMAND:
1810 switch (LOWORD(wParam)) {
22b26f24 1811 case IDC_TTEDIT:
374330e2 1812 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1813 GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype,
374330e2 1814 sizeof(cfg.termtype)-1);
1815 break;
22b26f24 1816 case IDC_LOGEDIT:
374330e2 1817 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1818 GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username,
374330e2 1819 sizeof(cfg.username)-1);
1820 break;
22b26f24 1821 case IDC_NOPTY:
fef97f43 1822 if (HIWORD(wParam) == BN_CLICKED ||
1823 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1824 cfg.nopty = IsDlgButtonChecked (hwnd, IDC_NOPTY);
fef97f43 1825 break;
22b26f24 1826 case IDC_AGENTFWD:
979310f1 1827 if (HIWORD(wParam) == BN_CLICKED ||
1828 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1829 cfg.agentfwd = IsDlgButtonChecked (hwnd, IDC_AGENTFWD);
979310f1 1830 break;
22b26f24 1831 case IDC_CIPHER3DES:
1832 case IDC_CIPHERBLOWF:
1833 case IDC_CIPHERDES:
bea1ef5f 1834 if (HIWORD(wParam) == BN_CLICKED ||
1835 HIWORD(wParam) == BN_DOUBLECLICKED) {
22b26f24 1836 if (IsDlgButtonChecked (hwnd, IDC_CIPHER3DES))
bea1ef5f 1837 cfg.cipher = CIPHER_3DES;
22b26f24 1838 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERBLOWF))
bea1ef5f 1839 cfg.cipher = CIPHER_BLOWFISH;
22b26f24 1840 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERDES))
9697bfd2 1841 cfg.cipher = CIPHER_DES;
bea1ef5f 1842 }
1843 break;
22b26f24 1844 case IDC_SSHPROT1:
1845 case IDC_SSHPROT2:
adf799dd 1846 if (HIWORD(wParam) == BN_CLICKED ||
1847 HIWORD(wParam) == BN_DOUBLECLICKED) {
22b26f24 1848 if (IsDlgButtonChecked (hwnd, IDC_SSHPROT1))
adf799dd 1849 cfg.sshprot = 1;
22b26f24 1850 else if (IsDlgButtonChecked (hwnd, IDC_SSHPROT2))
adf799dd 1851 cfg.sshprot = 2;
1852 }
1853 break;
22b26f24 1854 case IDC_AUTHTIS:
ccbfb941 1855 if (HIWORD(wParam) == BN_CLICKED ||
1856 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1857 cfg.try_tis_auth = IsDlgButtonChecked (hwnd, IDC_AUTHTIS);
ccbfb941 1858 break;
22b26f24 1859 case IDC_PKEDIT:
7cca0d81 1860 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1861 GetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile,
7cca0d81 1862 sizeof(cfg.keyfile)-1);
1863 break;
22b26f24 1864 case IDC_CMDEDIT:
4c73ca1f 1865 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1866 GetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd,
4c73ca1f 1867 sizeof(cfg.remote_cmd)-1);
1868 break;
22b26f24 1869 case IDC_PKBUTTON:
7cca0d81 1870 /*
1871 * FIXME: this crashes. Find out why.
1872 */
1873 memset(&of, 0, sizeof(of));
1874#ifdef OPENFILENAME_SIZE_VERSION_400
1875 of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
1876#else
1877 of.lStructSize = sizeof(of);
1878#endif
1879 of.hwndOwner = hwnd;
1880 of.lpstrFilter = "All Files\0*\0\0\0";
1881 of.lpstrCustomFilter = NULL;
1882 of.nFilterIndex = 1;
1883 of.lpstrFile = filename; strcpy(filename, cfg.keyfile);
1884 of.nMaxFile = sizeof(filename);
1885 of.lpstrFileTitle = NULL;
1886 of.lpstrInitialDir = NULL;
1887 of.lpstrTitle = "Select Public Key File";
1888 of.Flags = 0;
1889 if (GetOpenFileName(&of)) {
1890 strcpy(cfg.keyfile, filename);
22b26f24 1891 SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
7cca0d81 1892 }
1893 break;
374330e2 1894 }
1895 break;
1896 }
1897 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1898}
1899
1900static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
1901 WPARAM wParam, LPARAM lParam) {
d4dcbf56 1902 struct ctlpos cp;
374330e2 1903 int i;
22b26f24 1904 enum { controlstartvalue = 1000,
1905 IDC_MBSTATIC,
1906 IDC_MBWINDOWS,
1907 IDC_MBXTERM,
1908 IDC_CCSTATIC,
1909 IDC_CCLIST,
1910 IDC_CCSET,
1911 IDC_CCSTATIC2,
1912 IDC_CCEDIT
1913 };
374330e2 1914
1915 switch (msg) {
1916 case WM_INITDIALOG:
d4dcbf56 1917 /* Accelerators used: [aco] stwx */
1918 ctlposinit(&cp, hwnd);
22b26f24 1919 radiobig(&cp, "Action of mouse buttons:", IDC_MBSTATIC,
1920 "&Windows (Right pastes, Middle extends)", IDC_MBWINDOWS,
1921 "&xterm (Right extends, Middle pastes)", IDC_MBXTERM,
d4dcbf56 1922 NULL);
22b26f24 1923 charclass(&cp, "Character classes:", IDC_CCSTATIC, IDC_CCLIST,
1924 "&Set", IDC_CCSET, IDC_CCEDIT,
1925 "&to class", IDC_CCSTATIC2);
d4dcbf56 1926
22b26f24 1927 CheckRadioButton (hwnd, IDC_MBWINDOWS, IDC_MBXTERM,
1928 cfg.mouse_is_xterm ? IDC_MBXTERM : IDC_MBWINDOWS);
374330e2 1929 {
1930 static int tabs[4] = {25, 61, 96, 128};
22b26f24 1931 SendDlgItemMessage (hwnd, IDC_CCLIST, LB_SETTABSTOPS, 4,
374330e2 1932 (LPARAM) tabs);
1933 }
1934 for (i=0; i<256; i++) {
1935 char str[100];
1936 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1937 (i>=0x21 && i != 0x7F) ? i : ' ',
1938 cfg.wordness[i]);
22b26f24 1939 SendDlgItemMessage (hwnd, IDC_CCLIST, LB_ADDSTRING, 0,
374330e2 1940 (LPARAM) str);
1941 }
1942 break;
1943 case WM_COMMAND:
1944 switch (LOWORD(wParam)) {
22b26f24 1945 case IDC_MBWINDOWS:
1946 case IDC_MBXTERM:
1947 cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC_MBXTERM);
374330e2 1948 break;
22b26f24 1949 case IDC_CCSET:
374330e2 1950 {
1951 BOOL ok;
1952 int i;
22b26f24 1953 int n = GetDlgItemInt (hwnd, IDC_CCEDIT, &ok, FALSE);
374330e2 1954
1955 if (!ok)
1956 MessageBeep (0);
1957 else {
1958 for (i=0; i<256; i++)
22b26f24 1959 if (SendDlgItemMessage (hwnd, IDC_CCLIST, LB_GETSEL,
374330e2 1960 i, 0)) {
1961 char str[100];
1962 cfg.wordness[i] = n;
22b26f24 1963 SendDlgItemMessage (hwnd, IDC_CCLIST,
374330e2 1964 LB_DELETESTRING, i, 0);
1965 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1966 (i>=0x21 && i != 0x7F) ? i : ' ',
1967 cfg.wordness[i]);
22b26f24 1968 SendDlgItemMessage (hwnd, IDC_CCLIST,
374330e2 1969 LB_INSERTSTRING, i,
1970 (LPARAM)str);
1971 }
1972 }
1973 }
1974 break;
1975 }
1976 break;
1977 }
1978 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1979}
1980
1981static int CALLBACK ColourProc (HWND hwnd, UINT msg,
1982 WPARAM wParam, LPARAM lParam) {
1983 static const char *const colours[] = {
1984 "Default Foreground", "Default Bold Foreground",
1985 "Default Background", "Default Bold Background",
1986 "Cursor Text", "Cursor Colour",
1987 "ANSI Black", "ANSI Black Bold",
1988 "ANSI Red", "ANSI Red Bold",
1989 "ANSI Green", "ANSI Green Bold",
1990 "ANSI Yellow", "ANSI Yellow Bold",
1991 "ANSI Blue", "ANSI Blue Bold",
1992 "ANSI Magenta", "ANSI Magenta Bold",
1993 "ANSI Cyan", "ANSI Cyan Bold",
1994 "ANSI White", "ANSI White Bold"
1995 };
1996 static const int permanent[] = {
1997 TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
1998 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
1999 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
2000 };
d4dcbf56 2001 struct ctlpos cp;
22b26f24 2002 enum { controlstartvalue = 1000,
2003 IDC_BOLDCOLOUR,
2004 IDC_PALETTE,
2005 IDC_STATIC,
2006 IDC_LIST,
2007 IDC_RSTATIC,
2008 IDC_GSTATIC,
2009 IDC_BSTATIC,
2010 IDC_RVALUE,
2011 IDC_GVALUE,
2012 IDC_BVALUE,
2013 IDC_CHANGE
2014 };
d4dcbf56 2015
374330e2 2016 switch (msg) {
2017 case WM_INITDIALOG:
d4dcbf56 2018 /* Accelerators used: [aco] bmlu */
2019 ctlposinit(&cp, hwnd);
22b26f24 2020 checkbox(&cp, "&Bolded text is a different colour", IDC_BOLDCOLOUR);
2021 checkbox(&cp, "Attempt to use &logical palettes", IDC_PALETTE);
d4dcbf56 2022 colouredit(&cp, "Select a colo&ur and click to modify it:",
22b26f24 2023 IDC_STATIC, IDC_LIST,
2024 "&Modify...", IDC_CHANGE,
2025 "Red:", IDC_RSTATIC, IDC_RVALUE,
2026 "Green:", IDC_GSTATIC, IDC_GVALUE,
2027 "Blue:", IDC_BSTATIC, IDC_BVALUE, NULL);
2028
2029 CheckDlgButton (hwnd, IDC_BOLDCOLOUR, cfg.bold_colour);
2030 CheckDlgButton (hwnd, IDC_PALETTE, cfg.try_palette);
374330e2 2031 {
2032 int i;
2033 for (i=0; i<22; i++)
2034 if (cfg.bold_colour || permanent[i])
22b26f24 2035 SendDlgItemMessage (hwnd, IDC_LIST, LB_ADDSTRING, 0,
374330e2 2036 (LPARAM) colours[i]);
2037 }
22b26f24 2038 SendDlgItemMessage (hwnd, IDC_LIST, LB_SETCURSEL, 0, 0);
2039 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[0][0], FALSE);
2040 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[0][1], FALSE);
2041 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[0][2], FALSE);
374330e2 2042 break;
2043 case WM_COMMAND:
2044 switch (LOWORD(wParam)) {
22b26f24 2045 case IDC_BOLDCOLOUR:
374330e2 2046 if (HIWORD(wParam) == BN_CLICKED ||
2047 HIWORD(wParam) == BN_DOUBLECLICKED) {
2048 int n, i;
22b26f24 2049 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC_BOLDCOLOUR);
2050 n = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCOUNT, 0, 0);
374330e2 2051 if (cfg.bold_colour && n!=22) {
2052 for (i=0; i<22; i++)
2053 if (!permanent[i])
22b26f24 2054 SendDlgItemMessage (hwnd, IDC_LIST,
374330e2 2055 LB_INSERTSTRING, i,
2056 (LPARAM) colours[i]);
2057 } else if (!cfg.bold_colour && n!=12) {
2058 for (i=22; i-- ;)
2059 if (!permanent[i])
22b26f24 2060 SendDlgItemMessage (hwnd, IDC_LIST,
374330e2 2061 LB_DELETESTRING, i, 0);
2062 }
2063 }
2064 break;
22b26f24 2065 case IDC_PALETTE:
374330e2 2066 if (HIWORD(wParam) == BN_CLICKED ||
2067 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 2068 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC_PALETTE);
374330e2 2069 break;
22b26f24 2070 case IDC_LIST:
374330e2 2071 if (HIWORD(wParam) == LBN_DBLCLK ||
2072 HIWORD(wParam) == LBN_SELCHANGE) {
22b26f24 2073 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
374330e2 2074 0, 0);
2075 if (!cfg.bold_colour)
2076 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
22b26f24 2077 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0], FALSE);
2078 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1], FALSE);
2079 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2], FALSE);
374330e2 2080 }
2081 break;
22b26f24 2082 case IDC_CHANGE:
374330e2 2083 if (HIWORD(wParam) == BN_CLICKED ||
2084 HIWORD(wParam) == BN_DOUBLECLICKED) {
2085 static CHOOSECOLOR cc;
2086 static DWORD custom[16] = {0}; /* zero initialisers */
22b26f24 2087 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
374330e2 2088 0, 0);
2089 if (!cfg.bold_colour)
2090 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
2091 cc.lStructSize = sizeof(cc);
2092 cc.hwndOwner = hwnd;
1d470ad2 2093 cc.hInstance = (HWND)hinst;
374330e2 2094 cc.lpCustColors = custom;
2095 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
2096 cfg.colours[i][2]);
2097 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
2098 if (ChooseColor(&cc)) {
2099 cfg.colours[i][0] =
2100 (unsigned char) (cc.rgbResult & 0xFF);
2101 cfg.colours[i][1] =
2102 (unsigned char) (cc.rgbResult >> 8) & 0xFF;
2103 cfg.colours[i][2] =
2104 (unsigned char) (cc.rgbResult >> 16) & 0xFF;
22b26f24 2105 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0],
374330e2 2106 FALSE);
22b26f24 2107 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1],
374330e2 2108 FALSE);
22b26f24 2109 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2],
374330e2 2110 FALSE);
2111 }
2112 }
2113 break;
2114 }
2115 break;
2116 }
2117 return GeneralPanelProc (hwnd, msg, wParam, lParam);
2118}
2119
c9def1b8 2120static int CALLBACK TranslationProc (HWND hwnd, UINT msg,
14963b8f 2121 WPARAM wParam, LPARAM lParam) {
d4dcbf56 2122 struct ctlpos cp;
22b26f24 2123 enum { controlstartvalue = 1000,
2124 IDC_XLATSTATIC,
2125 IDC_NOXLAT,
2126 IDC_KOI8WIN1251,
2127 IDC_88592WIN1250,
2128 IDC_CAPSLOCKCYR,
2129 IDC_VTSTATIC,
2130 IDC_VTXWINDOWS,
2131 IDC_VTOEMANSI,
2132 IDC_VTOEMONLY,
2133 IDC_VTPOORMAN
2134 };
d4dcbf56 2135
14963b8f 2136 switch (msg) {
2137 case WM_INITDIALOG:
d4dcbf56 2138 /* Accelerators used: [aco] beiknpsx */
2139 ctlposinit(&cp, hwnd);
2140 radiobig(&cp,
22b26f24 2141 "Handling of VT100 line drawing characters:", IDC_VTSTATIC,
2142 "Font has &XWindows encoding", IDC_VTXWINDOWS,
2143 "Use font in &both ANSI and OEM modes", IDC_VTOEMANSI,
2144 "Use font in O&EM mode only", IDC_VTOEMONLY,
d4dcbf56 2145 "&Poor man's line drawing (""+"", ""-"" and ""|"")",
22b26f24 2146 IDC_VTPOORMAN, NULL);
d4dcbf56 2147 radiobig(&cp,
22b26f24 2148 "Character set translation:", IDC_XLATSTATIC,
2149 "&None", IDC_NOXLAT,
2150 "&KOI8 / Win-1251", IDC_KOI8WIN1251,
2151 "&ISO-8859-2 / Win-1250", IDC_88592WIN1250, NULL);
2152 checkbox(&cp, "CAP&S LOCK acts as cyrillic switch", IDC_CAPSLOCKCYR);
2153
2154 CheckRadioButton (hwnd, IDC_NOXLAT, IDC_88592WIN1250,
2155 cfg.xlat_88592w1250 ? IDC_88592WIN1250 :
2156 cfg.xlat_enablekoiwin ? IDC_KOI8WIN1251 :
2157 IDC_NOXLAT);
2158 CheckDlgButton (hwnd, IDC_CAPSLOCKCYR, cfg.xlat_capslockcyr);
2159 CheckRadioButton (hwnd, IDC_VTXWINDOWS, IDC_VTPOORMAN,
2160 cfg.vtmode == VT_XWINDOWS ? IDC_VTXWINDOWS :
2161 cfg.vtmode == VT_OEMANSI ? IDC_VTOEMANSI :
2162 cfg.vtmode == VT_OEMONLY ? IDC_VTOEMONLY :
2163 IDC_VTPOORMAN);
14963b8f 2164 case WM_COMMAND:
2165 switch (LOWORD(wParam)) {
22b26f24 2166 case IDC_NOXLAT:
2167 case IDC_KOI8WIN1251:
2168 case IDC_88592WIN1250:
d3d16feb 2169 cfg.xlat_enablekoiwin =
22b26f24 2170 IsDlgButtonChecked (hwnd, IDC_KOI8WIN1251);
d3d16feb 2171 cfg.xlat_88592w1250 =
22b26f24 2172 IsDlgButtonChecked (hwnd, IDC_88592WIN1250);
14963b8f 2173 break;
22b26f24 2174 case IDC_CAPSLOCKCYR:
14963b8f 2175 if (HIWORD(wParam) == BN_CLICKED ||
2176 HIWORD(wParam) == BN_DOUBLECLICKED) {
2177 cfg.xlat_capslockcyr =
22b26f24 2178 IsDlgButtonChecked (hwnd, IDC_CAPSLOCKCYR);
14963b8f 2179 }
2180 break;
22b26f24 2181 case IDC_VTXWINDOWS:
2182 case IDC_VTOEMANSI:
2183 case IDC_VTOEMONLY:
2184 case IDC_VTPOORMAN:
c9def1b8 2185 cfg.vtmode =
22b26f24 2186 (IsDlgButtonChecked (hwnd, IDC_VTXWINDOWS) ? VT_XWINDOWS :
2187 IsDlgButtonChecked (hwnd, IDC_VTOEMANSI) ? VT_OEMANSI :
2188 IsDlgButtonChecked (hwnd, IDC_VTOEMONLY) ? VT_OEMONLY :
c9def1b8 2189 VT_POORMAN);
2190 break;
14963b8f 2191 }
2192 }
2193 return GeneralPanelProc (hwnd, msg, wParam, lParam);
2194}
2195
374330e2 2196static DLGPROC panelproc[NPANELS] = {
9ca5da42 2197 ConnectionProc, KeyboardProc, TerminalProc, WindowProc,
c9def1b8 2198 TelnetProc, SshProc, SelectionProc, ColourProc, TranslationProc
374330e2 2199};
14963b8f 2200
374330e2 2201static char *names[NPANELS] = {
9ca5da42 2202 "Connection", "Keyboard", "Terminal", "Window", "Telnet",
c9def1b8 2203 "SSH", "Selection", "Colours", "Translation"
374330e2 2204};
2205
9ca5da42 2206static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8};
2207static int reconfp[RECONF_NPANELS] = { 1, 2, 3, 6, 7, 8};
374330e2 2208
d4dcbf56 2209static HWND makesubdialog(HWND hwnd, int x, int y, int w, int h, int n) {
2210 RECT r;
2211 HWND ret;
2212 WPARAM font;
2213 r.left = x; r.top = y;
2214 r.right = r.left + w; r.bottom = r.top + h;
2215 MapDialogRect(hwnd, &r);
2216 ret = CreateWindowEx(WS_EX_CONTROLPARENT,
2217 WC_DIALOG, "", /* no title */
2218 WS_CHILD | WS_VISIBLE | DS_SETFONT,
2219 r.left, r.top,
2220 r.right-r.left, r.bottom-r.top,
22b26f24 2221 hwnd, (HMENU)IDC_SUBDLG,
d4dcbf56 2222 hinst, NULL);
2223 SetWindowLong (ret, DWL_DLGPROC, (LONG)panelproc[n]);
2224 font = SendMessage(hwnd, WM_GETFONT, 0, 0);
2225 SendMessage (ret, WM_SETFONT, font, MAKELPARAM(0, 0));
2226 SendMessage (ret, WM_INITDIALOG, 0, 0);
2227 return ret;
2228}
2229
374330e2 2230static int GenericMainDlgProc (HWND hwnd, UINT msg,
2231 WPARAM wParam, LPARAM lParam,
2232 int npanels, int *panelnums, HWND *page) {
d4dcbf56 2233 HWND hw, tabctl;
374330e2 2234
2235 switch (msg) {
2236 case WM_INITDIALOG:
2237 { /* centre the window */
2238 RECT rs, rd;
2239
2240 hw = GetDesktopWindow();
2241 if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
2242 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
2243 (rs.bottom + rs.top + rd.top - rd.bottom)/2,
2244 rd.right-rd.left, rd.bottom-rd.top, TRUE);
2245 }
d4dcbf56 2246 {
2247 RECT r;
2248 r.left = 3; r.right = r.left + 174;
2249 r.top = 3; r.bottom = r.top + 193;
2250 MapDialogRect(hwnd, &r);
2251 tabctl = CreateWindowEx(0, WC_TABCONTROL, "",
2252 WS_CHILD | WS_VISIBLE |
2253 WS_TABSTOP | TCS_MULTILINE,
2254 r.left, r.top,
2255 r.right-r.left, r.bottom-r.top,
2256 hwnd, (HMENU)IDC_TAB, hinst, NULL);
2257
2258 if (!tabctl) {
2259 struct ctlpos cp;
2260 ctlposinit2(&cp, hwnd);
2261 ersatztab(&cp, "Category:", IDC_TABSTATIC1, IDC_TABLIST,
2262 IDC_TABSTATIC2);
2263 } else {
2264 WPARAM font = SendMessage(hwnd, WM_GETFONT, 0, 0);
2265 SendMessage(tabctl, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
2266 }
2267 }
374330e2 2268 *page = NULL;
d4dcbf56 2269 if (tabctl) { /* initialise the tab control */
374330e2 2270 TC_ITEMHEADER tab;
2271 int i;
2272
374330e2 2273 for (i=0; i<npanels; i++) {
2274 tab.mask = TCIF_TEXT;
2275 tab.pszText = names[panelnums[i]];
d4dcbf56 2276 TabCtrl_InsertItem (tabctl, i, &tab);
374330e2 2277 }
d4dcbf56 2278 } else {
2279 int i;
2280
2281 for (i=0; i<npanels; i++) {
2282 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_ADDSTRING,
2283 0, (LPARAM)names[panelnums[i]]);
2284 }
2285 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_SETCURSEL, 0, 0);
2286 }
2287 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[0]);
374330e2 2288 SetFocus (*page);
2289 return 0;
2290 case WM_NOTIFY:
2291 if (LOWORD(wParam) == IDC_TAB &&
2292 ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
2293 int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
2294 if (*page)
2295 DestroyWindow (*page);
d4dcbf56 2296 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]);
374330e2 2297 SetFocus (((LPNMHDR)lParam)->hwndFrom); /* ensure focus stays */
2298 return 0;
2299 }
2300 break;
374330e2 2301 case WM_COMMAND:
2302 switch (LOWORD(wParam)) {
d4dcbf56 2303 case IDC_TABLIST:
2304 if (HIWORD(wParam) == CBN_SELCHANGE) {
2305 HWND tablist = GetDlgItem (hwnd, IDC_TABLIST);
2306 int i = SendMessage (tablist, CB_GETCURSEL, 0, 0);
2307 if (*page)
2308 DestroyWindow (*page);
2309 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]);
2310 SetFocus(tablist); /* ensure focus stays */
2311 return 0;
2312 }
2313 break;
374330e2 2314 case IDOK:
2315 if (*cfg.host)
2316 EndDialog (hwnd, 1);
2317 else
2318 MessageBeep (0);
2319 return 0;
2320 case IDCANCEL:
2321 EndDialog (hwnd, 0);
2322 return 0;
2323 }
2324 return 0;
2325 case WM_CLOSE:
2326 EndDialog (hwnd, 0);
2327 return 0;
c9def1b8 2328
2329 /* Grrr Explorer will maximize Dialogs! */
2330 case WM_SIZE:
2331 if (wParam == SIZE_MAXIMIZED)
2332 force_normal(hwnd);
2333 return 0;
374330e2 2334 }
2335 return 0;
2336}
2337
2338static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
2339 WPARAM wParam, LPARAM lParam) {
374330e2 2340 static HWND page = NULL;
2341
2342 if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
374330e2 2343 }
2344 if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
2345 EnableWindow(hwnd, 0);
2346 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2347 GetParent(hwnd), AboutProc);
2348 EnableWindow(hwnd, 1);
9a70ac47 2349 SetActiveWindow(hwnd);
374330e2 2350 }
2351 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2352 MAIN_NPANELS, mainp, &page);
2353}
2354
2355static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
2356 WPARAM wParam, LPARAM lParam) {
2357 static HWND page;
2358 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2359 RECONF_NPANELS, reconfp, &page);
2360}
2361
0a4aa984 2362void get_sesslist(int allocate) {
d1622aed 2363 static char otherbuf[2048];
374330e2 2364 static char *buffer;
d1622aed 2365 int buflen, bufsize, i;
2366 char *p, *ret;
2367 void *handle;
374330e2 2368
2369 if (allocate) {
d1622aed 2370
2371 if ((handle = enum_settings_start()) == NULL)
374330e2 2372 return;
2373
2374 buflen = bufsize = 0;
2375 buffer = NULL;
374330e2 2376 do {
d1622aed 2377 ret = enum_settings_next(handle, otherbuf, sizeof(otherbuf));
2378 if (ret) {
2379 int len = strlen(otherbuf)+1;
2380 if (bufsize < buflen+len) {
2381 bufsize = buflen + len + 2048;
2382 buffer = srealloc(buffer, bufsize);
2383 }
2384 strcpy(buffer+buflen, otherbuf);
374330e2 2385 buflen += strlen(buffer+buflen)+1;
2386 }
d1622aed 2387 } while (ret);
2388 enum_settings_finish(handle);
374330e2 2389 buffer = srealloc(buffer, buflen+1);
2390 buffer[buflen] = '\0';
2391
2392 p = buffer;
2393 nsessions = 1; /* "Default Settings" counts as one */
2394 while (*p) {
2395 if (strcmp(p, "Default Settings"))
2396 nsessions++;
2397 while (*p) p++;
2398 p++;
2399 }
2400
2401 sessions = smalloc(nsessions * sizeof(char *));
2402 sessions[0] = "Default Settings";
2403 p = buffer;
2404 i = 1;
2405 while (*p) {
2406 if (strcmp(p, "Default Settings"))
2407 sessions[i++] = p;
2408 while (*p) p++;
2409 p++;
2410 }
2411 } else {
2412 sfree (buffer);
2413 sfree (sessions);
2414 }
2415}
2416
2417int do_config (void) {
2418 int ret;
2419
2420 get_sesslist(TRUE);
6584031a 2421 savedsession[0] = '\0';
374330e2 2422 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
2423 get_sesslist(FALSE);
2424
2425 return ret;
2426}
2427
2428int do_reconfig (HWND hwnd) {
2429 Config backup_cfg;
2430 int ret;
2431
2432 backup_cfg = cfg; /* structure copy */
2433 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
2434 if (!ret)
2435 cfg = backup_cfg; /* structure copy */
c9def1b8 2436 else
2437 force_normal(hwnd);
2438
374330e2 2439 return ret;
2440}
2441
2442void do_defaults (char *session) {
2443 if (session)
2444 load_settings (session, TRUE);
2445 else
2446 load_settings ("Default Settings", FALSE);
2447}
2448
c5e9c988 2449void logevent (char *string) {
2450 if (nevents >= negsize) {
374330e2 2451 negsize += 64;
c5e9c988 2452 events = srealloc (events, negsize * sizeof(*events));
374330e2 2453 }
c5e9c988 2454 events[nevents] = smalloc(1+strlen(string));
2455 strcpy (events[nevents], string);
2456 nevents++;
9ad90448 2457 if (logbox) {
2458 int count;
374330e2 2459 SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
2460 0, (LPARAM)string);
9ad90448 2461 count = SendDlgItemMessage (logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
989b10e9 2462 SendDlgItemMessage (logbox, IDN_LIST, LB_SETTOPINDEX, count-1, 0);
9ad90448 2463 }
374330e2 2464}
2465
c5e9c988 2466void showeventlog (HWND hwnd) {
374330e2 2467 if (!logbox) {
2468 logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
2469 hwnd, LogProc);
2470 ShowWindow (logbox, SW_SHOWNORMAL);
2471 }
2472}
2473
2474void showabout (HWND hwnd) {
2475 if (!abtbox) {
2476 abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2477 hwnd, AboutProc);
2478 ShowWindow (abtbox, SW_SHOWNORMAL);
2479 }
2480}
2481
d4857987 2482void verify_ssh_host_key(char *host, int port, char *keytype,
d5859615 2483 char *keystr, char *fingerprint) {
2484 int ret;
374330e2 2485
d5859615 2486 static const char absentmsg[] =
2487 "The server's host key is not cached in the registry. You\n"
2488 "have no guarantee that the server is the computer you\n"
2489 "think it is.\n"
2490 "The server's key fingerprint is:\n"
2491 "%s\n"
2492 "If you trust this host, hit Yes to add the key to\n"
2493 "PuTTY's cache and carry on connecting.\n"
2494 "If you do not trust this host, hit No to abandon the\n"
2495 "connection.\n";
2496
2497 static const char wrongmsg[] =
2498 "WARNING - POTENTIAL SECURITY BREACH!\n"
2499 "\n"
2500 "The server's host key does not match the one PuTTY has\n"
2501 "cached in the registry. This means that either the\n"
2502 "server administrator has changed the host key, or you\n"
2503 "have actually connected to another computer pretending\n"
2504 "to be the server.\n"
2505 "The new key fingerprint is:\n"
2506 "%s\n"
2507 "If you were expecting this change and trust the new key,\n"
2508 "hit Yes to update PuTTY's cache and continue connecting.\n"
2509 "If you want to carry on connecting but without updating\n"
2510 "the cache, hit No.\n"
2511 "If you want to abandon the connection completely, hit\n"
2512 "Cancel. Hitting Cancel is the ONLY guaranteed safe\n"
2513 "choice.\n";
2514
2515 static const char mbtitle[] = "PuTTY Security Alert";
de3df031 2516
d5859615 2517
2518 char message[160+ /* sensible fingerprint max size */
2519 (sizeof(absentmsg) > sizeof(wrongmsg) ?
2520 sizeof(absentmsg) : sizeof(wrongmsg))];
de3df031 2521
2522 /*
d5859615 2523 * Verify the key against the registry.
de3df031 2524 */
d4857987 2525 ret = verify_host_key(host, port, keytype, keystr);
d5859615 2526
2527 if (ret == 0) /* success - key matched OK */
2528 return;
2529 if (ret == 2) { /* key was different */
2530 int mbret;
2531 sprintf(message, wrongmsg, fingerprint);
2532 mbret = MessageBox(NULL, message, mbtitle,
2533 MB_ICONWARNING | MB_YESNOCANCEL);
2534 if (mbret == IDYES)
d4857987 2535 store_host_key(host, port, keytype, keystr);
d5859615 2536 if (mbret == IDCANCEL)
2537 exit(0);
de3df031 2538 }
d5859615 2539 if (ret == 1) { /* key was absent */
2540 int mbret;
2541 sprintf(message, absentmsg, fingerprint);
2542 mbret = MessageBox(NULL, message, mbtitle,
2543 MB_ICONWARNING | MB_YESNO);
2544 if (mbret == IDNO)
2545 exit(0);
d4857987 2546 store_host_key(host, port, keytype, keystr);
de3df031 2547 }
de3df031 2548}