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