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