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