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