More svn:ignores. I'm constantly amazed that I keep not having put
[u/mdw/putty] / config.c
CommitLineData
fe8abbf4 1/*
2 * config.c - the platform-independent parts of the PuTTY
3 * configuration box.
4 */
5
6#include <assert.h>
7#include <stdlib.h>
8
9#include "putty.h"
10#include "dialog.h"
11#include "storage.h"
12
13#define PRINTER_DISABLED_STRING "None (printing disabled)"
14
7374c779 15#define HOST_BOX_TITLE "Host Name (or IP address)"
16#define PORT_BOX_TITLE "Port"
17
9ad36e5f 18/*
19 * Convenience function: determine whether this binary supports a
20 * given backend.
21 */
22static int have_backend(int protocol)
23{
24 struct backend_list *p = backends;
25 for (p = backends; p->name; p++) {
26 if (p->protocol == protocol)
27 return 1;
28 }
29 return 0;
30}
31
7374c779 32static void config_host_handler(union control *ctrl, void *dlg,
33 void *data, int event)
34{
35 Config *cfg = (Config *)data;
36
37 /*
38 * This function works just like the standard edit box handler,
39 * only it has to choose the control's label and text from two
40 * different places depending on the protocol.
41 */
42 if (event == EVENT_REFRESH) {
43 if (cfg->protocol == PROT_SERIAL) {
44 /*
45 * This label text is carefully chosen to contain an n,
46 * since that's the shortcut for the host name control.
47 */
48 dlg_label_change(ctrl, dlg, "Serial line");
49 dlg_editbox_set(ctrl, dlg, cfg->serline);
50 } else {
51 dlg_label_change(ctrl, dlg, HOST_BOX_TITLE);
52 dlg_editbox_set(ctrl, dlg, cfg->host);
53 }
54 } else if (event == EVENT_VALCHANGE) {
55 if (cfg->protocol == PROT_SERIAL)
56 dlg_editbox_get(ctrl, dlg, cfg->serline, lenof(cfg->serline));
57 else
58 dlg_editbox_get(ctrl, dlg, cfg->host, lenof(cfg->host));
59 }
60}
61
62static void config_port_handler(union control *ctrl, void *dlg,
63 void *data, int event)
64{
65 Config *cfg = (Config *)data;
66 char buf[80];
67
68 /*
69 * This function works just like the standard edit box handler,
70 * only it has to choose the control's label and text from two
71 * different places depending on the protocol.
72 */
73 if (event == EVENT_REFRESH) {
74 if (cfg->protocol == PROT_SERIAL) {
75 /*
76 * This label text is carefully chosen to contain a p,
77 * since that's the shortcut for the port control.
78 */
79 dlg_label_change(ctrl, dlg, "Speed");
80 sprintf(buf, "%d", cfg->serspeed);
81 } else {
82 dlg_label_change(ctrl, dlg, PORT_BOX_TITLE);
83 sprintf(buf, "%d", cfg->port);
84 }
85 dlg_editbox_set(ctrl, dlg, buf);
86 } else if (event == EVENT_VALCHANGE) {
87 dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
88 if (cfg->protocol == PROT_SERIAL)
89 cfg->serspeed = atoi(buf);
90 else
91 cfg->port = atoi(buf);
92 }
93}
94
95struct hostport {
96 union control *host, *port;
97};
98
99/*
100 * We export this function so that platform-specific config
101 * routines can use it to conveniently identify the protocol radio
102 * buttons in order to add to them.
103 */
104void config_protocolbuttons_handler(union control *ctrl, void *dlg,
fe8abbf4 105 void *data, int event)
106{
107 int button, defport;
108 Config *cfg = (Config *)data;
7374c779 109 struct hostport *hp = (struct hostport *)ctrl->radio.context.p;
110
fe8abbf4 111 /*
112 * This function works just like the standard radio-button
113 * handler, except that it also has to change the setting of
7374c779 114 * the port box, and refresh both host and port boxes when. We
115 * expect the context parameter to point at a hostport
116 * structure giving the `union control's for both.
fe8abbf4 117 */
118 if (event == EVENT_REFRESH) {
119 for (button = 0; button < ctrl->radio.nbuttons; button++)
120 if (cfg->protocol == ctrl->radio.buttondata[button].i)
121 break;
122 /* We expected that `break' to happen, in all circumstances. */
123 assert(button < ctrl->radio.nbuttons);
124 dlg_radiobutton_set(ctrl, dlg, button);
125 } else if (event == EVENT_VALCHANGE) {
126 int oldproto = cfg->protocol;
127 button = dlg_radiobutton_get(ctrl, dlg);
128 assert(button >= 0 && button < ctrl->radio.nbuttons);
129 cfg->protocol = ctrl->radio.buttondata[button].i;
130 if (oldproto != cfg->protocol) {
131 defport = -1;
132 switch (cfg->protocol) {
133 case PROT_SSH: defport = 22; break;
134 case PROT_TELNET: defport = 23; break;
135 case PROT_RLOGIN: defport = 513; break;
136 }
137 if (defport > 0 && cfg->port != defport) {
138 cfg->port = defport;
fe8abbf4 139 }
140 }
7374c779 141 dlg_refresh(hp->host, dlg);
142 dlg_refresh(hp->port, dlg);
fe8abbf4 143 }
144}
145
17556692 146static void loggingbuttons_handler(union control *ctrl, void *dlg,
147 void *data, int event)
148{
149 int button;
150 Config *cfg = (Config *)data;
151 /* This function works just like the standard radio-button handler,
152 * but it has to fall back to "no logging" in situations where the
153 * configured logging type isn't applicable.
154 */
155 if (event == EVENT_REFRESH) {
156 for (button = 0; button < ctrl->radio.nbuttons; button++)
157 if (cfg->logtype == ctrl->radio.buttondata[button].i)
158 break;
159
160 /* We fell off the end, so we lack the configured logging type */
161 if (button == ctrl->radio.nbuttons) {
162 button=0;
163 cfg->logtype=LGTYP_NONE;
164 }
165 dlg_radiobutton_set(ctrl, dlg, button);
166 } else if (event == EVENT_VALCHANGE) {
167 button = dlg_radiobutton_get(ctrl, dlg);
168 assert(button >= 0 && button < ctrl->radio.nbuttons);
169 cfg->logtype = ctrl->radio.buttondata[button].i;
170 }
171}
172
fe8abbf4 173static void numeric_keypad_handler(union control *ctrl, void *dlg,
174 void *data, int event)
175{
176 int button;
177 Config *cfg = (Config *)data;
178 /*
179 * This function works much like the standard radio button
180 * handler, but it has to handle two fields in Config.
181 */
182 if (event == EVENT_REFRESH) {
183 if (cfg->nethack_keypad)
184 button = 2;
185 else if (cfg->app_keypad)
186 button = 1;
187 else
188 button = 0;
189 assert(button < ctrl->radio.nbuttons);
190 dlg_radiobutton_set(ctrl, dlg, button);
191 } else if (event == EVENT_VALCHANGE) {
192 button = dlg_radiobutton_get(ctrl, dlg);
193 assert(button >= 0 && button < ctrl->radio.nbuttons);
194 if (button == 2) {
195 cfg->app_keypad = FALSE;
196 cfg->nethack_keypad = TRUE;
197 } else {
198 cfg->app_keypad = (button != 0);
199 cfg->nethack_keypad = FALSE;
200 }
201 }
202}
203
204static void cipherlist_handler(union control *ctrl, void *dlg,
205 void *data, int event)
206{
207 Config *cfg = (Config *)data;
208 if (event == EVENT_REFRESH) {
209 int i;
210
211 static const struct { char *s; int c; } ciphers[] = {
212 { "3DES", CIPHER_3DES },
213 { "Blowfish", CIPHER_BLOWFISH },
214 { "DES", CIPHER_DES },
2e85c969 215 { "AES (SSH-2 only)", CIPHER_AES },
a2add208 216 { "Arcfour (SSH-2 only)", CIPHER_ARCFOUR },
fe8abbf4 217 { "-- warn below here --", CIPHER_WARN }
218 };
219
220 /* Set up the "selected ciphers" box. */
221 /* (cipherlist assumed to contain all ciphers) */
222 dlg_update_start(ctrl, dlg);
223 dlg_listbox_clear(ctrl, dlg);
224 for (i = 0; i < CIPHER_MAX; i++) {
225 int c = cfg->ssh_cipherlist[i];
226 int j;
227 char *cstr = NULL;
228 for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
229 if (ciphers[j].c == c) {
230 cstr = ciphers[j].s;
231 break;
232 }
233 }
4eaff8d4 234 dlg_listbox_addwithid(ctrl, dlg, cstr, c);
fe8abbf4 235 }
236 dlg_update_done(ctrl, dlg);
237
238 } else if (event == EVENT_VALCHANGE) {
239 int i;
240
241 /* Update array to match the list box. */
242 for (i=0; i < CIPHER_MAX; i++)
243 cfg->ssh_cipherlist[i] = dlg_listbox_getid(ctrl, dlg, i);
244
245 }
246}
247
83e7d008 248static void kexlist_handler(union control *ctrl, void *dlg,
249 void *data, int event)
250{
251 Config *cfg = (Config *)data;
252 if (event == EVENT_REFRESH) {
253 int i;
254
255 static const struct { char *s; int k; } kexes[] = {
256 { "Diffie-Hellman group 1", KEX_DHGROUP1 },
257 { "Diffie-Hellman group 14", KEX_DHGROUP14 },
258 { "Diffie-Hellman group exchange", KEX_DHGEX },
259 { "-- warn below here --", KEX_WARN }
260 };
261
262 /* Set up the "kex preference" box. */
263 /* (kexlist assumed to contain all algorithms) */
264 dlg_update_start(ctrl, dlg);
265 dlg_listbox_clear(ctrl, dlg);
266 for (i = 0; i < KEX_MAX; i++) {
267 int k = cfg->ssh_kexlist[i];
268 int j;
269 char *kstr = NULL;
270 for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) {
271 if (kexes[j].k == k) {
272 kstr = kexes[j].s;
273 break;
274 }
275 }
276 dlg_listbox_addwithid(ctrl, dlg, kstr, k);
277 }
278 dlg_update_done(ctrl, dlg);
279
280 } else if (event == EVENT_VALCHANGE) {
281 int i;
282
283 /* Update array to match the list box. */
284 for (i=0; i < KEX_MAX; i++)
285 cfg->ssh_kexlist[i] = dlg_listbox_getid(ctrl, dlg, i);
286
287 }
288}
289
fe8abbf4 290static void printerbox_handler(union control *ctrl, void *dlg,
291 void *data, int event)
292{
293 Config *cfg = (Config *)data;
294 if (event == EVENT_REFRESH) {
295 int nprinters, i;
296 printer_enum *pe;
297
298 dlg_update_start(ctrl, dlg);
0f915619 299 /*
300 * Some backends may wish to disable the drop-down list on
301 * this edit box. Be prepared for this.
302 */
303 if (ctrl->editbox.has_list) {
304 dlg_listbox_clear(ctrl, dlg);
305 dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING);
306 pe = printer_start_enum(&nprinters);
307 for (i = 0; i < nprinters; i++)
308 dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i));
309 printer_finish_enum(pe);
310 }
fe8abbf4 311 dlg_editbox_set(ctrl, dlg,
312 (*cfg->printer ? cfg->printer :
313 PRINTER_DISABLED_STRING));
314 dlg_update_done(ctrl, dlg);
315 } else if (event == EVENT_VALCHANGE) {
316 dlg_editbox_get(ctrl, dlg, cfg->printer, sizeof(cfg->printer));
317 if (!strcmp(cfg->printer, PRINTER_DISABLED_STRING))
318 *cfg->printer = '\0';
319 }
320}
321
322static void codepage_handler(union control *ctrl, void *dlg,
323 void *data, int event)
324{
325 Config *cfg = (Config *)data;
326 if (event == EVENT_REFRESH) {
327 int i;
d4413bd2 328 const char *cp;
fe8abbf4 329 dlg_update_start(ctrl, dlg);
330 strcpy(cfg->line_codepage,
331 cp_name(decode_codepage(cfg->line_codepage)));
332 dlg_listbox_clear(ctrl, dlg);
333 for (i = 0; (cp = cp_enumerate(i)) != NULL; i++)
334 dlg_listbox_add(ctrl, dlg, cp);
335 dlg_editbox_set(ctrl, dlg, cfg->line_codepage);
336 dlg_update_done(ctrl, dlg);
337 } else if (event == EVENT_VALCHANGE) {
338 dlg_editbox_get(ctrl, dlg, cfg->line_codepage,
339 sizeof(cfg->line_codepage));
340 strcpy(cfg->line_codepage,
341 cp_name(decode_codepage(cfg->line_codepage)));
342 }
343}
344
345static void sshbug_handler(union control *ctrl, void *dlg,
346 void *data, int event)
347{
348 if (event == EVENT_REFRESH) {
349 dlg_update_start(ctrl, dlg);
350 dlg_listbox_clear(ctrl, dlg);
4eaff8d4 351 dlg_listbox_addwithid(ctrl, dlg, "Auto", AUTO);
352 dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF);
353 dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON);
fe8abbf4 354 switch (*(int *)ATOFFSET(data, ctrl->listbox.context.i)) {
355 case AUTO: dlg_listbox_select(ctrl, dlg, 0); break;
356 case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break;
357 case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break;
358 }
359 dlg_update_done(ctrl, dlg);
360 } else if (event == EVENT_SELCHANGE) {
361 int i = dlg_listbox_index(ctrl, dlg);
362 if (i < 0)
363 i = AUTO;
364 else
365 i = dlg_listbox_getid(ctrl, dlg, i);
366 *(int *)ATOFFSET(data, ctrl->listbox.context.i) = i;
367 }
368}
369
4e6d4091 370#define SAVEDSESSION_LEN 2048
371
fe8abbf4 372struct sessionsaver_data {
373 union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
374 union control *okbutton, *cancelbutton;
12745e35 375 struct sesslist sesslist;
2e155f47 376 int midsession;
fe8abbf4 377};
378
379/*
380 * Helper function to load the session selected in the list box, if
381 * any, as this is done in more than one place below. Returns 0 for
382 * failure.
383 */
384static int load_selected_session(struct sessionsaver_data *ssd,
4e6d4091 385 char *savedsession,
fe8abbf4 386 void *dlg, Config *cfg)
387{
388 int i = dlg_listbox_index(ssd->listbox, dlg);
389 int isdef;
390 if (i < 0) {
391 dlg_beep(dlg);
392 return 0;
393 }
12745e35 394 isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
395 load_settings(ssd->sesslist.sessions[i], !isdef, cfg);
fe8abbf4 396 if (!isdef) {
12745e35 397 strncpy(savedsession, ssd->sesslist.sessions[i],
4e6d4091 398 SAVEDSESSION_LEN);
399 savedsession[SAVEDSESSION_LEN-1] = '\0';
fe8abbf4 400 } else {
4e6d4091 401 savedsession[0] = '\0';
fe8abbf4 402 }
403 dlg_refresh(NULL, dlg);
404 /* Restore the selection, which might have been clobbered by
405 * changing the value of the edit box. */
406 dlg_listbox_select(ssd->listbox, dlg, i);
407 return 1;
408}
409
410static void sessionsaver_handler(union control *ctrl, void *dlg,
411 void *data, int event)
412{
413 Config *cfg = (Config *)data;
414 struct sessionsaver_data *ssd =
415 (struct sessionsaver_data *)ctrl->generic.context.p;
4e6d4091 416 char *savedsession;
417
418 /*
419 * The first time we're called in a new dialog, we must
420 * allocate space to store the current contents of the saved
421 * session edit box (since it must persist even when we switch
422 * panels, but is not part of the Config).
423 */
56b9b9a7 424 if (!ssd->editbox) {
425 savedsession = NULL;
426 } else if (!dlg_get_privdata(ssd->editbox, dlg)) {
4e6d4091 427 savedsession = (char *)
428 dlg_alloc_privdata(ssd->editbox, dlg, SAVEDSESSION_LEN);
429 savedsession[0] = '\0';
430 } else {
431 savedsession = dlg_get_privdata(ssd->editbox, dlg);
432 }
fe8abbf4 433
434 if (event == EVENT_REFRESH) {
435 if (ctrl == ssd->editbox) {
4e6d4091 436 dlg_editbox_set(ctrl, dlg, savedsession);
fe8abbf4 437 } else if (ctrl == ssd->listbox) {
438 int i;
439 dlg_update_start(ctrl, dlg);
440 dlg_listbox_clear(ctrl, dlg);
12745e35 441 for (i = 0; i < ssd->sesslist.nsessions; i++)
442 dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]);
fe8abbf4 443 dlg_update_done(ctrl, dlg);
444 }
445 } else if (event == EVENT_VALCHANGE) {
dcfd0728 446 int top, bottom, halfway, i;
fe8abbf4 447 if (ctrl == ssd->editbox) {
4e6d4091 448 dlg_editbox_get(ctrl, dlg, savedsession,
449 SAVEDSESSION_LEN);
dcfd0728 450 top = ssd->sesslist.nsessions;
451 bottom = -1;
452 while (top-bottom > 1) {
453 halfway = (top+bottom)/2;
454 i = strcmp(savedsession, ssd->sesslist.sessions[halfway]);
455 if (i <= 0 ) {
456 top = halfway;
457 } else {
458 bottom = halfway;
459 }
460 }
461 if (top == ssd->sesslist.nsessions) {
462 top -= 1;
463 }
464 dlg_listbox_select(ssd->listbox, dlg, top);
fe8abbf4 465 }
466 } else if (event == EVENT_ACTION) {
2e155f47 467 if (!ssd->midsession &&
468 (ctrl == ssd->listbox ||
469 (ssd->loadbutton && ctrl == ssd->loadbutton))) {
fe8abbf4 470 /*
471 * The user has double-clicked a session, or hit Load.
472 * We must load the selected session, and then
473 * terminate the configuration dialog _if_ there was a
474 * double-click on the list box _and_ that session
475 * contains a hostname.
476 */
4e6d4091 477 if (load_selected_session(ssd, savedsession, dlg, cfg) &&
7374c779 478 (ctrl == ssd->listbox && cfg_launchable(cfg))) {
fe8abbf4 479 dlg_end(dlg, 1); /* it's all over, and succeeded */
480 }
481 } else if (ctrl == ssd->savebutton) {
4e6d4091 482 int isdef = !strcmp(savedsession, "Default Settings");
483 if (!savedsession[0]) {
8b0cb5aa 484 int i = dlg_listbox_index(ssd->listbox, dlg);
fe8abbf4 485 if (i < 0) {
486 dlg_beep(dlg);
487 return;
488 }
12745e35 489 isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
fe8abbf4 490 if (!isdef) {
12745e35 491 strncpy(savedsession, ssd->sesslist.sessions[i],
4e6d4091 492 SAVEDSESSION_LEN);
493 savedsession[SAVEDSESSION_LEN-1] = '\0';
fe8abbf4 494 } else {
4e6d4091 495 savedsession[0] = '\0';
fe8abbf4 496 }
497 }
3f935d5b 498 {
499 char *errmsg = save_settings(savedsession, !isdef, cfg);
500 if (errmsg) {
501 dlg_error_msg(dlg, errmsg);
502 sfree(errmsg);
503 }
504 }
12745e35 505 get_sesslist(&ssd->sesslist, FALSE);
506 get_sesslist(&ssd->sesslist, TRUE);
fe8abbf4 507 dlg_refresh(ssd->editbox, dlg);
508 dlg_refresh(ssd->listbox, dlg);
2e155f47 509 } else if (!ssd->midsession &&
510 ssd->delbutton && ctrl == ssd->delbutton) {
6f87d111 511 int i = dlg_listbox_index(ssd->listbox, dlg);
fe8abbf4 512 if (i <= 0) {
513 dlg_beep(dlg);
514 } else {
12745e35 515 del_settings(ssd->sesslist.sessions[i]);
516 get_sesslist(&ssd->sesslist, FALSE);
517 get_sesslist(&ssd->sesslist, TRUE);
fe8abbf4 518 dlg_refresh(ssd->listbox, dlg);
519 }
520 } else if (ctrl == ssd->okbutton) {
2e155f47 521 if (ssd->midsession) {
56b9b9a7 522 /* In a mid-session Change Settings, Apply is always OK. */
523 dlg_end(dlg, 1);
524 return;
525 }
fe8abbf4 526 /*
527 * Annoying special case. If the `Open' button is
528 * pressed while no host name is currently set, _and_
529 * the session list previously had the focus, _and_
530 * there was a session selected in that which had a
531 * valid host name in it, then load it and go.
532 */
7374c779 533 if (dlg_last_focused(ctrl, dlg) == ssd->listbox &&
534 !cfg_launchable(cfg)) {
fe8abbf4 535 Config cfg2;
4e6d4091 536 if (!load_selected_session(ssd, savedsession, dlg, &cfg2)) {
fe8abbf4 537 dlg_beep(dlg);
538 return;
539 }
540 /* If at this point we have a valid session, go! */
541 if (*cfg2.host) {
542 *cfg = cfg2; /* structure copy */
04c52f10 543 cfg->remote_cmd_ptr = NULL;
fe8abbf4 544 dlg_end(dlg, 1);
545 } else
546 dlg_beep(dlg);
431c0a12 547 return;
fe8abbf4 548 }
549
550 /*
551 * Otherwise, do the normal thing: if we have a valid
552 * session, get going.
553 */
7374c779 554 if (cfg_launchable(cfg)) {
fe8abbf4 555 dlg_end(dlg, 1);
556 } else
557 dlg_beep(dlg);
558 } else if (ctrl == ssd->cancelbutton) {
559 dlg_end(dlg, 0);
560 }
561 }
562}
563
564struct charclass_data {
565 union control *listbox, *editbox, *button;
566};
567
568static void charclass_handler(union control *ctrl, void *dlg,
569 void *data, int event)
570{
571 Config *cfg = (Config *)data;
572 struct charclass_data *ccd =
573 (struct charclass_data *)ctrl->generic.context.p;
574
575 if (event == EVENT_REFRESH) {
576 if (ctrl == ccd->listbox) {
577 int i;
578 dlg_update_start(ctrl, dlg);
579 dlg_listbox_clear(ctrl, dlg);
580 for (i = 0; i < 128; i++) {
581 char str[100];
582 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
583 (i >= 0x21 && i != 0x7F) ? i : ' ', cfg->wordness[i]);
584 dlg_listbox_add(ctrl, dlg, str);
585 }
586 dlg_update_done(ctrl, dlg);
587 }
588 } else if (event == EVENT_ACTION) {
589 if (ctrl == ccd->button) {
590 char str[100];
591 int i, n;
592 dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str));
593 n = atoi(str);
594 for (i = 0; i < 128; i++) {
595 if (dlg_listbox_issel(ccd->listbox, dlg, i))
596 cfg->wordness[i] = n;
597 }
598 dlg_refresh(ccd->listbox, dlg);
599 }
600 }
601}
602
603struct colour_data {
18c2f87c 604 union control *listbox, *redit, *gedit, *bedit, *button;
fe8abbf4 605};
606
607static const char *const colours[] = {
608 "Default Foreground", "Default Bold Foreground",
609 "Default Background", "Default Bold Background",
610 "Cursor Text", "Cursor Colour",
611 "ANSI Black", "ANSI Black Bold",
612 "ANSI Red", "ANSI Red Bold",
613 "ANSI Green", "ANSI Green Bold",
614 "ANSI Yellow", "ANSI Yellow Bold",
615 "ANSI Blue", "ANSI Blue Bold",
616 "ANSI Magenta", "ANSI Magenta Bold",
617 "ANSI Cyan", "ANSI Cyan Bold",
618 "ANSI White", "ANSI White Bold"
619};
620
621static void colour_handler(union control *ctrl, void *dlg,
622 void *data, int event)
623{
624 Config *cfg = (Config *)data;
625 struct colour_data *cd =
626 (struct colour_data *)ctrl->generic.context.p;
627 int update = FALSE, r, g, b;
628
629 if (event == EVENT_REFRESH) {
630 if (ctrl == cd->listbox) {
631 int i;
632 dlg_update_start(ctrl, dlg);
633 dlg_listbox_clear(ctrl, dlg);
634 for (i = 0; i < lenof(colours); i++)
635 dlg_listbox_add(ctrl, dlg, colours[i]);
636 dlg_update_done(ctrl, dlg);
18c2f87c 637 dlg_editbox_set(cd->redit, dlg, "");
638 dlg_editbox_set(cd->gedit, dlg, "");
639 dlg_editbox_set(cd->bedit, dlg, "");
fe8abbf4 640 }
641 } else if (event == EVENT_SELCHANGE) {
642 if (ctrl == cd->listbox) {
643 /* The user has selected a colour. Update the RGB text. */
644 int i = dlg_listbox_index(ctrl, dlg);
645 if (i < 0) {
646 dlg_beep(dlg);
647 return;
648 }
649 r = cfg->colours[i][0];
650 g = cfg->colours[i][1];
651 b = cfg->colours[i][2];
652 update = TRUE;
653 }
18c2f87c 654 } else if (event == EVENT_VALCHANGE) {
655 if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) {
656 /* The user has changed the colour using the edit boxes. */
657 char buf[80];
658 int i, cval;
659
660 dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
3d025d91 661 cval = atoi(buf);
662 if (cval > 255) cval = 255;
663 if (cval < 0) cval = 0;
18c2f87c 664
665 i = dlg_listbox_index(cd->listbox, dlg);
666 if (i >= 0) {
667 if (ctrl == cd->redit)
668 cfg->colours[i][0] = cval;
669 else if (ctrl == cd->gedit)
670 cfg->colours[i][1] = cval;
671 else if (ctrl == cd->bedit)
672 cfg->colours[i][2] = cval;
673 }
674 }
fe8abbf4 675 } else if (event == EVENT_ACTION) {
676 if (ctrl == cd->button) {
677 int i = dlg_listbox_index(cd->listbox, dlg);
678 if (i < 0) {
679 dlg_beep(dlg);
680 return;
681 }
682 /*
683 * Start a colour selector, which will send us an
684 * EVENT_CALLBACK when it's finished and allow us to
685 * pick up the results.
686 */
687 dlg_coloursel_start(ctrl, dlg,
688 cfg->colours[i][0],
689 cfg->colours[i][1],
690 cfg->colours[i][2]);
691 }
692 } else if (event == EVENT_CALLBACK) {
693 if (ctrl == cd->button) {
694 int i = dlg_listbox_index(cd->listbox, dlg);
695 /*
696 * Collect the results of the colour selector. Will
697 * return nonzero on success, or zero if the colour
698 * selector did nothing (user hit Cancel, for example).
699 */
700 if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
701 cfg->colours[i][0] = r;
702 cfg->colours[i][1] = g;
703 cfg->colours[i][2] = b;
704 update = TRUE;
705 }
706 }
707 }
708
709 if (update) {
710 char buf[40];
18c2f87c 711 sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
712 sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
713 sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
fe8abbf4 714 }
715}
716
c6ccd5c2 717struct ttymodes_data {
718 union control *modelist, *valradio, *valbox;
719 union control *addbutton, *rembutton, *listbox;
720};
721
722static void ttymodes_handler(union control *ctrl, void *dlg,
723 void *data, int event)
724{
725 Config *cfg = (Config *)data;
726 struct ttymodes_data *td =
727 (struct ttymodes_data *)ctrl->generic.context.p;
728
729 if (event == EVENT_REFRESH) {
730 if (ctrl == td->listbox) {
731 char *p = cfg->ttymodes;
732 dlg_update_start(ctrl, dlg);
733 dlg_listbox_clear(ctrl, dlg);
734 while (*p) {
735 int tabpos = strchr(p, '\t') - p;
736 char *disp = dupprintf("%.*s\t%s", tabpos, p,
737 (p[tabpos+1] == 'A') ? "(auto)" :
738 p+tabpos+2);
739 dlg_listbox_add(ctrl, dlg, disp);
740 p += strlen(p) + 1;
741 sfree(disp);
742 }
743 dlg_update_done(ctrl, dlg);
744 } else if (ctrl == td->modelist) {
745 int i;
746 dlg_update_start(ctrl, dlg);
747 dlg_listbox_clear(ctrl, dlg);
748 for (i = 0; ttymodes[i]; i++)
749 dlg_listbox_add(ctrl, dlg, ttymodes[i]);
750 dlg_listbox_select(ctrl, dlg, 0); /* *shrug* */
751 dlg_update_done(ctrl, dlg);
752 } else if (ctrl == td->valradio) {
753 dlg_radiobutton_set(ctrl, dlg, 0);
754 }
755 } else if (event == EVENT_ACTION) {
756 if (ctrl == td->addbutton) {
757 int ind = dlg_listbox_index(td->modelist, dlg);
758 if (ind >= 0) {
759 char type = dlg_radiobutton_get(td->valradio, dlg) ? 'V' : 'A';
760 int slen, left;
761 char *p, str[lenof(cfg->ttymodes)];
762 /* Construct new entry */
763 memset(str, 0, lenof(str));
764 strncpy(str, ttymodes[ind], lenof(str)-3);
765 slen = strlen(str);
766 str[slen] = '\t';
767 str[slen+1] = type;
768 slen += 2;
769 if (type == 'V') {
770 dlg_editbox_get(td->valbox, dlg, str+slen, lenof(str)-slen);
771 }
772 /* Find end of list, deleting any existing instance */
773 p = cfg->ttymodes;
774 left = lenof(cfg->ttymodes);
775 while (*p) {
776 int t = strchr(p, '\t') - p;
777 if (t == strlen(ttymodes[ind]) &&
778 strncmp(p, ttymodes[ind], t) == 0) {
779 memmove(p, p+strlen(p)+1, left - (strlen(p)+1));
780 continue;
781 }
782 left -= strlen(p) + 1;
783 p += strlen(p) + 1;
784 }
785 /* Append new entry */
786 memset(p, 0, left);
787 strncpy(p, str, left - 2);
788 dlg_refresh(td->listbox, dlg);
789 } else
790 dlg_beep(dlg);
791 } else if (ctrl == td->rembutton) {
792 char *p = cfg->ttymodes;
793 int i = 0, len = lenof(cfg->ttymodes);
794 while (*p) {
795 if (dlg_listbox_issel(td->listbox, dlg, i)) {
796 memmove(p, p+strlen(p)+1, len - (strlen(p)+1));
797 i++;
798 continue;
799 }
800 len -= strlen(p) + 1;
801 p += strlen(p) + 1;
802 i++;
803 }
804 memset(p, 0, lenof(cfg->ttymodes) - len);
805 dlg_refresh(td->listbox, dlg);
806 }
807 }
808}
809
fe8abbf4 810struct environ_data {
811 union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
812};
813
814static void environ_handler(union control *ctrl, void *dlg,
815 void *data, int event)
816{
817 Config *cfg = (Config *)data;
818 struct environ_data *ed =
819 (struct environ_data *)ctrl->generic.context.p;
820
821 if (event == EVENT_REFRESH) {
822 if (ctrl == ed->listbox) {
823 char *p = cfg->environmt;
824 dlg_update_start(ctrl, dlg);
825 dlg_listbox_clear(ctrl, dlg);
826 while (*p) {
827 dlg_listbox_add(ctrl, dlg, p);
828 p += strlen(p) + 1;
829 }
830 dlg_update_done(ctrl, dlg);
831 }
832 } else if (event == EVENT_ACTION) {
833 if (ctrl == ed->addbutton) {
834 char str[sizeof(cfg->environmt)];
835 char *p;
836 dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1);
837 if (!*str) {
838 dlg_beep(dlg);
839 return;
840 }
841 p = str + strlen(str);
842 *p++ = '\t';
843 dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str));
844 if (!*p) {
845 dlg_beep(dlg);
846 return;
847 }
848 p = cfg->environmt;
849 while (*p) {
850 while (*p)
851 p++;
852 p++;
853 }
854 if ((p - cfg->environmt) + strlen(str) + 2 <
855 sizeof(cfg->environmt)) {
856 strcpy(p, str);
857 p[strlen(str) + 1] = '\0';
858 dlg_listbox_add(ed->listbox, dlg, str);
859 dlg_editbox_set(ed->varbox, dlg, "");
860 dlg_editbox_set(ed->valbox, dlg, "");
861 } else {
862 dlg_error_msg(dlg, "Environment too big");
863 }
864 } else if (ctrl == ed->rembutton) {
865 int i = dlg_listbox_index(ed->listbox, dlg);
866 if (i < 0) {
867 dlg_beep(dlg);
868 } else {
869 char *p, *q;
870
871 dlg_listbox_del(ed->listbox, dlg, i);
872 p = cfg->environmt;
873 while (i > 0) {
874 if (!*p)
875 goto disaster;
876 while (*p)
877 p++;
878 p++;
879 i--;
880 }
881 q = p;
882 if (!*p)
883 goto disaster;
884 while (*p)
885 p++;
886 p++;
887 while (*p) {
888 while (*p)
889 *q++ = *p++;
890 *q++ = *p++;
891 }
892 *q = '\0';
893 disaster:;
894 }
895 }
896 }
897}
898
899struct portfwd_data {
900 union control *addbutton, *rembutton, *listbox;
901 union control *sourcebox, *destbox, *direction;
89adc0e2 902#ifndef NO_IPV6
05581745 903 union control *addressfamily;
89adc0e2 904#endif
fe8abbf4 905};
906
907static void portfwd_handler(union control *ctrl, void *dlg,
908 void *data, int event)
909{
910 Config *cfg = (Config *)data;
911 struct portfwd_data *pfd =
912 (struct portfwd_data *)ctrl->generic.context.p;
913
914 if (event == EVENT_REFRESH) {
915 if (ctrl == pfd->listbox) {
916 char *p = cfg->portfwd;
917 dlg_update_start(ctrl, dlg);
918 dlg_listbox_clear(ctrl, dlg);
919 while (*p) {
920 dlg_listbox_add(ctrl, dlg, p);
921 p += strlen(p) + 1;
922 }
923 dlg_update_done(ctrl, dlg);
07e4d76d 924 } else if (ctrl == pfd->direction) {
925 /*
926 * Default is Local.
927 */
928 dlg_radiobutton_set(ctrl, dlg, 0);
89adc0e2 929#ifndef NO_IPV6
930 } else if (ctrl == pfd->addressfamily) {
05581745 931 dlg_radiobutton_set(ctrl, dlg, 0);
89adc0e2 932#endif
fe8abbf4 933 }
934 } else if (event == EVENT_ACTION) {
935 if (ctrl == pfd->addbutton) {
936 char str[sizeof(cfg->portfwd)];
937 char *p;
05581745 938 int i, type;
939 int whichbutton;
940
941 i = 0;
89adc0e2 942#ifndef NO_IPV6
05581745 943 whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
944 if (whichbutton == 1)
945 str[i++] = '4';
946 else if (whichbutton == 2)
947 str[i++] = '6';
89adc0e2 948#endif
05581745 949
950 whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
820ebe3b 951 if (whichbutton == 0)
05581745 952 type = 'L';
820ebe3b 953 else if (whichbutton == 1)
05581745 954 type = 'R';
820ebe3b 955 else
05581745 956 type = 'D';
957 str[i++] = type;
958
959 dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i);
94042edc 960 if (!str[i]) {
fe8abbf4 961 dlg_error_msg(dlg, "You need to specify a source port number");
962 return;
963 }
964 p = str + strlen(str);
05581745 965 if (type != 'D') {
820ebe3b 966 *p++ = '\t';
967 dlg_editbox_get(pfd->destbox, dlg, p,
e49c58ed 968 sizeof(str) - (p - str));
820ebe3b 969 if (!*p || !strchr(p, ':')) {
970 dlg_error_msg(dlg,
971 "You need to specify a destination address\n"
972 "in the form \"host.name:port\"");
973 return;
974 }
975 } else
976 *p = '\0';
fe8abbf4 977 p = cfg->portfwd;
978 while (*p) {
979 while (*p)
980 p++;
981 p++;
982 }
e49c58ed 983 if ((p - cfg->portfwd) + strlen(str) + 2 <=
fe8abbf4 984 sizeof(cfg->portfwd)) {
985 strcpy(p, str);
986 p[strlen(str) + 1] = '\0';
987 dlg_listbox_add(pfd->listbox, dlg, str);
988 dlg_editbox_set(pfd->sourcebox, dlg, "");
989 dlg_editbox_set(pfd->destbox, dlg, "");
990 } else {
991 dlg_error_msg(dlg, "Too many forwardings");
992 }
993 } else if (ctrl == pfd->rembutton) {
994 int i = dlg_listbox_index(pfd->listbox, dlg);
995 if (i < 0)
996 dlg_beep(dlg);
997 else {
998 char *p, *q;
999
1000 dlg_listbox_del(pfd->listbox, dlg, i);
1001 p = cfg->portfwd;
1002 while (i > 0) {
1003 if (!*p)
1004 goto disaster2;
1005 while (*p)
1006 p++;
1007 p++;
1008 i--;
1009 }
1010 q = p;
1011 if (!*p)
1012 goto disaster2;
1013 while (*p)
1014 p++;
1015 p++;
1016 while (*p) {
1017 while (*p)
1018 *q++ = *p++;
1019 *q++ = *p++;
1020 }
1021 *q = '\0';
1022 disaster2:;
1023 }
1024 }
1025 }
1026}
1027
12745e35 1028void setup_config_box(struct controlbox *b, int midsession,
1029 int protocol, int protcfginfo)
fe8abbf4 1030{
1031 struct controlset *s;
1032 struct sessionsaver_data *ssd;
1033 struct charclass_data *ccd;
1034 struct colour_data *cd;
c6ccd5c2 1035 struct ttymodes_data *td;
fe8abbf4 1036 struct environ_data *ed;
1037 struct portfwd_data *pfd;
1038 union control *c;
f6f450e2 1039 char *str;
fe8abbf4 1040
1041 ssd = (struct sessionsaver_data *)
1042 ctrl_alloc(b, sizeof(struct sessionsaver_data));
56b9b9a7 1043 memset(ssd, 0, sizeof(*ssd));
2e155f47 1044 ssd->midsession = midsession;
fe8abbf4 1045
1046 /*
1047 * The standard panel that appears at the bottom of all panels:
1048 * Open, Cancel, Apply etc.
1049 */
1050 s = ctrl_getset(b, "", "", "");
1051 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
1052 ssd->okbutton = ctrl_pushbutton(s,
1053 (midsession ? "Apply" : "Open"),
1054 (char)(midsession ? 'a' : 'o'),
1055 HELPCTX(no_help),
1056 sessionsaver_handler, P(ssd));
1057 ssd->okbutton->button.isdefault = TRUE;
1058 ssd->okbutton->generic.column = 3;
1059 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
1060 sessionsaver_handler, P(ssd));
0bd8d76d 1061 ssd->cancelbutton->button.iscancel = TRUE;
fe8abbf4 1062 ssd->cancelbutton->generic.column = 4;
1063 /* We carefully don't close the 5-column part, so that platform-
1064 * specific add-ons can put extra buttons alongside Open and Cancel. */
1065
1066 /*
1067 * The Session panel.
1068 */
f6f450e2 1069 str = dupprintf("Basic options for your %s session", appname);
1070 ctrl_settitle(b, "Session", str);
1071 sfree(str);
fe8abbf4 1072
1073 if (!midsession) {
7374c779 1074 struct hostport *hp = (struct hostport *)
1075 ctrl_alloc(b, sizeof(struct hostport));
7374c779 1076
fe8abbf4 1077 s = ctrl_getset(b, "Session", "hostport",
7374c779 1078 "Specify the destination you want to connect to");
fe8abbf4 1079 ctrl_columns(s, 2, 75, 25);
7374c779 1080 c = ctrl_editbox(s, HOST_BOX_TITLE, 'n', 100,
fe8abbf4 1081 HELPCTX(session_hostname),
7374c779 1082 config_host_handler, I(0), I(0));
fe8abbf4 1083 c->generic.column = 0;
7374c779 1084 hp->host = c;
1085 c = ctrl_editbox(s, PORT_BOX_TITLE, 'p', 100,
1086 HELPCTX(session_hostname),
1087 config_port_handler, I(0), I(0));
fe8abbf4 1088 c->generic.column = 1;
7374c779 1089 hp->port = c;
fe8abbf4 1090 ctrl_columns(s, 1, 100);
7374c779 1091
9ad36e5f 1092 if (!have_backend(PROT_SSH)) {
7374c779 1093 ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 3,
fe8abbf4 1094 HELPCTX(session_hostname),
7374c779 1095 config_protocolbuttons_handler, P(hp),
fe8abbf4 1096 "Raw", 'r', I(PROT_RAW),
1097 "Telnet", 't', I(PROT_TELNET),
1098 "Rlogin", 'i', I(PROT_RLOGIN),
1099 NULL);
1100 } else {
7374c779 1101 ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 4,
fe8abbf4 1102 HELPCTX(session_hostname),
7374c779 1103 config_protocolbuttons_handler, P(hp),
fe8abbf4 1104 "Raw", 'r', I(PROT_RAW),
1105 "Telnet", 't', I(PROT_TELNET),
1106 "Rlogin", 'i', I(PROT_RLOGIN),
1107 "SSH", 's', I(PROT_SSH),
1108 NULL);
1109 }
fe8abbf4 1110 }
1111
48c4dd7c 1112 /*
1113 * The Load/Save panel is available even in mid-session.
1114 */
1115 s = ctrl_getset(b, "Session", "savedsessions",
59b8cd5a 1116 midsession ? "Save the current session settings" :
48c4dd7c 1117 "Load, save or delete a stored session");
1118 ctrl_columns(s, 2, 75, 25);
12745e35 1119 get_sesslist(&ssd->sesslist, TRUE);
48c4dd7c 1120 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
1121 HELPCTX(session_saved),
1122 sessionsaver_handler, P(ssd), P(NULL));
1123 ssd->editbox->generic.column = 0;
1124 /* Reset columns so that the buttons are alongside the list, rather
1125 * than alongside that edit box. */
1126 ctrl_columns(s, 1, 100);
1127 ctrl_columns(s, 2, 75, 25);
1128 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1129 HELPCTX(session_saved),
1130 sessionsaver_handler, P(ssd));
1131 ssd->listbox->generic.column = 0;
1132 ssd->listbox->listbox.height = 7;
2e155f47 1133 if (!midsession) {
1134 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
1135 HELPCTX(session_saved),
1136 sessionsaver_handler, P(ssd));
1137 ssd->loadbutton->generic.column = 1;
1138 } else {
1139 /* We can't offer the Load button mid-session, as it would allow the
1140 * user to load and subsequently save settings they can't see. (And
1141 * also change otherwise immutable settings underfoot; that probably
1142 * shouldn't be a problem, but.) */
1143 ssd->loadbutton = NULL;
1144 }
1145 /* "Save" button is permitted mid-session. */
48c4dd7c 1146 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
1147 HELPCTX(session_saved),
1148 sessionsaver_handler, P(ssd));
1149 ssd->savebutton->generic.column = 1;
2e155f47 1150 if (!midsession) {
1151 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
1152 HELPCTX(session_saved),
1153 sessionsaver_handler, P(ssd));
1154 ssd->delbutton->generic.column = 1;
1155 } else {
1156 /* Disable the Delete button mid-session too, for UI consistency. */
1157 ssd->delbutton = NULL;
1158 }
48c4dd7c 1159 ctrl_columns(s, 1, 100);
1160
fe8abbf4 1161 s = ctrl_getset(b, "Session", "otheropts", NULL);
1162 c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
1163 HELPCTX(session_coe),
1164 dlg_stdradiobutton_handler,
1165 I(offsetof(Config, close_on_exit)),
1166 "Always", I(FORCE_ON),
1167 "Never", I(FORCE_OFF),
1168 "Only on clean exit", I(AUTO), NULL);
1169
1170 /*
1171 * The Session/Logging panel.
1172 */
1173 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
1174
1175 s = ctrl_getset(b, "Session/Logging", "main", NULL);
3e547dd8 1176 /*
1177 * The logging buttons change depending on whether SSH packet
1178 * logging can sensibly be available.
1179 */
1180 {
bf8a49a1 1181 char *sshlogname, *sshrawlogname;
3e547dd8 1182 if ((midsession && protocol == PROT_SSH) ||
9ad36e5f 1183 (!midsession && have_backend(PROT_SSH))) {
bf8a49a1 1184 sshlogname = "SSH packets";
1185 sshrawlogname = "SSH packets and raw data";
1186 } else {
1187 sshlogname = NULL; /* this will disable both buttons */
1188 sshrawlogname = NULL; /* this will just placate optimisers */
1189 }
1190 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 2,
3e547dd8 1191 HELPCTX(logging_main),
17556692 1192 loggingbuttons_handler,
3e547dd8 1193 I(offsetof(Config, logtype)),
bf8a49a1 1194 "None", 't', I(LGTYP_NONE),
1195 "Printable output", 'p', I(LGTYP_ASCII),
1196 "All session output", 'l', I(LGTYP_DEBUG),
3e547dd8 1197 sshlogname, 's', I(LGTYP_PACKETS),
bf8a49a1 1198 sshrawlogname, 'r', I(LGTYP_SSHRAW),
3e547dd8 1199 NULL);
1200 }
fe8abbf4 1201 ctrl_filesel(s, "Log file name:", 'f',
1202 NULL, TRUE, "Select session log file name",
1203 HELPCTX(logging_filename),
1204 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
1205 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
1206 " &T for time, and &H for host name)",
1207 HELPCTX(logging_filename));
1208 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
1209 HELPCTX(logging_exists),
1210 dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
1211 "Always overwrite it", I(LGXF_OVR),
1212 "Always append to the end of it", I(LGXF_APN),
1213 "Ask the user every time", I(LGXF_ASK), NULL);
6d60c791 1214 ctrl_checkbox(s, "Flush log file frequently", 'u',
1215 HELPCTX(logging_flush),
1216 dlg_stdcheckbox_handler, I(offsetof(Config,logflush)));
fe8abbf4 1217
9a10ecf4 1218 if ((midsession && protocol == PROT_SSH) ||
9ad36e5f 1219 (!midsession && have_backend(PROT_SSH))) {
9a10ecf4 1220 s = ctrl_getset(b, "Session/Logging", "ssh",
1221 "Options specific to SSH packet logging");
1222 ctrl_checkbox(s, "Omit known password fields", 'k',
1223 HELPCTX(logging_ssh_omit_password),
1224 dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass)));
1225 ctrl_checkbox(s, "Omit session data", 'd',
1226 HELPCTX(logging_ssh_omit_data),
1227 dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata)));
1228 }
1229
fe8abbf4 1230 /*
1231 * The Terminal panel.
1232 */
1233 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
1234
1235 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
1236 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
1237 HELPCTX(terminal_autowrap),
1238 dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
1239 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
1240 HELPCTX(terminal_decom),
1241 dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
1242 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
1243 HELPCTX(terminal_lfhascr),
1244 dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
1245 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
1246 HELPCTX(terminal_bce),
1247 dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
1248 ctrl_checkbox(s, "Enable blinking text", 'n',
1249 HELPCTX(terminal_blink),
1250 dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
1251 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
1252 HELPCTX(terminal_answerback),
1253 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
1254 I(sizeof(((Config *)0)->answerback)));
1255
1256 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
1257 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
1258 HELPCTX(terminal_localecho),
1259 dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
1260 "Auto", I(AUTO),
1261 "Force on", I(FORCE_ON),
1262 "Force off", I(FORCE_OFF), NULL);
1263 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
1264 HELPCTX(terminal_localedit),
1265 dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
1266 "Auto", I(AUTO),
1267 "Force on", I(FORCE_ON),
1268 "Force off", I(FORCE_OFF), NULL);
1269
1270 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
1271 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
1272 HELPCTX(terminal_printing),
1273 printerbox_handler, P(NULL), P(NULL));
1274
1275 /*
1276 * The Terminal/Keyboard panel.
1277 */
1278 ctrl_settitle(b, "Terminal/Keyboard",
1279 "Options controlling the effects of keys");
1280
1281 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
1282 "Change the sequences sent by:");
1283 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
1284 HELPCTX(keyboard_backspace),
1285 dlg_stdradiobutton_handler,
1286 I(offsetof(Config, bksp_is_delete)),
1287 "Control-H", I(0), "Control-? (127)", I(1), NULL);
1288 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
1289 HELPCTX(keyboard_homeend),
1290 dlg_stdradiobutton_handler,
1291 I(offsetof(Config, rxvt_homeend)),
1292 "Standard", I(0), "rxvt", I(1), NULL);
1293 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
1294 HELPCTX(keyboard_funkeys),
1295 dlg_stdradiobutton_handler,
1296 I(offsetof(Config, funky_type)),
1297 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
1298 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
1299
1300 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
1301 "Application keypad settings:");
1302 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
1303 HELPCTX(keyboard_appcursor),
1304 dlg_stdradiobutton_handler,
1305 I(offsetof(Config, app_cursor)),
1306 "Normal", I(0), "Application", I(1), NULL);
1307 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
1308 HELPCTX(keyboard_appkeypad),
1309 numeric_keypad_handler, P(NULL),
1310 "Normal", I(0), "Application", I(1), "NetHack", I(2),
1311 NULL);
1312
1313 /*
1314 * The Terminal/Bell panel.
1315 */
1316 ctrl_settitle(b, "Terminal/Bell",
1317 "Options controlling the terminal bell");
1318
1319 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
1320 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
1321 HELPCTX(bell_style),
1322 dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
1323 "None (bell disabled)", I(BELL_DISABLED),
1324 "Make default system alert sound", I(BELL_DEFAULT),
1325 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
1326
1327 s = ctrl_getset(b, "Terminal/Bell", "overload",
1328 "Control the bell overload behaviour");
1329 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
1330 HELPCTX(bell_overload),
1331 dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
1332 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
1333 HELPCTX(bell_overload),
1334 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
1335 ctrl_editbox(s, "... in this many seconds", 't', 20,
1336 HELPCTX(bell_overload),
1337 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
62697e04 1338 I(-TICKSPERSEC));
fe8abbf4 1339 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
1340 HELPCTX(bell_overload));
1341 ctrl_editbox(s, "Seconds of silence required", 's', 20,
1342 HELPCTX(bell_overload),
1343 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
62697e04 1344 I(-TICKSPERSEC));
fe8abbf4 1345
1346 /*
1347 * The Terminal/Features panel.
1348 */
1349 ctrl_settitle(b, "Terminal/Features",
1350 "Enabling and disabling advanced terminal features");
1351
1352 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
1353 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
1354 HELPCTX(features_application),
1355 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
1356 ctrl_checkbox(s, "Disable application keypad mode", 'k',
1357 HELPCTX(features_application),
1358 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
1359 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
1360 HELPCTX(features_mouse),
1361 dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
1362 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
1363 HELPCTX(features_resize),
1364 dlg_stdcheckbox_handler,
1365 I(offsetof(Config,no_remote_resize)));
1366 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
1367 HELPCTX(features_altscreen),
1368 dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
1369 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
1370 HELPCTX(features_retitle),
1371 dlg_stdcheckbox_handler,
1372 I(offsetof(Config,no_remote_wintitle)));
e65096f2 1373 ctrl_radiobuttons(s, "Response to remote title query (SECURITY):", 'q', 3,
1374 HELPCTX(features_qtitle),
1375 dlg_stdradiobutton_handler,
1376 I(offsetof(Config,remote_qtitle_action)),
1377 "None", I(TITLE_NONE),
1378 "Empty string", I(TITLE_EMPTY),
1379 "Window title", I(TITLE_REAL), NULL);
fe8abbf4 1380 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
1381 HELPCTX(features_dbackspace),
1382 dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
1383 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
1384 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
1385 I(offsetof(Config,no_remote_charset)));
f0fccd51 1386 ctrl_checkbox(s, "Disable Arabic text shaping",
f4ec0818 1387 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler,
f0fccd51 1388 I(offsetof(Config, arabicshaping)));
1389 ctrl_checkbox(s, "Disable bidirectional text display",
f4ec0818 1390 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler,
f0fccd51 1391 I(offsetof(Config, bidi)));
fe8abbf4 1392
1393 /*
1394 * The Window panel.
1395 */
f6f450e2 1396 str = dupprintf("Options controlling %s's window", appname);
1397 ctrl_settitle(b, "Window", str);
1398 sfree(str);
fe8abbf4 1399
1400 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
1401 ctrl_columns(s, 2, 50, 50);
fe8abbf4 1402 c = ctrl_editbox(s, "Columns", 'm', 100,
1403 HELPCTX(window_size),
1404 dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
b8e45023 1405 c->generic.column = 0;
1406 c = ctrl_editbox(s, "Rows", 'r', 100,
1407 HELPCTX(window_size),
1408 dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
fe8abbf4 1409 c->generic.column = 1;
1410 ctrl_columns(s, 1, 100);
1411
1412 s = ctrl_getset(b, "Window", "scrollback",
1413 "Control the scrollback in the window");
1414 ctrl_editbox(s, "Lines of scrollback", 's', 50,
1415 HELPCTX(window_scrollback),
1416 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
1417 ctrl_checkbox(s, "Display scrollbar", 'd',
1418 HELPCTX(window_scrollback),
1419 dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
fe8abbf4 1420 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
1421 HELPCTX(window_scrollback),
1422 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
1423 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
1424 HELPCTX(window_scrollback),
1425 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
876e5d5e 1426 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
1427 HELPCTX(window_erased),
1428 dlg_stdcheckbox_handler,
1429 I(offsetof(Config,erase_to_scrollback)));
fe8abbf4 1430
1431 /*
1432 * The Window/Appearance panel.
1433 */
f6f450e2 1434 str = dupprintf("Configure the appearance of %s's window", appname);
1435 ctrl_settitle(b, "Window/Appearance", str);
1436 sfree(str);
fe8abbf4 1437
1438 s = ctrl_getset(b, "Window/Appearance", "cursor",
1439 "Adjust the use of the cursor");
1440 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
1441 HELPCTX(appearance_cursor),
1442 dlg_stdradiobutton_handler,
1443 I(offsetof(Config, cursor_type)),
1444 "Block", 'l', I(0),
1445 "Underline", 'u', I(1),
1446 "Vertical line", 'v', I(2), NULL);
1447 ctrl_checkbox(s, "Cursor blinks", 'b',
1448 HELPCTX(appearance_cursor),
1449 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1450
1451 s = ctrl_getset(b, "Window/Appearance", "font",
1452 "Font settings");
1453 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1454 HELPCTX(appearance_font),
1455 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1456
1457 s = ctrl_getset(b, "Window/Appearance", "mouse",
1458 "Adjust the use of the mouse pointer");
1459 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1460 HELPCTX(appearance_hidemouse),
1461 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1462
1463 s = ctrl_getset(b, "Window/Appearance", "border",
1464 "Adjust the window border");
b908db15 1465 ctrl_editbox(s, "Gap between text and window edge:", 'e', 20,
fe8abbf4 1466 HELPCTX(appearance_border),
1467 dlg_stdeditbox_handler,
1468 I(offsetof(Config,window_border)), I(-1));
1469
1470 /*
1471 * The Window/Behaviour panel.
1472 */
f6f450e2 1473 str = dupprintf("Configure the behaviour of %s's window", appname);
1474 ctrl_settitle(b, "Window/Behaviour", str);
1475 sfree(str);
fe8abbf4 1476
1477 s = ctrl_getset(b, "Window/Behaviour", "title",
1478 "Adjust the behaviour of the window title");
1479 ctrl_editbox(s, "Window title:", 't', 100,
1480 HELPCTX(appearance_title),
1481 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1482 I(sizeof(((Config *)0)->wintitle)));
1483 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1484 HELPCTX(appearance_title),
1485 dlg_stdcheckbox_handler,
1486 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1487
1488 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1489 ctrl_checkbox(s, "Warn before closing window", 'w',
1490 HELPCTX(behaviour_closewarn),
1491 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1492
1493 /*
1494 * The Window/Translation panel.
1495 */
1496 ctrl_settitle(b, "Window/Translation",
1497 "Options controlling character set translation");
1498
1499 s = ctrl_getset(b, "Window/Translation", "trans",
1500 "Character set translation on received data");
1501 ctrl_combobox(s, "Received data assumed to be in which character set:",
1502 'r', 100, HELPCTX(translation_codepage),
1503 codepage_handler, P(NULL), P(NULL));
1504
74790953 1505 s = ctrl_getset(b, "Window/Translation", "tweaks", NULL);
1506 ctrl_checkbox(s, "Treat CJK ambiguous characters as wide", 'w',
1507 HELPCTX(translation_cjk_ambig_wide),
1508 dlg_stdcheckbox_handler, I(offsetof(Config,cjk_ambig_wide)));
1509
00381fc7 1510 str = dupprintf("Adjust how %s handles line drawing characters", appname);
f6f450e2 1511 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1512 sfree(str);
fe8abbf4 1513 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1514 HELPCTX(translation_linedraw),
1515 dlg_stdradiobutton_handler,
1516 I(offsetof(Config, vtmode)),
3900c2d6 1517 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
fe8abbf4 1518 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
3900c2d6 1519 NULL);
00381fc7 1520 ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
1521 HELPCTX(selection_linedraw),
1522 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
fe8abbf4 1523
1524 /*
1525 * The Window/Selection panel.
1526 */
1527 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
fe8abbf4 1528
1529 s = ctrl_getset(b, "Window/Selection", "mouse",
1530 "Control use of mouse");
1531 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1532 HELPCTX(selection_shiftdrag),
1533 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1534 ctrl_radiobuttons(s,
1535 "Default selection mode (Alt+drag does the other one):",
1536 NO_SHORTCUT, 2,
1537 HELPCTX(selection_rect),
1538 dlg_stdradiobutton_handler,
1539 I(offsetof(Config, rect_select)),
1540 "Normal", 'n', I(0),
1541 "Rectangular block", 'r', I(1), NULL);
1542
1543 s = ctrl_getset(b, "Window/Selection", "charclass",
1544 "Control the select-one-word-at-a-time mode");
1545 ccd = (struct charclass_data *)
1546 ctrl_alloc(b, sizeof(struct charclass_data));
1547 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1548 HELPCTX(selection_charclasses),
1549 charclass_handler, P(ccd));
1550 ccd->listbox->listbox.multisel = 1;
1551 ccd->listbox->listbox.ncols = 4;
3d88e64d 1552 ccd->listbox->listbox.percentages = snewn(4, int);
fe8abbf4 1553 ccd->listbox->listbox.percentages[0] = 15;
1554 ccd->listbox->listbox.percentages[1] = 25;
1555 ccd->listbox->listbox.percentages[2] = 20;
1556 ccd->listbox->listbox.percentages[3] = 40;
1557 ctrl_columns(s, 2, 67, 33);
1558 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1559 HELPCTX(selection_charclasses),
1560 charclass_handler, P(ccd), P(NULL));
1561 ccd->editbox->generic.column = 0;
1562 ccd->button = ctrl_pushbutton(s, "Set", 's',
1563 HELPCTX(selection_charclasses),
1564 charclass_handler, P(ccd));
1565 ccd->button->generic.column = 1;
1566 ctrl_columns(s, 1, 100);
1567
1568 /*
1569 * The Window/Colours panel.
1570 */
1571 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1572
1573 s = ctrl_getset(b, "Window/Colours", "general",
1574 "General options for colour usage");
c6f1b8ed 1575 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1576 HELPCTX(colours_ansi),
1577 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
cecb13f6 1578 ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
1579 HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
1580 I(offsetof(Config,xterm_256_colour)));
fe8abbf4 1581 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1582 HELPCTX(colours_bold),
1583 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1584
f6f450e2 1585 str = dupprintf("Adjust the precise colours %s displays", appname);
1586 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1587 sfree(str);
fe8abbf4 1588 ctrl_text(s, "Select a colour from the list, and then click the"
1589 " Modify button to change its appearance.",
1590 HELPCTX(colours_config));
1591 ctrl_columns(s, 2, 67, 33);
1592 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1593 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1594 HELPCTX(colours_config), colour_handler, P(cd));
1595 cd->listbox->generic.column = 0;
18c2f87c 1596 cd->listbox->listbox.height = 7;
fe8abbf4 1597 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1598 c->generic.column = 1;
18c2f87c 1599 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1600 colour_handler, P(cd), P(NULL));
1601 cd->redit->generic.column = 1;
1602 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1603 colour_handler, P(cd), P(NULL));
1604 cd->gedit->generic.column = 1;
1605 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1606 colour_handler, P(cd), P(NULL));
1607 cd->bedit->generic.column = 1;
fe8abbf4 1608 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1609 colour_handler, P(cd));
1610 cd->button->generic.column = 1;
1611 ctrl_columns(s, 1, 100);
1612
1613 /*
3e547dd8 1614 * The Connection panel. This doesn't show up if we're in a
1615 * non-network utility such as pterm. We tell this by being
1616 * passed a protocol < 0.
fe8abbf4 1617 */
3e547dd8 1618 if (protocol >= 0) {
1619 ctrl_settitle(b, "Connection", "Options controlling the connection");
1620
05581745 1621 s = ctrl_getset(b, "Connection", "keepalive",
1622 "Sending of null packets to keep session active");
1623 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1624 HELPCTX(connection_keepalive),
1625 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1626 I(-1));
1627
3e547dd8 1628 if (!midsession) {
05581745 1629 s = ctrl_getset(b, "Connection", "tcp",
1630 "Low-level TCP connection options");
1631 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1632 'n', HELPCTX(connection_nodelay),
1633 dlg_stdcheckbox_handler,
1634 I(offsetof(Config,tcp_nodelay)));
1635 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1636 'p', HELPCTX(connection_tcpkeepalive),
1637 dlg_stdcheckbox_handler,
1638 I(offsetof(Config,tcp_keepalives)));
22db244f 1639#ifndef NO_IPV6
05581745 1640 s = ctrl_getset(b, "Connection", "ipversion",
1641 "Internet protocol version");
22db244f 1642 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
05581745 1643 HELPCTX(connection_ipversion),
1644 dlg_stdradiobutton_handler,
1645 I(offsetof(Config, addressfamily)),
b908db15 1646 "Auto", 'u', I(ADDRTYPE_UNSPEC),
1647 "IPv4", '4', I(ADDRTYPE_IPV4),
1648 "IPv6", '6', I(ADDRTYPE_IPV6),
05581745 1649 NULL);
22db244f 1650#endif
05581745 1651 }
1652
1653 /*
1654 * A sub-panel Connection/Data, containing options that
1655 * decide on data to send to the server.
1656 */
1657 if (!midsession) {
1658 ctrl_settitle(b, "Connection/Data", "Data to send to the server");
1659
1660 s = ctrl_getset(b, "Connection/Data", "login",
1661 "Login details");
1662 ctrl_editbox(s, "Auto-login username", 'u', 50,
1663 HELPCTX(connection_username),
1664 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1665 I(sizeof(((Config *)0)->username)));
1666
1667 s = ctrl_getset(b, "Connection/Data", "term",
1668 "Terminal details");
3e547dd8 1669 ctrl_editbox(s, "Terminal-type string", 't', 50,
1670 HELPCTX(connection_termtype),
1671 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1672 I(sizeof(((Config *)0)->termtype)));
a5dd8467 1673 ctrl_editbox(s, "Terminal speeds", 's', 50,
1674 HELPCTX(connection_termspeed),
1675 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1676 I(sizeof(((Config *)0)->termspeed)));
73feed4f 1677
05581745 1678 s = ctrl_getset(b, "Connection/Data", "env",
1679 "Environment variables");
73feed4f 1680 ctrl_columns(s, 2, 80, 20);
1681 ed = (struct environ_data *)
1682 ctrl_alloc(b, sizeof(struct environ_data));
1683 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1684 HELPCTX(telnet_environ),
1685 environ_handler, P(ed), P(NULL));
1686 ed->varbox->generic.column = 0;
1687 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1688 HELPCTX(telnet_environ),
1689 environ_handler, P(ed), P(NULL));
1690 ed->valbox->generic.column = 0;
1691 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1692 HELPCTX(telnet_environ),
1693 environ_handler, P(ed));
1694 ed->addbutton->generic.column = 1;
1695 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1696 HELPCTX(telnet_environ),
1697 environ_handler, P(ed));
1698 ed->rembutton->generic.column = 1;
1699 ctrl_columns(s, 1, 100);
1700 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1701 HELPCTX(telnet_environ),
1702 environ_handler, P(ed));
1703 ed->listbox->listbox.height = 3;
1704 ed->listbox->listbox.ncols = 2;
1705 ed->listbox->listbox.percentages = snewn(2, int);
1706 ed->listbox->listbox.percentages[0] = 30;
1707 ed->listbox->listbox.percentages[1] = 70;
3e547dd8 1708 }
fe8abbf4 1709
fe8abbf4 1710 }
1711
1712 if (!midsession) {
1713 /*
1714 * The Connection/Proxy panel.
1715 */
1716 ctrl_settitle(b, "Connection/Proxy",
1717 "Options controlling proxy usage");
1718
10068a0b 1719 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1720 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
fe8abbf4 1721 HELPCTX(proxy_type),
1722 dlg_stdradiobutton_handler,
1723 I(offsetof(Config, proxy_type)),
0f0a2507 1724 "None", I(PROXY_NONE),
10068a0b 1725 "SOCKS 4", I(PROXY_SOCKS4),
1726 "SOCKS 5", I(PROXY_SOCKS5),
0f0a2507 1727 "HTTP", I(PROXY_HTTP),
0f0a2507 1728 "Telnet", I(PROXY_TELNET),
fe8abbf4 1729 NULL);
1730 ctrl_columns(s, 2, 80, 20);
1731 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1732 HELPCTX(proxy_main),
1733 dlg_stdeditbox_handler,
1734 I(offsetof(Config,proxy_host)),
1735 I(sizeof(((Config *)0)->proxy_host)));
1736 c->generic.column = 0;
1737 c = ctrl_editbox(s, "Port", 'p', 100,
1738 HELPCTX(proxy_main),
1739 dlg_stdeditbox_handler,
1740 I(offsetof(Config,proxy_port)),
1741 I(-1));
1742 c->generic.column = 1;
1743 ctrl_columns(s, 1, 100);
1744 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1745 HELPCTX(proxy_exclude),
1746 dlg_stdeditbox_handler,
1747 I(offsetof(Config,proxy_exclude_list)),
1748 I(sizeof(((Config *)0)->proxy_exclude_list)));
1749 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1750 HELPCTX(proxy_exclude),
1751 dlg_stdcheckbox_handler,
1752 I(offsetof(Config,even_proxy_localhost)));
1753 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1754 HELPCTX(proxy_dns),
1755 dlg_stdradiobutton_handler,
1756 I(offsetof(Config, proxy_dns)),
1757 "No", I(FORCE_OFF),
1758 "Auto", I(AUTO),
1759 "Yes", I(FORCE_ON), NULL);
1760 ctrl_editbox(s, "Username", 'u', 60,
1761 HELPCTX(proxy_auth),
1762 dlg_stdeditbox_handler,
1763 I(offsetof(Config,proxy_username)),
1764 I(sizeof(((Config *)0)->proxy_username)));
1765 c = ctrl_editbox(s, "Password", 'w', 60,
1766 HELPCTX(proxy_auth),
1767 dlg_stdeditbox_handler,
1768 I(offsetof(Config,proxy_password)),
1769 I(sizeof(((Config *)0)->proxy_password)));
1770 c->editbox.password = 1;
fe8abbf4 1771 ctrl_editbox(s, "Telnet command", 'm', 100,
1772 HELPCTX(proxy_command),
1773 dlg_stdeditbox_handler,
1774 I(offsetof(Config,proxy_telnet_command)),
1775 I(sizeof(((Config *)0)->proxy_telnet_command)));
fe8abbf4 1776 }
1777
1778 /*
1779 * The Telnet panel exists in the base config box, and in a
1780 * mid-session reconfig box _if_ we're using Telnet.
1781 */
1782 if (!midsession || protocol == PROT_TELNET) {
1783 /*
1784 * The Connection/Telnet panel.
1785 */
1786 ctrl_settitle(b, "Connection/Telnet",
1787 "Options controlling Telnet connections");
1788
fe8abbf4 1789 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1790 "Telnet protocol adjustments");
1791
1792 if (!midsession) {
1793 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1794 NO_SHORTCUT, 2,
1795 HELPCTX(telnet_oldenviron),
1796 dlg_stdradiobutton_handler,
1797 I(offsetof(Config, rfc_environ)),
1798 "BSD (commonplace)", 'b', I(0),
1799 "RFC 1408 (unusual)", 'f', I(1), NULL);
1800 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1801 HELPCTX(telnet_passive),
1802 dlg_stdradiobutton_handler,
1803 I(offsetof(Config, passive_telnet)),
1804 "Passive", I(1), "Active", I(0), NULL);
1805 }
76d3d354 1806 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
fe8abbf4 1807 HELPCTX(telnet_specialkeys),
1808 dlg_stdcheckbox_handler,
1809 I(offsetof(Config,telnet_keyboard)));
76d3d354 1810 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1811 'm', HELPCTX(telnet_newline),
fe8abbf4 1812 dlg_stdcheckbox_handler,
1813 I(offsetof(Config,telnet_newline)));
1814 }
1815
1816 if (!midsession) {
1817
1818 /*
1819 * The Connection/Rlogin panel.
1820 */
1821 ctrl_settitle(b, "Connection/Rlogin",
1822 "Options controlling Rlogin connections");
1823
1824 s = ctrl_getset(b, "Connection/Rlogin", "data",
1825 "Data to send to the server");
fe8abbf4 1826 ctrl_editbox(s, "Local username:", 'l', 50,
1827 HELPCTX(rlogin_localuser),
1828 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1829 I(sizeof(((Config *)0)->localusername)));
1830
1831 }
1832
1833 /*
fda2feb1 1834 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
1835 * when we're not doing SSH.
fe8abbf4 1836 */
1837
9ad36e5f 1838 if (have_backend(PROT_SSH) && (!midsession || protocol == PROT_SSH)) {
fe8abbf4 1839
1840 /*
1841 * The Connection/SSH panel.
1842 */
1843 ctrl_settitle(b, "Connection/SSH",
1844 "Options controlling SSH connections");
1845
e13bba36 1846 if (midsession && protcfginfo == 1) {
fda2feb1 1847 s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
1848 ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
1849 "session; it is only here so that sub-panels of it can "
1850 "exist without looking strange.", HELPCTX(no_help));
1851 }
1852
1853 if (!midsession) {
1854
1855 s = ctrl_getset(b, "Connection/SSH", "data",
1856 "Data to send to the server");
1857 ctrl_editbox(s, "Remote command:", 'r', 100,
1858 HELPCTX(ssh_command),
1859 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1860 I(sizeof(((Config *)0)->remote_cmd)));
1861
1862 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
fda2feb1 1863 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
1864 HELPCTX(ssh_noshell),
1865 dlg_stdcheckbox_handler,
1866 I(offsetof(Config,ssh_no_shell)));
e13bba36 1867 }
1868
1869 if (!midsession || protcfginfo != 1) {
1870 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1871
fda2feb1 1872 ctrl_checkbox(s, "Enable compression", 'e',
1873 HELPCTX(ssh_compress),
1874 dlg_stdcheckbox_handler,
1875 I(offsetof(Config,compression)));
e13bba36 1876 }
1877
1878 if (!midsession) {
1879 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1880
fda2feb1 1881 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1882 HELPCTX(ssh_protocol),
1883 dlg_stdradiobutton_handler,
1884 I(offsetof(Config, sshprot)),
1885 "1 only", 'l', I(0),
1886 "1", '1', I(1),
1887 "2", '2', I(2),
1888 "2 only", 'y', I(3), NULL);
e13bba36 1889 }
fda2feb1 1890
e13bba36 1891 if (!midsession || protcfginfo != 1) {
fda2feb1 1892 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1893 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1894 HELPCTX(ssh_ciphers),
1895 cipherlist_handler, P(NULL));
1896 c->listbox.height = 6;
1897
2e85c969 1898 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i',
bb524800 1899 HELPCTX(ssh_ciphers),
fda2feb1 1900 dlg_stdcheckbox_handler,
1901 I(offsetof(Config,ssh2_des_cbc)));
e6c1536e 1902 }
fe8abbf4 1903
e6c1536e 1904 /*
1905 * The Connection/SSH/Kex panel. (Owing to repeat key
f89c3294 1906 * exchange, this is all meaningful in mid-session _if_
2e85c969 1907 * we're using SSH-2 or haven't decided yet.)
e6c1536e 1908 */
f89c3294 1909 if (protcfginfo != 1) {
1910 ctrl_settitle(b, "Connection/SSH/Kex",
1911 "Options controlling SSH key exchange");
1912
1913 s = ctrl_getset(b, "Connection/SSH/Kex", "main",
1914 "Key exchange algorithm options");
2e077f2e 1915 c = ctrl_draglist(s, "Algorithm selection policy:", 's',
f89c3294 1916 HELPCTX(ssh_kexlist),
1917 kexlist_handler, P(NULL));
1918 c->listbox.height = 5;
1919
1920 s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
1921 "Options controlling key re-exchange");
1922
1923 ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
1924 HELPCTX(ssh_kex_repeat),
1925 dlg_stdeditbox_handler,
1926 I(offsetof(Config,ssh_rekey_time)),
1927 I(-1));
1928 ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
1929 HELPCTX(ssh_kex_repeat),
1930 dlg_stdeditbox_handler,
1931 I(offsetof(Config,ssh_rekey_data)),
1932 I(16));
1933 ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
1934 HELPCTX(ssh_kex_repeat));
1935 }
e6c1536e 1936
1937 if (!midsession) {
83e7d008 1938
fda2feb1 1939 /*
1940 * The Connection/SSH/Auth panel.
1941 */
1942 ctrl_settitle(b, "Connection/SSH/Auth",
1943 "Options controlling SSH authentication");
fe8abbf4 1944
a1a1fae4 1945 s = ctrl_getset(b, "Connection/SSH/Auth", "main", NULL);
1946 ctrl_checkbox(s, "Bypass authentication entirely (SSH-2 only)", 'b',
1947 HELPCTX(ssh_auth_bypass),
1948 dlg_stdcheckbox_handler,
1949 I(offsetof(Config,ssh_no_userauth)));
1950
fda2feb1 1951 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1952 "Authentication methods");
973612f5 1953 ctrl_checkbox(s, "Attempt authentication using Pageant", 'p',
1954 HELPCTX(ssh_auth_pageant),
1955 dlg_stdcheckbox_handler,
1956 I(offsetof(Config,tryagent)));
2e85c969 1957 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
fda2feb1 1958 HELPCTX(ssh_auth_tis),
1959 dlg_stdcheckbox_handler,
1960 I(offsetof(Config,try_tis_auth)));
2e85c969 1961 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH-2)",
fda2feb1 1962 'i', HELPCTX(ssh_auth_ki),
1963 dlg_stdcheckbox_handler,
1964 I(offsetof(Config,try_ki_auth)));
1965
1966 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1967 "Authentication parameters");
1968 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1969 HELPCTX(ssh_auth_agentfwd),
1970 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
2e85c969 1971 ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", 'u',
fda2feb1 1972 HELPCTX(ssh_auth_changeuser),
1973 dlg_stdcheckbox_handler,
1974 I(offsetof(Config,change_username)));
1975 ctrl_filesel(s, "Private key file for authentication:", 'k',
1976 FILTER_KEY_FILES, FALSE, "Select private key file",
1977 HELPCTX(ssh_auth_privkey),
1978 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1979 }
fe8abbf4 1980
fda2feb1 1981 if (!midsession) {
05581745 1982 /*
c6ccd5c2 1983 * The Connection/SSH/TTY panel.
1984 */
1985 ctrl_settitle(b, "Connection/SSH/TTY", "Remote terminal settings");
1986
1987 s = ctrl_getset(b, "Connection/SSH/TTY", "sshtty", NULL);
1988 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1989 HELPCTX(ssh_nopty),
1990 dlg_stdcheckbox_handler,
1991 I(offsetof(Config,nopty)));
1992
1993 s = ctrl_getset(b, "Connection/SSH/TTY", "ttymodes",
1994 "Terminal modes");
1995 td = (struct ttymodes_data *)
1996 ctrl_alloc(b, sizeof(struct ttymodes_data));
1997 ctrl_columns(s, 2, 75, 25);
1998 c = ctrl_text(s, "Terminal modes to send:", HELPCTX(ssh_ttymodes));
1999 c->generic.column = 0;
2000 td->rembutton = ctrl_pushbutton(s, "Remove", 'r',
2001 HELPCTX(ssh_ttymodes),
2002 ttymodes_handler, P(td));
2003 td->rembutton->generic.column = 1;
2004 td->rembutton->generic.tabdelay = 1;
2005 ctrl_columns(s, 1, 100);
2006 td->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
2007 HELPCTX(ssh_ttymodes),
2008 ttymodes_handler, P(td));
2009 td->listbox->listbox.multisel = 1;
2010 td->listbox->listbox.height = 4;
2011 td->listbox->listbox.ncols = 2;
2012 td->listbox->listbox.percentages = snewn(2, int);
2013 td->listbox->listbox.percentages[0] = 40;
2014 td->listbox->listbox.percentages[1] = 60;
2015 ctrl_tabdelay(s, td->rembutton);
2016 ctrl_columns(s, 2, 75, 25);
2017 td->modelist = ctrl_droplist(s, "Mode:", 'm', 67,
2018 HELPCTX(ssh_ttymodes),
2019 ttymodes_handler, P(td));
2020 td->modelist->generic.column = 0;
2021 td->addbutton = ctrl_pushbutton(s, "Add", 'd',
2022 HELPCTX(ssh_ttymodes),
2023 ttymodes_handler, P(td));
2024 td->addbutton->generic.column = 1;
2025 td->addbutton->generic.tabdelay = 1;
2026 ctrl_columns(s, 1, 100); /* column break */
2027 /* Bit of a hack to get the value radio buttons and
2028 * edit-box on the same row. */
2029 ctrl_columns(s, 3, 25, 50, 25);
2030 c = ctrl_text(s, "Value:", HELPCTX(ssh_ttymodes));
2031 c->generic.column = 0;
2032 td->valradio = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2,
2033 HELPCTX(ssh_ttymodes),
2034 ttymodes_handler, P(td),
2035 "Auto", NO_SHORTCUT, P(NULL),
2036 "This:", NO_SHORTCUT, P(NULL),
2037 NULL);
2038 td->valradio->generic.column = 1;
2039 td->valbox = ctrl_editbox(s, NULL, NO_SHORTCUT, 100,
2040 HELPCTX(ssh_ttymodes),
2041 ttymodes_handler, P(td), P(NULL));
2042 td->valbox->generic.column = 2;
2043 ctrl_tabdelay(s, td->addbutton);
2044
2045 }
2046
2047 if (!midsession) {
2048 /*
05581745 2049 * The Connection/SSH/X11 panel.
2050 */
2051 ctrl_settitle(b, "Connection/SSH/X11",
2052 "Options controlling SSH X11 forwarding");
2053
2054 s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
fda2feb1 2055 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
2056 HELPCTX(ssh_tunnels_x11),
2057 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
2058 ctrl_editbox(s, "X display location", 'x', 50,
2059 HELPCTX(ssh_tunnels_x11),
2060 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
2061 I(sizeof(((Config *)0)->x11_display)));
2062 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
2063 HELPCTX(ssh_tunnels_x11auth),
2064 dlg_stdradiobutton_handler,
2065 I(offsetof(Config, x11_auth)),
2066 "MIT-Magic-Cookie-1", I(X11_MIT),
2067 "XDM-Authorization-1", I(X11_XDM), NULL);
2068 }
fe8abbf4 2069
05581745 2070 /*
2071 * The Tunnels panel _is_ still available in mid-session.
2072 */
2073 ctrl_settitle(b, "Connection/SSH/Tunnels",
2074 "Options controlling SSH port forwarding");
2075
fe8abbf4 2076 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
2077 "Port forwarding");
2078 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
2079 HELPCTX(ssh_tunnels_portfwd_localhost),
2080 dlg_stdcheckbox_handler,
2081 I(offsetof(Config,lport_acceptall)));
2e85c969 2082 ctrl_checkbox(s, "Remote ports do the same (SSH-2 only)", 'p',
fe8abbf4 2083 HELPCTX(ssh_tunnels_portfwd_localhost),
2084 dlg_stdcheckbox_handler,
2085 I(offsetof(Config,rport_acceptall)));
2086
2087 ctrl_columns(s, 3, 55, 20, 25);
2088 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
2089 c->generic.column = COLUMN_FIELD(0,2);
2090 /* You want to select from the list, _then_ hit Remove. So tab order
2091 * should be that way round. */
2092 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
2093 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
2094 HELPCTX(ssh_tunnels_portfwd),
2095 portfwd_handler, P(pfd));
2096 pfd->rembutton->generic.column = 2;
2097 pfd->rembutton->generic.tabdelay = 1;
2098 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
2099 HELPCTX(ssh_tunnels_portfwd),
2100 portfwd_handler, P(pfd));
2101 pfd->listbox->listbox.height = 3;
37dbf11c 2102 pfd->listbox->listbox.ncols = 2;
3d88e64d 2103 pfd->listbox->listbox.percentages = snewn(2, int);
37dbf11c 2104 pfd->listbox->listbox.percentages[0] = 20;
2105 pfd->listbox->listbox.percentages[1] = 80;
fe8abbf4 2106 ctrl_tabdelay(s, pfd->rembutton);
2107 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
2108 /* You want to enter source, destination and type, _then_ hit Add.
2109 * Again, we adjust the tab order to reflect this. */
2110 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
2111 HELPCTX(ssh_tunnels_portfwd),
2112 portfwd_handler, P(pfd));
2113 pfd->addbutton->generic.column = 2;
2114 pfd->addbutton->generic.tabdelay = 1;
2115 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
2116 HELPCTX(ssh_tunnels_portfwd),
2117 portfwd_handler, P(pfd), P(NULL));
2118 pfd->sourcebox->generic.column = 0;
2119 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
2120 HELPCTX(ssh_tunnels_portfwd),
2121 portfwd_handler, P(pfd), P(NULL));
820ebe3b 2122 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
fe8abbf4 2123 HELPCTX(ssh_tunnels_portfwd),
2124 portfwd_handler, P(pfd),
2125 "Local", 'l', P(NULL),
820ebe3b 2126 "Remote", 'm', P(NULL),
2127 "Dynamic", 'y', P(NULL),
2128 NULL);
05581745 2129#ifndef NO_IPV6
22db244f 2130 pfd->addressfamily =
2131 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
05581745 2132 HELPCTX(ssh_tunnels_portfwd_ipversion),
2133 portfwd_handler, P(pfd),
b908db15 2134 "Auto", 'u', I(ADDRTYPE_UNSPEC),
2135 "IPv4", '4', I(ADDRTYPE_IPV4),
2136 "IPv6", '6', I(ADDRTYPE_IPV6),
05581745 2137 NULL);
22db244f 2138#endif
fe8abbf4 2139 ctrl_tabdelay(s, pfd->addbutton);
2140 ctrl_columns(s, 1, 100);
2141
fda2feb1 2142 if (!midsession) {
2143 /*
2144 * The Connection/SSH/Bugs panel.
2145 */
2146 ctrl_settitle(b, "Connection/SSH/Bugs",
2147 "Workarounds for SSH server bugs");
2148
2149 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
2150 "Detection of known bugs in SSH servers");
2e85c969 2151 ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
fda2feb1 2152 HELPCTX(ssh_bugs_ignore1),
2153 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
2e85c969 2154 ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
fda2feb1 2155 HELPCTX(ssh_bugs_plainpw1),
2156 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
2e85c969 2157 ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
fda2feb1 2158 HELPCTX(ssh_bugs_rsa1),
2159 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
2e85c969 2160 ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
fda2feb1 2161 HELPCTX(ssh_bugs_hmac2),
2162 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
2e85c969 2163 ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
fda2feb1 2164 HELPCTX(ssh_bugs_derivekey2),
2165 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
2e85c969 2166 ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
fda2feb1 2167 HELPCTX(ssh_bugs_rsapad2),
2168 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
19f47a7d 2169 ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
fda2feb1 2170 HELPCTX(ssh_bugs_pksessid2),
2171 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
19f47a7d 2172 ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
f382c87d 2173 HELPCTX(ssh_bugs_rekey2),
2174 sshbug_handler, I(offsetof(Config,sshbug_rekey2)));
fda2feb1 2175 }
fe8abbf4 2176 }
2177}