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