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