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