Move omission of SSH protocol setting in PuTTYtel into windlg.c and
[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);
9d01fc92 1094 if (backends[2].backend == NULL) {
1095 /* this is PuTTYtel, so only two protocols available */
1096 radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
1097 "&Raw", IDC_PROTRAW,
1098 "&Telnet", IDC_PROTTELNET, NULL);
1099 } else {
1100 radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
1101 "&Raw", IDC_PROTRAW,
1102 "&Telnet", IDC_PROTTELNET,
d4dcbf56 1103#ifdef FWHACK
9d01fc92 1104 "SS&H/hack",
d4dcbf56 1105#else
9d01fc92 1106 "SS&H",
d4dcbf56 1107#endif
9d01fc92 1108 IDC_PROTSSH, NULL);
1109 }
d4dcbf56 1110 sesssaver(&cp, "Stor&ed Sessions",
22b26f24 1111 IDC_SESSSTATIC, IDC_SESSEDIT, IDC_SESSLIST,
1112 "&Load", IDC_SESSLOAD,
1113 "&Save", IDC_SESSSAVE,
1114 "&Delete", IDC_SESSDEL, NULL);
1115 checkbox(&cp, "Close Window on E&xit", IDC_CLOSEEXIT);
1116 checkbox(&cp, "&Warn on Close", IDC_CLOSEWARN);
1117
1118 SetDlgItemText (hwnd, IDC_HOST, cfg.host);
1119 SetDlgItemText (hwnd, IDC_SESSEDIT, savedsession);
1120 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
374330e2 1121 for (i = 0; i < nsessions; i++)
22b26f24 1122 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
374330e2 1123 0, (LPARAM) (sessions[i]));
22b26f24 1124 CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH,
1125 cfg.protocol==PROT_SSH ? IDC_PROTSSH :
1126 cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW );
1127 CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit);
1128 CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close);
374330e2 1129 break;
1cd246bb 1130 case WM_LBUTTONUP:
1131 /*
1132 * Button release should trigger WM_OK if there was a
1133 * previous double click on the session list.
1134 */
1135 ReleaseCapture();
1136 if (readytogo)
1137 SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
1138 break;
374330e2 1139 case WM_COMMAND:
1140 switch (LOWORD(wParam)) {
22b26f24 1141 case IDC_PROTTELNET:
1142 case IDC_PROTSSH:
1143 case IDC_PROTRAW:
374330e2 1144 if (HIWORD(wParam) == BN_CLICKED ||
1145 HIWORD(wParam) == BN_DOUBLECLICKED) {
22b26f24 1146 int i = IsDlgButtonChecked (hwnd, IDC_PROTSSH);
1147 int j = IsDlgButtonChecked (hwnd, IDC_PROTTELNET);
5e1a8e27 1148 cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ;
374330e2 1149 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
1150 (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
1151 cfg.port = i ? 22 : 23;
22b26f24 1152 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
374330e2 1153 }
1154 }
1155 break;
22b26f24 1156 case IDC_HOST:
374330e2 1157 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1158 GetDlgItemText (hwnd, IDC_HOST, cfg.host,
374330e2 1159 sizeof(cfg.host)-1);
1160 break;
22b26f24 1161 case IDC_PORT:
374330e2 1162 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1163 MyGetDlgItemInt (hwnd, IDC_PORT, &cfg.port);
374330e2 1164 break;
22b26f24 1165 case IDC_CLOSEEXIT:
374330e2 1166 if (HIWORD(wParam) == BN_CLICKED ||
1167 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1168 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC_CLOSEEXIT);
374330e2 1169 break;
22b26f24 1170 case IDC_CLOSEWARN:
9ef49106 1171 if (HIWORD(wParam) == BN_CLICKED ||
1172 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1173 cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC_CLOSEWARN);
9ef49106 1174 break;
22b26f24 1175 case IDC_SESSEDIT:
6584031a 1176 if (HIWORD(wParam) == EN_CHANGE) {
22b26f24 1177 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
374330e2 1178 (WPARAM) -1, 0);
22b26f24 1179 GetDlgItemText (hwnd, IDC_SESSEDIT,
6584031a 1180 savedsession, sizeof(savedsession)-1);
1181 savedsession[sizeof(savedsession)-1] = '\0';
1182 }
374330e2 1183 break;
22b26f24 1184 case IDC_SESSSAVE:
374330e2 1185 if (HIWORD(wParam) == BN_CLICKED ||
1186 HIWORD(wParam) == BN_DOUBLECLICKED) {
1187 /*
1188 * Save a session
1189 */
1190 char str[2048];
22b26f24 1191 GetDlgItemText (hwnd, IDC_SESSEDIT, str, sizeof(str)-1);
374330e2 1192 if (!*str) {
22b26f24 1193 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
374330e2 1194 LB_GETCURSEL, 0, 0);
1195 if (n == LB_ERR) {
1196 MessageBeep(0);
1197 break;
1198 }
1199 strcpy (str, sessions[n]);
1200 }
1201 save_settings (str, !!strcmp(str, "Default Settings"));
1202 get_sesslist (FALSE);
1203 get_sesslist (TRUE);
22b26f24 1204 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
374330e2 1205 0, 0);
1206 for (i = 0; i < nsessions; i++)
22b26f24 1207 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
374330e2 1208 0, (LPARAM) (sessions[i]));
22b26f24 1209 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
374330e2 1210 (WPARAM) -1, 0);
1211 }
1212 break;
22b26f24 1213 case IDC_SESSLIST:
1214 case IDC_SESSLOAD:
1215 if (LOWORD(wParam) == IDC_SESSLOAD &&
374330e2 1216 HIWORD(wParam) != BN_CLICKED &&
1217 HIWORD(wParam) != BN_DOUBLECLICKED)
1218 break;
22b26f24 1219 if (LOWORD(wParam) == IDC_SESSLIST &&
374330e2 1220 HIWORD(wParam) != LBN_DBLCLK)
1221 break;
1222 {
22b26f24 1223 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
374330e2 1224 LB_GETCURSEL, 0, 0);
1225 if (n == LB_ERR) {
1226 MessageBeep(0);
1227 break;
1228 }
1229 load_settings (sessions[n],
1230 !!strcmp(sessions[n], "Default Settings"));
22b26f24 1231 SetDlgItemText (hwnd, IDC_HOST, cfg.host);
1232 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1233 CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH,
1234 (cfg.protocol==PROT_SSH ? IDC_PROTSSH :
1235 cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW));
1236 CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit);
1237 CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close);
1238 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
374330e2 1239 (WPARAM) -1, 0);
1240 }
22b26f24 1241 if (LOWORD(wParam) == IDC_SESSLIST) {
374330e2 1242 /*
1243 * A double-click on a saved session should
1244 * actually start the session, not just load it.
1245 * Unless it's Default Settings or some other
1246 * host-less set of saved settings.
1247 */
1cd246bb 1248 if (*cfg.host) {
1249 readytogo = TRUE;
1250 SetCapture(hwnd);
1251 }
374330e2 1252 }
1253 break;
22b26f24 1254 case IDC_SESSDEL:
374330e2 1255 if (HIWORD(wParam) == BN_CLICKED ||
1256 HIWORD(wParam) == BN_DOUBLECLICKED) {
22b26f24 1257 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
374330e2 1258 LB_GETCURSEL, 0, 0);
1259 if (n == LB_ERR || n == 0) {
1260 MessageBeep(0);
1261 break;
1262 }
d1622aed 1263 del_settings(sessions[n]);
374330e2 1264 get_sesslist (FALSE);
1265 get_sesslist (TRUE);
22b26f24 1266 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
374330e2 1267 0, 0);
1268 for (i = 0; i < nsessions; i++)
22b26f24 1269 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
374330e2 1270 0, (LPARAM) (sessions[i]));
22b26f24 1271 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
374330e2 1272 (WPARAM) -1, 0);
1273 }
1274 }
1275 }
1276 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1277}
1278
1279static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
d4dcbf56 1280 WPARAM wParam, LPARAM lParam) {
1281 struct ctlpos cp;
22b26f24 1282 enum { controlstartvalue = 1000,
1283 IDC_DELSTATIC,
1284 IDC_DEL008,
1285 IDC_DEL127,
1286 IDC_HOMESTATIC,
1287 IDC_HOMETILDE,
1288 IDC_HOMERXVT,
1289 IDC_FUNCSTATIC,
1290 IDC_FUNCTILDE,
1291 IDC_FUNCLINUX,
1292 IDC_FUNCXTERM,
1293 IDC_KPSTATIC,
1294 IDC_KPNORMAL,
1295 IDC_KPAPPLIC,
1296 IDC_KPNH,
1297 IDC_CURSTATIC,
1298 IDC_CURNORMAL,
1299 IDC_CURAPPLIC,
1300 IDC_ALTF4,
1301 IDC_ALTSPACE,
1302 IDC_LDISCTERM,
1303 IDC_SCROLLKEY
1304 };
1305
374330e2 1306 switch (msg) {
1307 case WM_INITDIALOG:
d4dcbf56 1308 /* Accelerators used: [aco] 4?ehiklmnprsuvxy */
1309 ctlposinit(&cp, hwnd);
22b26f24 1310 radioline(&cp, "Action of Backspace:", IDC_DELSTATIC, 2,
1311 "Control-&H", IDC_DEL008,
1312 "Control-&? (127)", IDC_DEL127, NULL);
1313 radioline(&cp, "Action of Home and End:", IDC_HOMESTATIC, 2,
1314 "&Standard", IDC_HOMETILDE,
1315 "&rxvt", IDC_HOMERXVT, NULL);
1316 radioline(&cp, "Function key and keypad layout:", IDC_FUNCSTATIC, 3,
1317 "&VT400", IDC_FUNCTILDE,
1318 "&Linux", IDC_FUNCLINUX,
1319 "&Xterm R6", IDC_FUNCXTERM, NULL);
1320 radioline(&cp, "Initial state of cursor keys:", IDC_CURSTATIC, 2,
1321 "&Normal", IDC_CURNORMAL,
1322 "A&pplication", IDC_CURAPPLIC, NULL);
1323 radioline(&cp, "Initial state of numeric keypad:", IDC_KPSTATIC, 3,
1324 "Nor&mal", IDC_KPNORMAL,
1325 "Appl&ication", IDC_KPAPPLIC,
1326 "N&etHack", IDC_KPNH, NULL);
1327 checkbox(&cp, "ALT-F&4 is special (closes window)", IDC_ALTF4);
1328 checkbox(&cp, "ALT-Space is special (S&ystem menu)", IDC_ALTSPACE);
1329 checkbox(&cp, "&Use local terminal line discipline", IDC_LDISCTERM);
1330 checkbox(&cp, "Reset scrollback on &keypress", IDC_SCROLLKEY);
1331
1332 CheckRadioButton (hwnd, IDC_DEL008, IDC_DEL127,
1333 cfg.bksp_is_delete ? IDC_DEL127 : IDC_DEL008);
1334 CheckRadioButton (hwnd, IDC_HOMETILDE, IDC_HOMERXVT,
1335 cfg.rxvt_homeend ? IDC_HOMERXVT : IDC_HOMETILDE);
1336 CheckRadioButton (hwnd, IDC_FUNCTILDE, IDC_FUNCXTERM,
c9def1b8 1337 cfg.funky_type ?
22b26f24 1338 (cfg.funky_type==2 ? IDC_FUNCXTERM
1339 : IDC_FUNCLINUX )
1340 : IDC_FUNCTILDE);
1341 CheckRadioButton (hwnd, IDC_CURNORMAL, IDC_CURAPPLIC,
1342 cfg.app_cursor ? IDC_CURAPPLIC : IDC_CURNORMAL);
1343 CheckRadioButton (hwnd, IDC_KPNORMAL, IDC_KPNH,
1344 cfg.nethack_keypad ? IDC_KPNH :
1345 cfg.app_keypad ? IDC_KPAPPLIC : IDC_KPNORMAL);
1346 CheckDlgButton (hwnd, IDC_ALTF4, cfg.alt_f4);
1347 CheckDlgButton (hwnd, IDC_ALTSPACE, cfg.alt_space);
1348 CheckDlgButton (hwnd, IDC_LDISCTERM, cfg.ldisc_term);
1349 CheckDlgButton (hwnd, IDC_SCROLLKEY, cfg.scroll_on_key);
374330e2 1350 break;
1351 case WM_COMMAND:
1352 if (HIWORD(wParam) == BN_CLICKED ||
1353 HIWORD(wParam) == BN_DOUBLECLICKED)
1354 switch (LOWORD(wParam)) {
22b26f24 1355 case IDC_DEL008:
1356 case IDC_DEL127:
1357 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC_DEL127);
374330e2 1358 break;
22b26f24 1359 case IDC_HOMETILDE:
1360 case IDC_HOMERXVT:
1361 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC_HOMERXVT);
374330e2 1362 break;
22b26f24 1363 case IDC_FUNCXTERM:
c9def1b8 1364 cfg.funky_type = 2;
1365 break;
22b26f24 1366 case IDC_FUNCTILDE:
1367 case IDC_FUNCLINUX:
1368 cfg.funky_type = IsDlgButtonChecked (hwnd, IDC_FUNCLINUX);
374330e2 1369 break;
22b26f24 1370 case IDC_KPNORMAL:
1371 case IDC_KPAPPLIC:
1372 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC_KPAPPLIC);
c5e9c988 1373 cfg.nethack_keypad = FALSE;
1374 break;
22b26f24 1375 case IDC_KPNH:
c5e9c988 1376 cfg.app_keypad = FALSE;
1377 cfg.nethack_keypad = TRUE;
374330e2 1378 break;
22b26f24 1379 case IDC_CURNORMAL:
1380 case IDC_CURAPPLIC:
1381 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC_CURAPPLIC);
374330e2 1382 break;
22b26f24 1383 case IDC_ALTF4:
c5e9c988 1384 if (HIWORD(wParam) == BN_CLICKED ||
1385 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1386 cfg.alt_f4 = IsDlgButtonChecked (hwnd, IDC_ALTF4);
c5e9c988 1387 break;
22b26f24 1388 case IDC_ALTSPACE:
c5e9c988 1389 if (HIWORD(wParam) == BN_CLICKED ||
1390 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1391 cfg.alt_space = IsDlgButtonChecked (hwnd, IDC_ALTSPACE);
c5e9c988 1392 break;
22b26f24 1393 case IDC_LDISCTERM:
5bc238bb 1394 if (HIWORD(wParam) == BN_CLICKED ||
1395 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1396 cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC_LDISCTERM);
5bc238bb 1397 break;
22b26f24 1398 case IDC_SCROLLKEY:
217dceef 1399 if (HIWORD(wParam) == BN_CLICKED ||
1400 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1401 cfg.scroll_on_key = IsDlgButtonChecked (hwnd, IDC_SCROLLKEY);
217dceef 1402 break;
374330e2 1403 }
1404 }
1405 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1406}
1407
1408static void fmtfont (char *buf) {
1409 sprintf (buf, "Font: %s, ", cfg.font);
1410 if (cfg.fontisbold)
1411 strcat(buf, "bold, ");
1412 if (cfg.fontheight == 0)
1413 strcat (buf, "default height");
1414 else
1415 sprintf (buf+strlen(buf), "%d-%s",
1416 (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
1417 (cfg.fontheight < 0 ? "pixel" : "point"));
1418}
1419
1420static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
1421 WPARAM wParam, LPARAM lParam) {
d4dcbf56 1422 struct ctlpos cp;
374330e2 1423 CHOOSEFONT cf;
1424 LOGFONT lf;
1425 char fontstatic[256];
22b26f24 1426 enum { controlstartvalue = 1000,
1427 IDC_WRAPMODE,
1428 IDC_DECOM,
1429 IDC_DIMSTATIC,
1430 IDC_ROWSSTATIC,
1431 IDC_ROWSEDIT,
1432 IDC_COLSSTATIC,
1433 IDC_COLSEDIT,
1434 IDC_SAVESTATIC,
1435 IDC_SAVEEDIT,
1436 IDC_FONTSTATIC,
1437 IDC_CHOOSEFONT,
1438 IDC_LFHASCR,
1439 IDC_BEEP,
1440 IDC_BCE,
1441 IDC_BLINKTEXT
1442 };
374330e2 1443
1444 switch (msg) {
1445 case WM_INITDIALOG:
d4dcbf56 1446 /* Accelerators used: [aco] dghlmnprsw */
1447 ctlposinit(&cp, hwnd);
1448 multiedit(&cp,
22b26f24 1449 "&Rows", IDC_ROWSSTATIC, IDC_ROWSEDIT, 33,
1450 "Colu&mns", IDC_COLSSTATIC, IDC_COLSEDIT, 33,
1451 "&Scrollback", IDC_SAVESTATIC, IDC_SAVEEDIT, 33,
d4dcbf56 1452 NULL);
22b26f24 1453 staticbtn(&cp, "", IDC_FONTSTATIC, "C&hange...", IDC_CHOOSEFONT);
1454 checkbox(&cp, "Auto &wrap mode initially on", IDC_WRAPMODE);
1455 checkbox(&cp, "&DEC Origin Mode initially on", IDC_DECOM);
1456 checkbox(&cp, "Implicit CR in every &LF", IDC_LFHASCR);
1457 checkbox(&cp, "Bee&p enabled", IDC_BEEP);
1458 checkbox(&cp, "Use Back&ground colour erase", IDC_BCE);
1459 checkbox(&cp, "Enable bli&nking text", IDC_BLINKTEXT);
1460
1461 CheckDlgButton (hwnd, IDC_WRAPMODE, cfg.wrap_mode);
1462 CheckDlgButton (hwnd, IDC_DECOM, cfg.dec_om);
1463 CheckDlgButton (hwnd, IDC_LFHASCR, cfg.lfhascr);
1464 SetDlgItemInt (hwnd, IDC_ROWSEDIT, cfg.height, FALSE);
1465 SetDlgItemInt (hwnd, IDC_COLSEDIT, cfg.width, FALSE);
1466 SetDlgItemInt (hwnd, IDC_SAVEEDIT, cfg.savelines, FALSE);
374330e2 1467 fmtfont (fontstatic);
22b26f24 1468 SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
1469 CheckDlgButton (hwnd, IDC_BEEP, cfg.beep);
1470 CheckDlgButton (hwnd, IDC_BCE, cfg.bce);
1471 CheckDlgButton (hwnd, IDC_BLINKTEXT, cfg.blinktext);
374330e2 1472 break;
1473 case WM_COMMAND:
1474 switch (LOWORD(wParam)) {
22b26f24 1475 case IDC_WRAPMODE:
374330e2 1476 if (HIWORD(wParam) == BN_CLICKED ||
1477 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1478 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC_WRAPMODE);
374330e2 1479 break;
22b26f24 1480 case IDC_DECOM:
374330e2 1481 if (HIWORD(wParam) == BN_CLICKED ||
1482 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1483 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC_DECOM);
374330e2 1484 break;
22b26f24 1485 case IDC_LFHASCR:
fef97f43 1486 if (HIWORD(wParam) == BN_CLICKED ||
1487 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1488 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC_LFHASCR);
fef97f43 1489 break;
22b26f24 1490 case IDC_ROWSEDIT:
374330e2 1491 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1492 MyGetDlgItemInt (hwnd, IDC_ROWSEDIT, &cfg.height);
374330e2 1493 break;
22b26f24 1494 case IDC_COLSEDIT:
374330e2 1495 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1496 MyGetDlgItemInt (hwnd, IDC_COLSEDIT, &cfg.width);
374330e2 1497 break;
22b26f24 1498 case IDC_SAVEEDIT:
374330e2 1499 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1500 MyGetDlgItemInt (hwnd, IDC_SAVEEDIT, &cfg.savelines);
374330e2 1501 break;
22b26f24 1502 case IDC_CHOOSEFONT:
374330e2 1503 lf.lfHeight = cfg.fontheight;
1504 lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
1505 lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
1506 lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
14963b8f 1507 lf.lfCharSet = cfg.fontcharset;
374330e2 1508 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
1509 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1510 lf.lfQuality = DEFAULT_QUALITY;
1511 lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
1512 strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
1513 lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
1514
1515 cf.lStructSize = sizeof(cf);
1516 cf.hwndOwner = hwnd;
1517 cf.lpLogFont = &lf;
1518 cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
1519 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
1520
1521 if (ChooseFont (&cf)) {
1522 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
1523 cfg.font[sizeof(cfg.font)-1] = '\0';
1524 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
14963b8f 1525 cfg.fontcharset = lf.lfCharSet;
374330e2 1526 cfg.fontheight = lf.lfHeight;
1527 fmtfont (fontstatic);
22b26f24 1528 SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
374330e2 1529 }
1530 break;
22b26f24 1531 case IDC_BEEP:
c9def1b8 1532 if (HIWORD(wParam) == BN_CLICKED ||
1533 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1534 cfg.beep = IsDlgButtonChecked (hwnd, IDC_BEEP);
c9def1b8 1535 break;
22b26f24 1536 case IDC_BLINKTEXT:
c9def1b8 1537 if (HIWORD(wParam) == BN_CLICKED ||
1538 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1539 cfg.blinktext = IsDlgButtonChecked (hwnd, IDC_BLINKTEXT);
c9def1b8 1540 break;
22b26f24 1541 case IDC_BCE:
c9def1b8 1542 if (HIWORD(wParam) == BN_CLICKED ||
1543 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1544 cfg.bce = IsDlgButtonChecked (hwnd, IDC_BCE);
c9def1b8 1545 break;
374330e2 1546 }
1547 break;
1548 }
1549 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1550}
1551
9ca5da42 1552static int CALLBACK WindowProc (HWND hwnd, UINT msg,
1553 WPARAM wParam, LPARAM lParam) {
d4dcbf56 1554 struct ctlpos cp;
22b26f24 1555 enum { controlstartvalue = 1000,
1556 IDC_WINNAME,
1557 IDC_BLINKCUR,
1558 IDC_SCROLLBAR,
1559 IDC_LOCKSIZE,
1560 IDC_WINTITLE,
1561 IDC_WINEDIT
1562 };
1563
9ca5da42 1564 switch (msg) {
1565 case WM_INITDIALOG:
d4dcbf56 1566 /* Accelerators used: [aco] bikty */
1567 ctlposinit(&cp, hwnd);
1568 multiedit(&cp,
22b26f24 1569 "Initial window &title:", IDC_WINTITLE, IDC_WINEDIT, 100,
d4dcbf56 1570 NULL);
22b26f24 1571 checkbox(&cp, "Avoid ever using &icon title", IDC_WINNAME);
1572 checkbox(&cp, "&Blinking cursor", IDC_BLINKCUR);
1573 checkbox(&cp, "Displa&y scrollbar", IDC_SCROLLBAR);
1574 checkbox(&cp, "Loc&k Window size", IDC_LOCKSIZE);
1575
1576 SetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle);
1577 CheckDlgButton (hwnd, IDC_WINNAME, cfg.win_name_always);
1578 CheckDlgButton (hwnd, IDC_BLINKCUR, cfg.blink_cur);
1579 CheckDlgButton (hwnd, IDC_SCROLLBAR, cfg.scrollbar);
1580 CheckDlgButton (hwnd, IDC_LOCKSIZE, cfg.locksize);
9ca5da42 1581 break;
1582 case WM_COMMAND:
1583 switch (LOWORD(wParam)) {
22b26f24 1584 case IDC_WINNAME:
9ca5da42 1585 if (HIWORD(wParam) == BN_CLICKED ||
1586 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1587 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC_WINNAME);
9ca5da42 1588 break;
22b26f24 1589 case IDC_BLINKCUR:
9ca5da42 1590 if (HIWORD(wParam) == BN_CLICKED ||
1591 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1592 cfg.blink_cur = IsDlgButtonChecked (hwnd, IDC_BLINKCUR);
9ca5da42 1593 break;
22b26f24 1594 case IDC_SCROLLBAR:
9ca5da42 1595 if (HIWORD(wParam) == BN_CLICKED ||
1596 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1597 cfg.scrollbar = IsDlgButtonChecked (hwnd, IDC_SCROLLBAR);
9ca5da42 1598 break;
22b26f24 1599 case IDC_LOCKSIZE:
9ca5da42 1600 if (HIWORD(wParam) == BN_CLICKED ||
1601 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1602 cfg.locksize = IsDlgButtonChecked (hwnd, IDC_LOCKSIZE);
9ca5da42 1603 break;
22b26f24 1604 case IDC_WINEDIT:
9ca5da42 1605 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1606 GetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle,
9ca5da42 1607 sizeof(cfg.wintitle)-1);
1608 break;
1609 }
1610 break;
1611 }
1612 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1613}
1614
374330e2 1615static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
1616 WPARAM wParam, LPARAM lParam) {
1617 int i;
d4dcbf56 1618 struct ctlpos cp;
22b26f24 1619 enum { controlstartvalue = 1000,
1620 IDC_TTSTATIC,
1621 IDC_TTEDIT,
1622 IDC_TSSTATIC,
1623 IDC_TSEDIT,
1624 IDC_LOGSTATIC,
1625 IDC_LOGEDIT,
1626 IDC_ENVSTATIC,
1627 IDC_VARSTATIC,
1628 IDC_VAREDIT,
1629 IDC_VALSTATIC,
1630 IDC_VALEDIT,
1631 IDC_ENVLIST,
1632 IDC_ENVADD,
1633 IDC_ENVREMOVE,
1634 IDC_EMSTATIC,
1635 IDC_EMBSD,
1636 IDC_EMRFC
1637 };
374330e2 1638
1639 switch (msg) {
1640 case WM_INITDIALOG:
d4dcbf56 1641 /* Accelerators used: [aco] bdflrstuv */
1642 ctlposinit(&cp, hwnd);
22b26f24 1643 staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT);
1644 staticedit(&cp, "Terminal-&speed string", IDC_TSSTATIC, IDC_TSEDIT);
1645 staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT);
1646 envsetter(&cp, "Environment variables:", IDC_ENVSTATIC,
1647 "&Variable", IDC_VARSTATIC, IDC_VAREDIT,
1648 "Va&lue", IDC_VALSTATIC, IDC_VALEDIT,
1649 IDC_ENVLIST,
1650 "A&dd", IDC_ENVADD, "&Remove", IDC_ENVREMOVE);
1651 radioline(&cp, "Handling of OLD_ENVIRON ambiguity:", IDC_EMSTATIC, 2,
1652 "&BSD (commonplace)", IDC_EMBSD,
1653 "R&FC 1408 (unusual)", IDC_EMRFC, NULL);
1654
1655 SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1656 SetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed);
1657 SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
374330e2 1658 {
37508af4 1659 char *p = cfg.environmt;
374330e2 1660 while (*p) {
22b26f24 1661 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING, 0,
374330e2 1662 (LPARAM) p);
1663 p += strlen(p)+1;
1664 }
1665 }
22b26f24 1666 CheckRadioButton (hwnd, IDC_EMBSD, IDC_EMRFC,
1667 cfg.rfc_environ ? IDC_EMRFC : IDC_EMBSD);
374330e2 1668 break;
1669 case WM_COMMAND:
1670 switch (LOWORD(wParam)) {
22b26f24 1671 case IDC_TTEDIT:
374330e2 1672 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1673 GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype,
374330e2 1674 sizeof(cfg.termtype)-1);
1675 break;
22b26f24 1676 case IDC_TSEDIT:
374330e2 1677 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1678 GetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed,
374330e2 1679 sizeof(cfg.termspeed)-1);
1680 break;
22b26f24 1681 case IDC_LOGEDIT:
374330e2 1682 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1683 GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username,
374330e2 1684 sizeof(cfg.username)-1);
1685 break;
22b26f24 1686 case IDC_EMBSD:
1687 case IDC_EMRFC:
1688 cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC_EMRFC);
374330e2 1689 break;
22b26f24 1690 case IDC_ENVADD:
374330e2 1691 if (HIWORD(wParam) == BN_CLICKED ||
1692 HIWORD(wParam) == BN_DOUBLECLICKED) {
37508af4 1693 char str[sizeof(cfg.environmt)];
374330e2 1694 char *p;
22b26f24 1695 GetDlgItemText (hwnd, IDC_VAREDIT, str, sizeof(str)-1);
374330e2 1696 if (!*str) {
1697 MessageBeep(0);
1698 break;
1699 }
1700 p = str + strlen(str);
1701 *p++ = '\t';
22b26f24 1702 GetDlgItemText (hwnd, IDC_VALEDIT, p, sizeof(str)-1-(p-str));
374330e2 1703 if (!*p) {
1704 MessageBeep(0);
1705 break;
1706 }
37508af4 1707 p = cfg.environmt;
374330e2 1708 while (*p) {
1709 while (*p) p++;
1710 p++;
1711 }
37508af4 1712 if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
374330e2 1713 strcpy (p, str);
1714 p[strlen(str)+1] = '\0';
22b26f24 1715 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING,
374330e2 1716 0, (LPARAM)str);
22b26f24 1717 SetDlgItemText (hwnd, IDC_VAREDIT, "");
1718 SetDlgItemText (hwnd, IDC_VALEDIT, "");
374330e2 1719 } else {
1720 MessageBox(hwnd, "Environment too big", "PuTTY Error",
1721 MB_OK | MB_ICONERROR);
1722 }
1723 }
1724 break;
22b26f24 1725 case IDC_ENVREMOVE:
374330e2 1726 if (HIWORD(wParam) != BN_CLICKED &&
1727 HIWORD(wParam) != BN_DOUBLECLICKED)
1728 break;
22b26f24 1729 i = SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_GETCURSEL, 0, 0);
374330e2 1730 if (i == LB_ERR)
1731 MessageBeep (0);
1732 else {
1733 char *p, *q;
1734
22b26f24 1735 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_DELETESTRING,
374330e2 1736 i, 0);
37508af4 1737 p = cfg.environmt;
374330e2 1738 while (i > 0) {
1739 if (!*p)
1740 goto disaster;
1741 while (*p) p++;
1742 p++;
1743 i--;
1744 }
1745 q = p;
1746 if (!*p)
1747 goto disaster;
1748 while (*p) p++;
1749 p++;
1750 while (*p) {
1751 while (*p)
1752 *q++ = *p++;
1753 *q++ = *p++;
1754 }
1755 *q = '\0';
1756 disaster:;
1757 }
1758 break;
1759 }
1760 break;
1761 }
1762 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1763}
1764
1765static int CALLBACK SshProc (HWND hwnd, UINT msg,
1766 WPARAM wParam, LPARAM lParam) {
d4dcbf56 1767 struct ctlpos cp;
7cca0d81 1768 OPENFILENAME of;
1769 char filename[sizeof(cfg.keyfile)];
22b26f24 1770 enum { controlstartvalue = 1000,
1771 IDC_TTSTATIC,
1772 IDC_TTEDIT,
1773 IDC_LOGSTATIC,
1774 IDC_LOGEDIT,
1775 IDC_NOPTY,
1776 IDC_CIPHERSTATIC,
1777 IDC_CIPHER3DES,
1778 IDC_CIPHERBLOWF,
1779 IDC_CIPHERDES,
1780 IDC_AUTHTIS,
1781 IDC_PKSTATIC,
1782 IDC_PKEDIT,
1783 IDC_PKBUTTON,
1784 IDC_SSHPROTSTATIC,
1785 IDC_SSHPROT1,
1786 IDC_SSHPROT2,
1787 IDC_AGENTFWD,
1788 IDC_CMDSTATIC,
1789 IDC_CMDEDIT
1790 };
7cca0d81 1791
374330e2 1792 switch (msg) {
1793 case WM_INITDIALOG:
d4dcbf56 1794 /* Accelerators used: [aco] 123abdkmprtuw */
1795 ctlposinit(&cp, hwnd);
22b26f24 1796 staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT);
1797 staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT);
d4dcbf56 1798 multiedit(&cp,
22b26f24 1799 "&Remote command:", IDC_CMDSTATIC, IDC_CMDEDIT, 100,
d4dcbf56 1800 NULL);
22b26f24 1801 checkbox(&cp, "Don't allocate a &pseudo-terminal", IDC_NOPTY);
d4dcbf56 1802 checkbox(&cp, "Atte&mpt TIS or CryptoCard authentication",
22b26f24 1803 IDC_AUTHTIS);
1804 checkbox(&cp, "Allow &agent forwarding", IDC_AGENTFWD);
d4dcbf56 1805 editbutton(&cp, "Private &key file for authentication:",
22b26f24 1806 IDC_PKSTATIC, IDC_PKEDIT, "Bro&wse...", IDC_PKBUTTON);
d4dcbf56 1807 radioline(&cp, "Preferred SSH protocol version:",
22b26f24 1808 IDC_SSHPROTSTATIC, 2,
1809 "&1", IDC_SSHPROT1, "&2", IDC_SSHPROT2, NULL);
1810 radioline(&cp, "Preferred encryption algorithm:", IDC_CIPHERSTATIC, 3,
1811 "&3DES", IDC_CIPHER3DES,
1812 "&Blowfish", IDC_CIPHERBLOWF,
1813 "&DES", IDC_CIPHERDES, NULL);
1814
1815 SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1816 SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
1817 CheckDlgButton (hwnd, IDC_NOPTY, cfg.nopty);
1818 CheckDlgButton (hwnd, IDC_AGENTFWD, cfg.agentfwd);
1819 CheckRadioButton (hwnd, IDC_CIPHER3DES, IDC_CIPHERDES,
1820 cfg.cipher == CIPHER_BLOWFISH ? IDC_CIPHERBLOWF :
1821 cfg.cipher == CIPHER_DES ? IDC_CIPHERDES :
1822 IDC_CIPHER3DES);
1823 CheckRadioButton (hwnd, IDC_SSHPROT1, IDC_SSHPROT2,
1824 cfg.sshprot == 1 ? IDC_SSHPROT1 : IDC_SSHPROT2);
1825 CheckDlgButton (hwnd, IDC_AUTHTIS, cfg.try_tis_auth);
1826 SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
1827 SetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd);
374330e2 1828 break;
1829 case WM_COMMAND:
1830 switch (LOWORD(wParam)) {
22b26f24 1831 case IDC_TTEDIT:
374330e2 1832 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1833 GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype,
374330e2 1834 sizeof(cfg.termtype)-1);
1835 break;
22b26f24 1836 case IDC_LOGEDIT:
374330e2 1837 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1838 GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username,
374330e2 1839 sizeof(cfg.username)-1);
1840 break;
22b26f24 1841 case IDC_NOPTY:
fef97f43 1842 if (HIWORD(wParam) == BN_CLICKED ||
1843 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1844 cfg.nopty = IsDlgButtonChecked (hwnd, IDC_NOPTY);
fef97f43 1845 break;
22b26f24 1846 case IDC_AGENTFWD:
979310f1 1847 if (HIWORD(wParam) == BN_CLICKED ||
1848 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1849 cfg.agentfwd = IsDlgButtonChecked (hwnd, IDC_AGENTFWD);
979310f1 1850 break;
22b26f24 1851 case IDC_CIPHER3DES:
1852 case IDC_CIPHERBLOWF:
1853 case IDC_CIPHERDES:
bea1ef5f 1854 if (HIWORD(wParam) == BN_CLICKED ||
1855 HIWORD(wParam) == BN_DOUBLECLICKED) {
22b26f24 1856 if (IsDlgButtonChecked (hwnd, IDC_CIPHER3DES))
bea1ef5f 1857 cfg.cipher = CIPHER_3DES;
22b26f24 1858 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERBLOWF))
bea1ef5f 1859 cfg.cipher = CIPHER_BLOWFISH;
22b26f24 1860 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERDES))
9697bfd2 1861 cfg.cipher = CIPHER_DES;
bea1ef5f 1862 }
1863 break;
22b26f24 1864 case IDC_SSHPROT1:
1865 case IDC_SSHPROT2:
adf799dd 1866 if (HIWORD(wParam) == BN_CLICKED ||
1867 HIWORD(wParam) == BN_DOUBLECLICKED) {
22b26f24 1868 if (IsDlgButtonChecked (hwnd, IDC_SSHPROT1))
adf799dd 1869 cfg.sshprot = 1;
22b26f24 1870 else if (IsDlgButtonChecked (hwnd, IDC_SSHPROT2))
adf799dd 1871 cfg.sshprot = 2;
1872 }
1873 break;
22b26f24 1874 case IDC_AUTHTIS:
ccbfb941 1875 if (HIWORD(wParam) == BN_CLICKED ||
1876 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 1877 cfg.try_tis_auth = IsDlgButtonChecked (hwnd, IDC_AUTHTIS);
ccbfb941 1878 break;
22b26f24 1879 case IDC_PKEDIT:
7cca0d81 1880 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1881 GetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile,
7cca0d81 1882 sizeof(cfg.keyfile)-1);
1883 break;
22b26f24 1884 case IDC_CMDEDIT:
4c73ca1f 1885 if (HIWORD(wParam) == EN_CHANGE)
22b26f24 1886 GetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd,
4c73ca1f 1887 sizeof(cfg.remote_cmd)-1);
1888 break;
22b26f24 1889 case IDC_PKBUTTON:
7cca0d81 1890 /*
1891 * FIXME: this crashes. Find out why.
1892 */
1893 memset(&of, 0, sizeof(of));
1894#ifdef OPENFILENAME_SIZE_VERSION_400
1895 of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
1896#else
1897 of.lStructSize = sizeof(of);
1898#endif
1899 of.hwndOwner = hwnd;
1900 of.lpstrFilter = "All Files\0*\0\0\0";
1901 of.lpstrCustomFilter = NULL;
1902 of.nFilterIndex = 1;
1903 of.lpstrFile = filename; strcpy(filename, cfg.keyfile);
1904 of.nMaxFile = sizeof(filename);
1905 of.lpstrFileTitle = NULL;
1906 of.lpstrInitialDir = NULL;
1907 of.lpstrTitle = "Select Public Key File";
1908 of.Flags = 0;
1909 if (GetOpenFileName(&of)) {
1910 strcpy(cfg.keyfile, filename);
22b26f24 1911 SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
7cca0d81 1912 }
1913 break;
374330e2 1914 }
1915 break;
1916 }
1917 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1918}
1919
1920static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
1921 WPARAM wParam, LPARAM lParam) {
d4dcbf56 1922 struct ctlpos cp;
374330e2 1923 int i;
22b26f24 1924 enum { controlstartvalue = 1000,
1925 IDC_MBSTATIC,
1926 IDC_MBWINDOWS,
1927 IDC_MBXTERM,
1928 IDC_CCSTATIC,
1929 IDC_CCLIST,
1930 IDC_CCSET,
1931 IDC_CCSTATIC2,
1932 IDC_CCEDIT
1933 };
374330e2 1934
1935 switch (msg) {
1936 case WM_INITDIALOG:
d4dcbf56 1937 /* Accelerators used: [aco] stwx */
1938 ctlposinit(&cp, hwnd);
22b26f24 1939 radiobig(&cp, "Action of mouse buttons:", IDC_MBSTATIC,
1940 "&Windows (Right pastes, Middle extends)", IDC_MBWINDOWS,
1941 "&xterm (Right extends, Middle pastes)", IDC_MBXTERM,
d4dcbf56 1942 NULL);
22b26f24 1943 charclass(&cp, "Character classes:", IDC_CCSTATIC, IDC_CCLIST,
1944 "&Set", IDC_CCSET, IDC_CCEDIT,
1945 "&to class", IDC_CCSTATIC2);
d4dcbf56 1946
22b26f24 1947 CheckRadioButton (hwnd, IDC_MBWINDOWS, IDC_MBXTERM,
1948 cfg.mouse_is_xterm ? IDC_MBXTERM : IDC_MBWINDOWS);
374330e2 1949 {
1950 static int tabs[4] = {25, 61, 96, 128};
22b26f24 1951 SendDlgItemMessage (hwnd, IDC_CCLIST, LB_SETTABSTOPS, 4,
374330e2 1952 (LPARAM) tabs);
1953 }
1954 for (i=0; i<256; i++) {
1955 char str[100];
1956 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1957 (i>=0x21 && i != 0x7F) ? i : ' ',
1958 cfg.wordness[i]);
22b26f24 1959 SendDlgItemMessage (hwnd, IDC_CCLIST, LB_ADDSTRING, 0,
374330e2 1960 (LPARAM) str);
1961 }
1962 break;
1963 case WM_COMMAND:
1964 switch (LOWORD(wParam)) {
22b26f24 1965 case IDC_MBWINDOWS:
1966 case IDC_MBXTERM:
1967 cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC_MBXTERM);
374330e2 1968 break;
22b26f24 1969 case IDC_CCSET:
374330e2 1970 {
1971 BOOL ok;
1972 int i;
22b26f24 1973 int n = GetDlgItemInt (hwnd, IDC_CCEDIT, &ok, FALSE);
374330e2 1974
1975 if (!ok)
1976 MessageBeep (0);
1977 else {
1978 for (i=0; i<256; i++)
22b26f24 1979 if (SendDlgItemMessage (hwnd, IDC_CCLIST, LB_GETSEL,
374330e2 1980 i, 0)) {
1981 char str[100];
1982 cfg.wordness[i] = n;
22b26f24 1983 SendDlgItemMessage (hwnd, IDC_CCLIST,
374330e2 1984 LB_DELETESTRING, i, 0);
1985 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1986 (i>=0x21 && i != 0x7F) ? i : ' ',
1987 cfg.wordness[i]);
22b26f24 1988 SendDlgItemMessage (hwnd, IDC_CCLIST,
374330e2 1989 LB_INSERTSTRING, i,
1990 (LPARAM)str);
1991 }
1992 }
1993 }
1994 break;
1995 }
1996 break;
1997 }
1998 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1999}
2000
2001static int CALLBACK ColourProc (HWND hwnd, UINT msg,
2002 WPARAM wParam, LPARAM lParam) {
2003 static const char *const colours[] = {
2004 "Default Foreground", "Default Bold Foreground",
2005 "Default Background", "Default Bold Background",
2006 "Cursor Text", "Cursor Colour",
2007 "ANSI Black", "ANSI Black Bold",
2008 "ANSI Red", "ANSI Red Bold",
2009 "ANSI Green", "ANSI Green Bold",
2010 "ANSI Yellow", "ANSI Yellow Bold",
2011 "ANSI Blue", "ANSI Blue Bold",
2012 "ANSI Magenta", "ANSI Magenta Bold",
2013 "ANSI Cyan", "ANSI Cyan Bold",
2014 "ANSI White", "ANSI White Bold"
2015 };
2016 static const int permanent[] = {
2017 TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
2018 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
2019 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
2020 };
d4dcbf56 2021 struct ctlpos cp;
22b26f24 2022 enum { controlstartvalue = 1000,
2023 IDC_BOLDCOLOUR,
2024 IDC_PALETTE,
2025 IDC_STATIC,
2026 IDC_LIST,
2027 IDC_RSTATIC,
2028 IDC_GSTATIC,
2029 IDC_BSTATIC,
2030 IDC_RVALUE,
2031 IDC_GVALUE,
2032 IDC_BVALUE,
2033 IDC_CHANGE
2034 };
d4dcbf56 2035
374330e2 2036 switch (msg) {
2037 case WM_INITDIALOG:
d4dcbf56 2038 /* Accelerators used: [aco] bmlu */
2039 ctlposinit(&cp, hwnd);
22b26f24 2040 checkbox(&cp, "&Bolded text is a different colour", IDC_BOLDCOLOUR);
2041 checkbox(&cp, "Attempt to use &logical palettes", IDC_PALETTE);
d4dcbf56 2042 colouredit(&cp, "Select a colo&ur and click to modify it:",
22b26f24 2043 IDC_STATIC, IDC_LIST,
2044 "&Modify...", IDC_CHANGE,
2045 "Red:", IDC_RSTATIC, IDC_RVALUE,
2046 "Green:", IDC_GSTATIC, IDC_GVALUE,
2047 "Blue:", IDC_BSTATIC, IDC_BVALUE, NULL);
2048
2049 CheckDlgButton (hwnd, IDC_BOLDCOLOUR, cfg.bold_colour);
2050 CheckDlgButton (hwnd, IDC_PALETTE, cfg.try_palette);
374330e2 2051 {
2052 int i;
2053 for (i=0; i<22; i++)
2054 if (cfg.bold_colour || permanent[i])
22b26f24 2055 SendDlgItemMessage (hwnd, IDC_LIST, LB_ADDSTRING, 0,
374330e2 2056 (LPARAM) colours[i]);
2057 }
22b26f24 2058 SendDlgItemMessage (hwnd, IDC_LIST, LB_SETCURSEL, 0, 0);
2059 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[0][0], FALSE);
2060 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[0][1], FALSE);
2061 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[0][2], FALSE);
374330e2 2062 break;
2063 case WM_COMMAND:
2064 switch (LOWORD(wParam)) {
22b26f24 2065 case IDC_BOLDCOLOUR:
374330e2 2066 if (HIWORD(wParam) == BN_CLICKED ||
2067 HIWORD(wParam) == BN_DOUBLECLICKED) {
2068 int n, i;
22b26f24 2069 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC_BOLDCOLOUR);
2070 n = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCOUNT, 0, 0);
374330e2 2071 if (cfg.bold_colour && n!=22) {
2072 for (i=0; i<22; i++)
2073 if (!permanent[i])
22b26f24 2074 SendDlgItemMessage (hwnd, IDC_LIST,
374330e2 2075 LB_INSERTSTRING, i,
2076 (LPARAM) colours[i]);
2077 } else if (!cfg.bold_colour && n!=12) {
2078 for (i=22; i-- ;)
2079 if (!permanent[i])
22b26f24 2080 SendDlgItemMessage (hwnd, IDC_LIST,
374330e2 2081 LB_DELETESTRING, i, 0);
2082 }
2083 }
2084 break;
22b26f24 2085 case IDC_PALETTE:
374330e2 2086 if (HIWORD(wParam) == BN_CLICKED ||
2087 HIWORD(wParam) == BN_DOUBLECLICKED)
22b26f24 2088 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC_PALETTE);
374330e2 2089 break;
22b26f24 2090 case IDC_LIST:
374330e2 2091 if (HIWORD(wParam) == LBN_DBLCLK ||
2092 HIWORD(wParam) == LBN_SELCHANGE) {
22b26f24 2093 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
374330e2 2094 0, 0);
2095 if (!cfg.bold_colour)
2096 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
22b26f24 2097 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0], FALSE);
2098 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1], FALSE);
2099 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2], FALSE);
374330e2 2100 }
2101 break;
22b26f24 2102 case IDC_CHANGE:
374330e2 2103 if (HIWORD(wParam) == BN_CLICKED ||
2104 HIWORD(wParam) == BN_DOUBLECLICKED) {
2105 static CHOOSECOLOR cc;
2106 static DWORD custom[16] = {0}; /* zero initialisers */
22b26f24 2107 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
374330e2 2108 0, 0);
2109 if (!cfg.bold_colour)
2110 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
2111 cc.lStructSize = sizeof(cc);
2112 cc.hwndOwner = hwnd;
1d470ad2 2113 cc.hInstance = (HWND)hinst;
374330e2 2114 cc.lpCustColors = custom;
2115 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
2116 cfg.colours[i][2]);
2117 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
2118 if (ChooseColor(&cc)) {
2119 cfg.colours[i][0] =
2120 (unsigned char) (cc.rgbResult & 0xFF);
2121 cfg.colours[i][1] =
2122 (unsigned char) (cc.rgbResult >> 8) & 0xFF;
2123 cfg.colours[i][2] =
2124 (unsigned char) (cc.rgbResult >> 16) & 0xFF;
22b26f24 2125 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0],
374330e2 2126 FALSE);
22b26f24 2127 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1],
374330e2 2128 FALSE);
22b26f24 2129 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2],
374330e2 2130 FALSE);
2131 }
2132 }
2133 break;
2134 }
2135 break;
2136 }
2137 return GeneralPanelProc (hwnd, msg, wParam, lParam);
2138}
2139
c9def1b8 2140static int CALLBACK TranslationProc (HWND hwnd, UINT msg,
14963b8f 2141 WPARAM wParam, LPARAM lParam) {
d4dcbf56 2142 struct ctlpos cp;
22b26f24 2143 enum { controlstartvalue = 1000,
2144 IDC_XLATSTATIC,
2145 IDC_NOXLAT,
2146 IDC_KOI8WIN1251,
2147 IDC_88592WIN1250,
2148 IDC_CAPSLOCKCYR,
2149 IDC_VTSTATIC,
2150 IDC_VTXWINDOWS,
2151 IDC_VTOEMANSI,
2152 IDC_VTOEMONLY,
2153 IDC_VTPOORMAN
2154 };
d4dcbf56 2155
14963b8f 2156 switch (msg) {
2157 case WM_INITDIALOG:
d4dcbf56 2158 /* Accelerators used: [aco] beiknpsx */
2159 ctlposinit(&cp, hwnd);
2160 radiobig(&cp,
22b26f24 2161 "Handling of VT100 line drawing characters:", IDC_VTSTATIC,
2162 "Font has &XWindows encoding", IDC_VTXWINDOWS,
2163 "Use font in &both ANSI and OEM modes", IDC_VTOEMANSI,
2164 "Use font in O&EM mode only", IDC_VTOEMONLY,
d4dcbf56 2165 "&Poor man's line drawing (""+"", ""-"" and ""|"")",
22b26f24 2166 IDC_VTPOORMAN, NULL);
d4dcbf56 2167 radiobig(&cp,
22b26f24 2168 "Character set translation:", IDC_XLATSTATIC,
2169 "&None", IDC_NOXLAT,
2170 "&KOI8 / Win-1251", IDC_KOI8WIN1251,
2171 "&ISO-8859-2 / Win-1250", IDC_88592WIN1250, NULL);
2172 checkbox(&cp, "CAP&S LOCK acts as cyrillic switch", IDC_CAPSLOCKCYR);
2173
2174 CheckRadioButton (hwnd, IDC_NOXLAT, IDC_88592WIN1250,
2175 cfg.xlat_88592w1250 ? IDC_88592WIN1250 :
2176 cfg.xlat_enablekoiwin ? IDC_KOI8WIN1251 :
2177 IDC_NOXLAT);
2178 CheckDlgButton (hwnd, IDC_CAPSLOCKCYR, cfg.xlat_capslockcyr);
2179 CheckRadioButton (hwnd, IDC_VTXWINDOWS, IDC_VTPOORMAN,
2180 cfg.vtmode == VT_XWINDOWS ? IDC_VTXWINDOWS :
2181 cfg.vtmode == VT_OEMANSI ? IDC_VTOEMANSI :
2182 cfg.vtmode == VT_OEMONLY ? IDC_VTOEMONLY :
2183 IDC_VTPOORMAN);
14963b8f 2184 case WM_COMMAND:
2185 switch (LOWORD(wParam)) {
22b26f24 2186 case IDC_NOXLAT:
2187 case IDC_KOI8WIN1251:
2188 case IDC_88592WIN1250:
d3d16feb 2189 cfg.xlat_enablekoiwin =
22b26f24 2190 IsDlgButtonChecked (hwnd, IDC_KOI8WIN1251);
d3d16feb 2191 cfg.xlat_88592w1250 =
22b26f24 2192 IsDlgButtonChecked (hwnd, IDC_88592WIN1250);
14963b8f 2193 break;
22b26f24 2194 case IDC_CAPSLOCKCYR:
14963b8f 2195 if (HIWORD(wParam) == BN_CLICKED ||
2196 HIWORD(wParam) == BN_DOUBLECLICKED) {
2197 cfg.xlat_capslockcyr =
22b26f24 2198 IsDlgButtonChecked (hwnd, IDC_CAPSLOCKCYR);
14963b8f 2199 }
2200 break;
22b26f24 2201 case IDC_VTXWINDOWS:
2202 case IDC_VTOEMANSI:
2203 case IDC_VTOEMONLY:
2204 case IDC_VTPOORMAN:
c9def1b8 2205 cfg.vtmode =
22b26f24 2206 (IsDlgButtonChecked (hwnd, IDC_VTXWINDOWS) ? VT_XWINDOWS :
2207 IsDlgButtonChecked (hwnd, IDC_VTOEMANSI) ? VT_OEMANSI :
2208 IsDlgButtonChecked (hwnd, IDC_VTOEMONLY) ? VT_OEMONLY :
c9def1b8 2209 VT_POORMAN);
2210 break;
14963b8f 2211 }
2212 }
2213 return GeneralPanelProc (hwnd, msg, wParam, lParam);
2214}
2215
374330e2 2216static DLGPROC panelproc[NPANELS] = {
9ca5da42 2217 ConnectionProc, KeyboardProc, TerminalProc, WindowProc,
c9def1b8 2218 TelnetProc, SshProc, SelectionProc, ColourProc, TranslationProc
374330e2 2219};
14963b8f 2220
374330e2 2221static char *names[NPANELS] = {
9ca5da42 2222 "Connection", "Keyboard", "Terminal", "Window", "Telnet",
c9def1b8 2223 "SSH", "Selection", "Colours", "Translation"
374330e2 2224};
2225
9ca5da42 2226static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8};
2227static int reconfp[RECONF_NPANELS] = { 1, 2, 3, 6, 7, 8};
374330e2 2228
d4dcbf56 2229static HWND makesubdialog(HWND hwnd, int x, int y, int w, int h, int n) {
2230 RECT r;
2231 HWND ret;
2232 WPARAM font;
2233 r.left = x; r.top = y;
2234 r.right = r.left + w; r.bottom = r.top + h;
2235 MapDialogRect(hwnd, &r);
2236 ret = CreateWindowEx(WS_EX_CONTROLPARENT,
2237 WC_DIALOG, "", /* no title */
2238 WS_CHILD | WS_VISIBLE | DS_SETFONT,
2239 r.left, r.top,
2240 r.right-r.left, r.bottom-r.top,
22b26f24 2241 hwnd, (HMENU)IDC_SUBDLG,
d4dcbf56 2242 hinst, NULL);
2243 SetWindowLong (ret, DWL_DLGPROC, (LONG)panelproc[n]);
2244 font = SendMessage(hwnd, WM_GETFONT, 0, 0);
2245 SendMessage (ret, WM_SETFONT, font, MAKELPARAM(0, 0));
2246 SendMessage (ret, WM_INITDIALOG, 0, 0);
2247 return ret;
2248}
2249
374330e2 2250static int GenericMainDlgProc (HWND hwnd, UINT msg,
2251 WPARAM wParam, LPARAM lParam,
2252 int npanels, int *panelnums, HWND *page) {
d4dcbf56 2253 HWND hw, tabctl;
374330e2 2254
2255 switch (msg) {
2256 case WM_INITDIALOG:
2257 { /* centre the window */
2258 RECT rs, rd;
2259
2260 hw = GetDesktopWindow();
2261 if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
2262 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
2263 (rs.bottom + rs.top + rd.top - rd.bottom)/2,
2264 rd.right-rd.left, rd.bottom-rd.top, TRUE);
2265 }
d4dcbf56 2266 {
2267 RECT r;
2268 r.left = 3; r.right = r.left + 174;
2269 r.top = 3; r.bottom = r.top + 193;
2270 MapDialogRect(hwnd, &r);
2271 tabctl = CreateWindowEx(0, WC_TABCONTROL, "",
2272 WS_CHILD | WS_VISIBLE |
2273 WS_TABSTOP | TCS_MULTILINE,
2274 r.left, r.top,
2275 r.right-r.left, r.bottom-r.top,
2276 hwnd, (HMENU)IDC_TAB, hinst, NULL);
2277
2278 if (!tabctl) {
2279 struct ctlpos cp;
2280 ctlposinit2(&cp, hwnd);
2281 ersatztab(&cp, "Category:", IDC_TABSTATIC1, IDC_TABLIST,
2282 IDC_TABSTATIC2);
2283 } else {
2284 WPARAM font = SendMessage(hwnd, WM_GETFONT, 0, 0);
2285 SendMessage(tabctl, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
2286 }
2287 }
374330e2 2288 *page = NULL;
d4dcbf56 2289 if (tabctl) { /* initialise the tab control */
374330e2 2290 TC_ITEMHEADER tab;
2291 int i;
2292
374330e2 2293 for (i=0; i<npanels; i++) {
2294 tab.mask = TCIF_TEXT;
2295 tab.pszText = names[panelnums[i]];
d4dcbf56 2296 TabCtrl_InsertItem (tabctl, i, &tab);
374330e2 2297 }
d4dcbf56 2298 } else {
2299 int i;
2300
2301 for (i=0; i<npanels; i++) {
2302 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_ADDSTRING,
2303 0, (LPARAM)names[panelnums[i]]);
2304 }
2305 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_SETCURSEL, 0, 0);
2306 }
2307 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[0]);
374330e2 2308 SetFocus (*page);
2309 return 0;
2310 case WM_NOTIFY:
2311 if (LOWORD(wParam) == IDC_TAB &&
2312 ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
2313 int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
2314 if (*page)
2315 DestroyWindow (*page);
d4dcbf56 2316 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]);
374330e2 2317 SetFocus (((LPNMHDR)lParam)->hwndFrom); /* ensure focus stays */
2318 return 0;
2319 }
2320 break;
374330e2 2321 case WM_COMMAND:
2322 switch (LOWORD(wParam)) {
d4dcbf56 2323 case IDC_TABLIST:
2324 if (HIWORD(wParam) == CBN_SELCHANGE) {
2325 HWND tablist = GetDlgItem (hwnd, IDC_TABLIST);
2326 int i = SendMessage (tablist, CB_GETCURSEL, 0, 0);
2327 if (*page)
2328 DestroyWindow (*page);
2329 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]);
2330 SetFocus(tablist); /* ensure focus stays */
2331 return 0;
2332 }
2333 break;
374330e2 2334 case IDOK:
2335 if (*cfg.host)
2336 EndDialog (hwnd, 1);
2337 else
2338 MessageBeep (0);
2339 return 0;
2340 case IDCANCEL:
2341 EndDialog (hwnd, 0);
2342 return 0;
2343 }
2344 return 0;
2345 case WM_CLOSE:
2346 EndDialog (hwnd, 0);
2347 return 0;
c9def1b8 2348
2349 /* Grrr Explorer will maximize Dialogs! */
2350 case WM_SIZE:
2351 if (wParam == SIZE_MAXIMIZED)
2352 force_normal(hwnd);
2353 return 0;
374330e2 2354 }
2355 return 0;
2356}
2357
2358static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
2359 WPARAM wParam, LPARAM lParam) {
374330e2 2360 static HWND page = NULL;
2361
2362 if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
374330e2 2363 }
2364 if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
2365 EnableWindow(hwnd, 0);
2366 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2367 GetParent(hwnd), AboutProc);
2368 EnableWindow(hwnd, 1);
9a70ac47 2369 SetActiveWindow(hwnd);
374330e2 2370 }
2371 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2372 MAIN_NPANELS, mainp, &page);
2373}
2374
2375static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
2376 WPARAM wParam, LPARAM lParam) {
2377 static HWND page;
2378 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2379 RECONF_NPANELS, reconfp, &page);
2380}
2381
0a4aa984 2382void get_sesslist(int allocate) {
d1622aed 2383 static char otherbuf[2048];
374330e2 2384 static char *buffer;
d1622aed 2385 int buflen, bufsize, i;
2386 char *p, *ret;
2387 void *handle;
374330e2 2388
2389 if (allocate) {
d1622aed 2390
2391 if ((handle = enum_settings_start()) == NULL)
374330e2 2392 return;
2393
2394 buflen = bufsize = 0;
2395 buffer = NULL;
374330e2 2396 do {
d1622aed 2397 ret = enum_settings_next(handle, otherbuf, sizeof(otherbuf));
2398 if (ret) {
2399 int len = strlen(otherbuf)+1;
2400 if (bufsize < buflen+len) {
2401 bufsize = buflen + len + 2048;
2402 buffer = srealloc(buffer, bufsize);
2403 }
2404 strcpy(buffer+buflen, otherbuf);
374330e2 2405 buflen += strlen(buffer+buflen)+1;
2406 }
d1622aed 2407 } while (ret);
2408 enum_settings_finish(handle);
374330e2 2409 buffer = srealloc(buffer, buflen+1);
2410 buffer[buflen] = '\0';
2411
2412 p = buffer;
2413 nsessions = 1; /* "Default Settings" counts as one */
2414 while (*p) {
2415 if (strcmp(p, "Default Settings"))
2416 nsessions++;
2417 while (*p) p++;
2418 p++;
2419 }
2420
2421 sessions = smalloc(nsessions * sizeof(char *));
2422 sessions[0] = "Default Settings";
2423 p = buffer;
2424 i = 1;
2425 while (*p) {
2426 if (strcmp(p, "Default Settings"))
2427 sessions[i++] = p;
2428 while (*p) p++;
2429 p++;
2430 }
2431 } else {
2432 sfree (buffer);
2433 sfree (sessions);
2434 }
2435}
2436
2437int do_config (void) {
2438 int ret;
2439
2440 get_sesslist(TRUE);
6584031a 2441 savedsession[0] = '\0';
374330e2 2442 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
2443 get_sesslist(FALSE);
2444
2445 return ret;
2446}
2447
2448int do_reconfig (HWND hwnd) {
2449 Config backup_cfg;
2450 int ret;
2451
2452 backup_cfg = cfg; /* structure copy */
2453 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
2454 if (!ret)
2455 cfg = backup_cfg; /* structure copy */
c9def1b8 2456 else
2457 force_normal(hwnd);
2458
374330e2 2459 return ret;
2460}
2461
2462void do_defaults (char *session) {
2463 if (session)
2464 load_settings (session, TRUE);
2465 else
2466 load_settings ("Default Settings", FALSE);
2467}
2468
c5e9c988 2469void logevent (char *string) {
2470 if (nevents >= negsize) {
374330e2 2471 negsize += 64;
c5e9c988 2472 events = srealloc (events, negsize * sizeof(*events));
374330e2 2473 }
c5e9c988 2474 events[nevents] = smalloc(1+strlen(string));
2475 strcpy (events[nevents], string);
2476 nevents++;
9ad90448 2477 if (logbox) {
2478 int count;
374330e2 2479 SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
2480 0, (LPARAM)string);
9ad90448 2481 count = SendDlgItemMessage (logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
989b10e9 2482 SendDlgItemMessage (logbox, IDN_LIST, LB_SETTOPINDEX, count-1, 0);
9ad90448 2483 }
374330e2 2484}
2485
c5e9c988 2486void showeventlog (HWND hwnd) {
374330e2 2487 if (!logbox) {
2488 logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
2489 hwnd, LogProc);
2490 ShowWindow (logbox, SW_SHOWNORMAL);
2491 }
2492}
2493
2494void showabout (HWND hwnd) {
2495 if (!abtbox) {
2496 abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2497 hwnd, AboutProc);
2498 ShowWindow (abtbox, SW_SHOWNORMAL);
2499 }
2500}
2501
d4857987 2502void verify_ssh_host_key(char *host, int port, char *keytype,
d5859615 2503 char *keystr, char *fingerprint) {
2504 int ret;
374330e2 2505
d5859615 2506 static const char absentmsg[] =
2507 "The server's host key is not cached in the registry. You\n"
2508 "have no guarantee that the server is the computer you\n"
2509 "think it is.\n"
2510 "The server's key fingerprint is:\n"
2511 "%s\n"
2512 "If you trust this host, hit Yes to add the key to\n"
2513 "PuTTY's cache and carry on connecting.\n"
2514 "If you do not trust this host, hit No to abandon the\n"
2515 "connection.\n";
2516
2517 static const char wrongmsg[] =
2518 "WARNING - POTENTIAL SECURITY BREACH!\n"
2519 "\n"
2520 "The server's host key does not match the one PuTTY has\n"
2521 "cached in the registry. This means that either the\n"
2522 "server administrator has changed the host key, or you\n"
2523 "have actually connected to another computer pretending\n"
2524 "to be the server.\n"
2525 "The new key fingerprint is:\n"
2526 "%s\n"
2527 "If you were expecting this change and trust the new key,\n"
2528 "hit Yes to update PuTTY's cache and continue connecting.\n"
2529 "If you want to carry on connecting but without updating\n"
2530 "the cache, hit No.\n"
2531 "If you want to abandon the connection completely, hit\n"
2532 "Cancel. Hitting Cancel is the ONLY guaranteed safe\n"
2533 "choice.\n";
2534
2535 static const char mbtitle[] = "PuTTY Security Alert";
de3df031 2536
d5859615 2537
2538 char message[160+ /* sensible fingerprint max size */
2539 (sizeof(absentmsg) > sizeof(wrongmsg) ?
2540 sizeof(absentmsg) : sizeof(wrongmsg))];
de3df031 2541
2542 /*
d5859615 2543 * Verify the key against the registry.
de3df031 2544 */
d4857987 2545 ret = verify_host_key(host, port, keytype, keystr);
d5859615 2546
2547 if (ret == 0) /* success - key matched OK */
2548 return;
2549 if (ret == 2) { /* key was different */
2550 int mbret;
2551 sprintf(message, wrongmsg, fingerprint);
2552 mbret = MessageBox(NULL, message, mbtitle,
2553 MB_ICONWARNING | MB_YESNOCANCEL);
2554 if (mbret == IDYES)
d4857987 2555 store_host_key(host, port, keytype, keystr);
d5859615 2556 if (mbret == IDCANCEL)
2557 exit(0);
de3df031 2558 }
d5859615 2559 if (ret == 1) { /* key was absent */
2560 int mbret;
2561 sprintf(message, absentmsg, fingerprint);
2562 mbret = MessageBox(NULL, message, mbtitle,
2563 MB_ICONWARNING | MB_YESNO);
2564 if (mbret == IDNO)
2565 exit(0);
d4857987 2566 store_host_key(host, port, keytype, keystr);
de3df031 2567 }
de3df031 2568}