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