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