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