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