Explicitly closing logctx on various kinds of error exit means that
[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
18static void config_host_handler(union control *ctrl, void *dlg,
19 void *data, int event)
20{
21 Config *cfg = (Config *)data;
22
23 /*
24 * This function works just like the standard edit box handler,
25 * only it has to choose the control's label and text from two
26 * different places depending on the protocol.
27 */
28 if (event == EVENT_REFRESH) {
29 if (cfg->protocol == PROT_SERIAL) {
30 /*
31 * This label text is carefully chosen to contain an n,
32 * since that's the shortcut for the host name control.
33 */
34 dlg_label_change(ctrl, dlg, "Serial line");
35 dlg_editbox_set(ctrl, dlg, cfg->serline);
36 } else {
37 dlg_label_change(ctrl, dlg, HOST_BOX_TITLE);
38 dlg_editbox_set(ctrl, dlg, cfg->host);
39 }
40 } else if (event == EVENT_VALCHANGE) {
41 if (cfg->protocol == PROT_SERIAL)
42 dlg_editbox_get(ctrl, dlg, cfg->serline, lenof(cfg->serline));
43 else
44 dlg_editbox_get(ctrl, dlg, cfg->host, lenof(cfg->host));
45 }
46}
47
48static void config_port_handler(union control *ctrl, void *dlg,
49 void *data, int event)
50{
51 Config *cfg = (Config *)data;
52 char buf[80];
53
54 /*
55 * This function works just like the standard edit box handler,
56 * only it has to choose the control's label and text from two
57 * different places depending on the protocol.
58 */
59 if (event == EVENT_REFRESH) {
60 if (cfg->protocol == PROT_SERIAL) {
61 /*
62 * This label text is carefully chosen to contain a p,
63 * since that's the shortcut for the port control.
64 */
65 dlg_label_change(ctrl, dlg, "Speed");
66 sprintf(buf, "%d", cfg->serspeed);
67 } else {
68 dlg_label_change(ctrl, dlg, PORT_BOX_TITLE);
69 sprintf(buf, "%d", cfg->port);
70 }
71 dlg_editbox_set(ctrl, dlg, buf);
72 } else if (event == EVENT_VALCHANGE) {
73 dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
74 if (cfg->protocol == PROT_SERIAL)
75 cfg->serspeed = atoi(buf);
76 else
77 cfg->port = atoi(buf);
78 }
79}
80
81struct hostport {
82 union control *host, *port;
83};
84
85/*
86 * We export this function so that platform-specific config
87 * routines can use it to conveniently identify the protocol radio
88 * buttons in order to add to them.
89 */
90void config_protocolbuttons_handler(union control *ctrl, void *dlg,
fe8abbf4 91 void *data, int event)
92{
93 int button, defport;
94 Config *cfg = (Config *)data;
7374c779 95 struct hostport *hp = (struct hostport *)ctrl->radio.context.p;
96
fe8abbf4 97 /*
98 * This function works just like the standard radio-button
99 * handler, except that it also has to change the setting of
7374c779 100 * the port box, and refresh both host and port boxes when. We
101 * expect the context parameter to point at a hostport
102 * structure giving the `union control's for both.
fe8abbf4 103 */
104 if (event == EVENT_REFRESH) {
105 for (button = 0; button < ctrl->radio.nbuttons; button++)
106 if (cfg->protocol == ctrl->radio.buttondata[button].i)
107 break;
108 /* We expected that `break' to happen, in all circumstances. */
109 assert(button < ctrl->radio.nbuttons);
110 dlg_radiobutton_set(ctrl, dlg, button);
111 } else if (event == EVENT_VALCHANGE) {
112 int oldproto = cfg->protocol;
113 button = dlg_radiobutton_get(ctrl, dlg);
114 assert(button >= 0 && button < ctrl->radio.nbuttons);
115 cfg->protocol = ctrl->radio.buttondata[button].i;
116 if (oldproto != cfg->protocol) {
117 defport = -1;
118 switch (cfg->protocol) {
119 case PROT_SSH: defport = 22; break;
120 case PROT_TELNET: defport = 23; break;
121 case PROT_RLOGIN: defport = 513; break;
122 }
123 if (defport > 0 && cfg->port != defport) {
124 cfg->port = defport;
fe8abbf4 125 }
126 }
7374c779 127 dlg_refresh(hp->host, dlg);
128 dlg_refresh(hp->port, dlg);
fe8abbf4 129 }
130}
131
17556692 132static void loggingbuttons_handler(union control *ctrl, void *dlg,
133 void *data, int event)
134{
135 int button;
136 Config *cfg = (Config *)data;
137 /* This function works just like the standard radio-button handler,
138 * but it has to fall back to "no logging" in situations where the
139 * configured logging type isn't applicable.
140 */
141 if (event == EVENT_REFRESH) {
142 for (button = 0; button < ctrl->radio.nbuttons; button++)
143 if (cfg->logtype == ctrl->radio.buttondata[button].i)
144 break;
145
146 /* We fell off the end, so we lack the configured logging type */
147 if (button == ctrl->radio.nbuttons) {
148 button=0;
149 cfg->logtype=LGTYP_NONE;
150 }
151 dlg_radiobutton_set(ctrl, dlg, button);
152 } else if (event == EVENT_VALCHANGE) {
153 button = dlg_radiobutton_get(ctrl, dlg);
154 assert(button >= 0 && button < ctrl->radio.nbuttons);
155 cfg->logtype = ctrl->radio.buttondata[button].i;
156 }
157}
158
fe8abbf4 159static void numeric_keypad_handler(union control *ctrl, void *dlg,
160 void *data, int event)
161{
162 int button;
163 Config *cfg = (Config *)data;
164 /*
165 * This function works much like the standard radio button
166 * handler, but it has to handle two fields in Config.
167 */
168 if (event == EVENT_REFRESH) {
169 if (cfg->nethack_keypad)
170 button = 2;
171 else if (cfg->app_keypad)
172 button = 1;
173 else
174 button = 0;
175 assert(button < ctrl->radio.nbuttons);
176 dlg_radiobutton_set(ctrl, dlg, button);
177 } else if (event == EVENT_VALCHANGE) {
178 button = dlg_radiobutton_get(ctrl, dlg);
179 assert(button >= 0 && button < ctrl->radio.nbuttons);
180 if (button == 2) {
181 cfg->app_keypad = FALSE;
182 cfg->nethack_keypad = TRUE;
183 } else {
184 cfg->app_keypad = (button != 0);
185 cfg->nethack_keypad = FALSE;
186 }
187 }
188}
189
190static void cipherlist_handler(union control *ctrl, void *dlg,
191 void *data, int event)
192{
193 Config *cfg = (Config *)data;
194 if (event == EVENT_REFRESH) {
195 int i;
196
197 static const struct { char *s; int c; } ciphers[] = {
198 { "3DES", CIPHER_3DES },
199 { "Blowfish", CIPHER_BLOWFISH },
200 { "DES", CIPHER_DES },
2e85c969 201 { "AES (SSH-2 only)", CIPHER_AES },
a2add208 202 { "Arcfour (SSH-2 only)", CIPHER_ARCFOUR },
fe8abbf4 203 { "-- warn below here --", CIPHER_WARN }
204 };
205
206 /* Set up the "selected ciphers" box. */
207 /* (cipherlist assumed to contain all ciphers) */
208 dlg_update_start(ctrl, dlg);
209 dlg_listbox_clear(ctrl, dlg);
210 for (i = 0; i < CIPHER_MAX; i++) {
211 int c = cfg->ssh_cipherlist[i];
212 int j;
213 char *cstr = NULL;
214 for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
215 if (ciphers[j].c == c) {
216 cstr = ciphers[j].s;
217 break;
218 }
219 }
4eaff8d4 220 dlg_listbox_addwithid(ctrl, dlg, cstr, c);
fe8abbf4 221 }
222 dlg_update_done(ctrl, dlg);
223
224 } else if (event == EVENT_VALCHANGE) {
225 int i;
226
227 /* Update array to match the list box. */
228 for (i=0; i < CIPHER_MAX; i++)
229 cfg->ssh_cipherlist[i] = dlg_listbox_getid(ctrl, dlg, i);
230
231 }
232}
233
83e7d008 234static void kexlist_handler(union control *ctrl, void *dlg,
235 void *data, int event)
236{
237 Config *cfg = (Config *)data;
238 if (event == EVENT_REFRESH) {
239 int i;
240
241 static const struct { char *s; int k; } kexes[] = {
242 { "Diffie-Hellman group 1", KEX_DHGROUP1 },
243 { "Diffie-Hellman group 14", KEX_DHGROUP14 },
244 { "Diffie-Hellman group exchange", KEX_DHGEX },
245 { "-- warn below here --", KEX_WARN }
246 };
247
248 /* Set up the "kex preference" box. */
249 /* (kexlist assumed to contain all algorithms) */
250 dlg_update_start(ctrl, dlg);
251 dlg_listbox_clear(ctrl, dlg);
252 for (i = 0; i < KEX_MAX; i++) {
253 int k = cfg->ssh_kexlist[i];
254 int j;
255 char *kstr = NULL;
256 for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) {
257 if (kexes[j].k == k) {
258 kstr = kexes[j].s;
259 break;
260 }
261 }
262 dlg_listbox_addwithid(ctrl, dlg, kstr, k);
263 }
264 dlg_update_done(ctrl, dlg);
265
266 } else if (event == EVENT_VALCHANGE) {
267 int i;
268
269 /* Update array to match the list box. */
270 for (i=0; i < KEX_MAX; i++)
271 cfg->ssh_kexlist[i] = dlg_listbox_getid(ctrl, dlg, i);
272
273 }
274}
275
fe8abbf4 276static void printerbox_handler(union control *ctrl, void *dlg,
277 void *data, int event)
278{
279 Config *cfg = (Config *)data;
280 if (event == EVENT_REFRESH) {
281 int nprinters, i;
282 printer_enum *pe;
283
284 dlg_update_start(ctrl, dlg);
0f915619 285 /*
286 * Some backends may wish to disable the drop-down list on
287 * this edit box. Be prepared for this.
288 */
289 if (ctrl->editbox.has_list) {
290 dlg_listbox_clear(ctrl, dlg);
291 dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING);
292 pe = printer_start_enum(&nprinters);
293 for (i = 0; i < nprinters; i++)
294 dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i));
295 printer_finish_enum(pe);
296 }
fe8abbf4 297 dlg_editbox_set(ctrl, dlg,
298 (*cfg->printer ? cfg->printer :
299 PRINTER_DISABLED_STRING));
300 dlg_update_done(ctrl, dlg);
301 } else if (event == EVENT_VALCHANGE) {
302 dlg_editbox_get(ctrl, dlg, cfg->printer, sizeof(cfg->printer));
303 if (!strcmp(cfg->printer, PRINTER_DISABLED_STRING))
304 *cfg->printer = '\0';
305 }
306}
307
308static void codepage_handler(union control *ctrl, void *dlg,
309 void *data, int event)
310{
311 Config *cfg = (Config *)data;
312 if (event == EVENT_REFRESH) {
313 int i;
d4413bd2 314 const char *cp;
fe8abbf4 315 dlg_update_start(ctrl, dlg);
316 strcpy(cfg->line_codepage,
317 cp_name(decode_codepage(cfg->line_codepage)));
318 dlg_listbox_clear(ctrl, dlg);
319 for (i = 0; (cp = cp_enumerate(i)) != NULL; i++)
320 dlg_listbox_add(ctrl, dlg, cp);
321 dlg_editbox_set(ctrl, dlg, cfg->line_codepage);
322 dlg_update_done(ctrl, dlg);
323 } else if (event == EVENT_VALCHANGE) {
324 dlg_editbox_get(ctrl, dlg, cfg->line_codepage,
325 sizeof(cfg->line_codepage));
326 strcpy(cfg->line_codepage,
327 cp_name(decode_codepage(cfg->line_codepage)));
328 }
329}
330
331static void sshbug_handler(union control *ctrl, void *dlg,
332 void *data, int event)
333{
334 if (event == EVENT_REFRESH) {
335 dlg_update_start(ctrl, dlg);
336 dlg_listbox_clear(ctrl, dlg);
4eaff8d4 337 dlg_listbox_addwithid(ctrl, dlg, "Auto", AUTO);
338 dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF);
339 dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON);
fe8abbf4 340 switch (*(int *)ATOFFSET(data, ctrl->listbox.context.i)) {
341 case AUTO: dlg_listbox_select(ctrl, dlg, 0); break;
342 case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break;
343 case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break;
344 }
345 dlg_update_done(ctrl, dlg);
346 } else if (event == EVENT_SELCHANGE) {
347 int i = dlg_listbox_index(ctrl, dlg);
348 if (i < 0)
349 i = AUTO;
350 else
351 i = dlg_listbox_getid(ctrl, dlg, i);
352 *(int *)ATOFFSET(data, ctrl->listbox.context.i) = i;
353 }
354}
355
4e6d4091 356#define SAVEDSESSION_LEN 2048
357
fe8abbf4 358struct sessionsaver_data {
359 union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
360 union control *okbutton, *cancelbutton;
12745e35 361 struct sesslist sesslist;
2e155f47 362 int midsession;
fe8abbf4 363};
364
365/*
366 * Helper function to load the session selected in the list box, if
367 * any, as this is done in more than one place below. Returns 0 for
368 * failure.
369 */
370static int load_selected_session(struct sessionsaver_data *ssd,
4e6d4091 371 char *savedsession,
fe8abbf4 372 void *dlg, Config *cfg)
373{
374 int i = dlg_listbox_index(ssd->listbox, dlg);
375 int isdef;
376 if (i < 0) {
377 dlg_beep(dlg);
378 return 0;
379 }
12745e35 380 isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
381 load_settings(ssd->sesslist.sessions[i], !isdef, cfg);
fe8abbf4 382 if (!isdef) {
12745e35 383 strncpy(savedsession, ssd->sesslist.sessions[i],
4e6d4091 384 SAVEDSESSION_LEN);
385 savedsession[SAVEDSESSION_LEN-1] = '\0';
fe8abbf4 386 } else {
4e6d4091 387 savedsession[0] = '\0';
fe8abbf4 388 }
389 dlg_refresh(NULL, dlg);
390 /* Restore the selection, which might have been clobbered by
391 * changing the value of the edit box. */
392 dlg_listbox_select(ssd->listbox, dlg, i);
393 return 1;
394}
395
396static void sessionsaver_handler(union control *ctrl, void *dlg,
397 void *data, int event)
398{
399 Config *cfg = (Config *)data;
400 struct sessionsaver_data *ssd =
401 (struct sessionsaver_data *)ctrl->generic.context.p;
4e6d4091 402 char *savedsession;
403
404 /*
405 * The first time we're called in a new dialog, we must
406 * allocate space to store the current contents of the saved
407 * session edit box (since it must persist even when we switch
408 * panels, but is not part of the Config).
409 */
56b9b9a7 410 if (!ssd->editbox) {
411 savedsession = NULL;
412 } else if (!dlg_get_privdata(ssd->editbox, dlg)) {
4e6d4091 413 savedsession = (char *)
414 dlg_alloc_privdata(ssd->editbox, dlg, SAVEDSESSION_LEN);
415 savedsession[0] = '\0';
416 } else {
417 savedsession = dlg_get_privdata(ssd->editbox, dlg);
418 }
fe8abbf4 419
420 if (event == EVENT_REFRESH) {
421 if (ctrl == ssd->editbox) {
4e6d4091 422 dlg_editbox_set(ctrl, dlg, savedsession);
fe8abbf4 423 } else if (ctrl == ssd->listbox) {
424 int i;
425 dlg_update_start(ctrl, dlg);
426 dlg_listbox_clear(ctrl, dlg);
12745e35 427 for (i = 0; i < ssd->sesslist.nsessions; i++)
428 dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]);
fe8abbf4 429 dlg_update_done(ctrl, dlg);
430 }
431 } else if (event == EVENT_VALCHANGE) {
dcfd0728 432 int top, bottom, halfway, i;
fe8abbf4 433 if (ctrl == ssd->editbox) {
4e6d4091 434 dlg_editbox_get(ctrl, dlg, savedsession,
435 SAVEDSESSION_LEN);
dcfd0728 436 top = ssd->sesslist.nsessions;
437 bottom = -1;
438 while (top-bottom > 1) {
439 halfway = (top+bottom)/2;
440 i = strcmp(savedsession, ssd->sesslist.sessions[halfway]);
441 if (i <= 0 ) {
442 top = halfway;
443 } else {
444 bottom = halfway;
445 }
446 }
447 if (top == ssd->sesslist.nsessions) {
448 top -= 1;
449 }
450 dlg_listbox_select(ssd->listbox, dlg, top);
fe8abbf4 451 }
452 } else if (event == EVENT_ACTION) {
2e155f47 453 if (!ssd->midsession &&
454 (ctrl == ssd->listbox ||
455 (ssd->loadbutton && ctrl == ssd->loadbutton))) {
fe8abbf4 456 /*
457 * The user has double-clicked a session, or hit Load.
458 * We must load the selected session, and then
459 * terminate the configuration dialog _if_ there was a
460 * double-click on the list box _and_ that session
461 * contains a hostname.
462 */
4e6d4091 463 if (load_selected_session(ssd, savedsession, dlg, cfg) &&
7374c779 464 (ctrl == ssd->listbox && cfg_launchable(cfg))) {
fe8abbf4 465 dlg_end(dlg, 1); /* it's all over, and succeeded */
466 }
467 } else if (ctrl == ssd->savebutton) {
4e6d4091 468 int isdef = !strcmp(savedsession, "Default Settings");
469 if (!savedsession[0]) {
8b0cb5aa 470 int i = dlg_listbox_index(ssd->listbox, dlg);
fe8abbf4 471 if (i < 0) {
472 dlg_beep(dlg);
473 return;
474 }
12745e35 475 isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
fe8abbf4 476 if (!isdef) {
12745e35 477 strncpy(savedsession, ssd->sesslist.sessions[i],
4e6d4091 478 SAVEDSESSION_LEN);
479 savedsession[SAVEDSESSION_LEN-1] = '\0';
fe8abbf4 480 } else {
4e6d4091 481 savedsession[0] = '\0';
fe8abbf4 482 }
483 }
3f935d5b 484 {
485 char *errmsg = save_settings(savedsession, !isdef, cfg);
486 if (errmsg) {
487 dlg_error_msg(dlg, errmsg);
488 sfree(errmsg);
489 }
490 }
12745e35 491 get_sesslist(&ssd->sesslist, FALSE);
492 get_sesslist(&ssd->sesslist, TRUE);
fe8abbf4 493 dlg_refresh(ssd->editbox, dlg);
494 dlg_refresh(ssd->listbox, dlg);
2e155f47 495 } else if (!ssd->midsession &&
496 ssd->delbutton && ctrl == ssd->delbutton) {
6f87d111 497 int i = dlg_listbox_index(ssd->listbox, dlg);
fe8abbf4 498 if (i <= 0) {
499 dlg_beep(dlg);
500 } else {
12745e35 501 del_settings(ssd->sesslist.sessions[i]);
502 get_sesslist(&ssd->sesslist, FALSE);
503 get_sesslist(&ssd->sesslist, TRUE);
fe8abbf4 504 dlg_refresh(ssd->listbox, dlg);
505 }
506 } else if (ctrl == ssd->okbutton) {
2e155f47 507 if (ssd->midsession) {
56b9b9a7 508 /* In a mid-session Change Settings, Apply is always OK. */
509 dlg_end(dlg, 1);
510 return;
511 }
fe8abbf4 512 /*
513 * Annoying special case. If the `Open' button is
514 * pressed while no host name is currently set, _and_
515 * the session list previously had the focus, _and_
516 * there was a session selected in that which had a
517 * valid host name in it, then load it and go.
518 */
7374c779 519 if (dlg_last_focused(ctrl, dlg) == ssd->listbox &&
520 !cfg_launchable(cfg)) {
fe8abbf4 521 Config cfg2;
4e6d4091 522 if (!load_selected_session(ssd, savedsession, dlg, &cfg2)) {
fe8abbf4 523 dlg_beep(dlg);
524 return;
525 }
526 /* If at this point we have a valid session, go! */
527 if (*cfg2.host) {
528 *cfg = cfg2; /* structure copy */
04c52f10 529 cfg->remote_cmd_ptr = NULL;
fe8abbf4 530 dlg_end(dlg, 1);
531 } else
532 dlg_beep(dlg);
431c0a12 533 return;
fe8abbf4 534 }
535
536 /*
537 * Otherwise, do the normal thing: if we have a valid
538 * session, get going.
539 */
7374c779 540 if (cfg_launchable(cfg)) {
fe8abbf4 541 dlg_end(dlg, 1);
542 } else
543 dlg_beep(dlg);
544 } else if (ctrl == ssd->cancelbutton) {
545 dlg_end(dlg, 0);
546 }
547 }
548}
549
550struct charclass_data {
551 union control *listbox, *editbox, *button;
552};
553
554static void charclass_handler(union control *ctrl, void *dlg,
555 void *data, int event)
556{
557 Config *cfg = (Config *)data;
558 struct charclass_data *ccd =
559 (struct charclass_data *)ctrl->generic.context.p;
560
561 if (event == EVENT_REFRESH) {
562 if (ctrl == ccd->listbox) {
563 int i;
564 dlg_update_start(ctrl, dlg);
565 dlg_listbox_clear(ctrl, dlg);
566 for (i = 0; i < 128; i++) {
567 char str[100];
568 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
569 (i >= 0x21 && i != 0x7F) ? i : ' ', cfg->wordness[i]);
570 dlg_listbox_add(ctrl, dlg, str);
571 }
572 dlg_update_done(ctrl, dlg);
573 }
574 } else if (event == EVENT_ACTION) {
575 if (ctrl == ccd->button) {
576 char str[100];
577 int i, n;
578 dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str));
579 n = atoi(str);
580 for (i = 0; i < 128; i++) {
581 if (dlg_listbox_issel(ccd->listbox, dlg, i))
582 cfg->wordness[i] = n;
583 }
584 dlg_refresh(ccd->listbox, dlg);
585 }
586 }
587}
588
589struct colour_data {
18c2f87c 590 union control *listbox, *redit, *gedit, *bedit, *button;
fe8abbf4 591};
592
593static const char *const colours[] = {
594 "Default Foreground", "Default Bold Foreground",
595 "Default Background", "Default Bold Background",
596 "Cursor Text", "Cursor Colour",
597 "ANSI Black", "ANSI Black Bold",
598 "ANSI Red", "ANSI Red Bold",
599 "ANSI Green", "ANSI Green Bold",
600 "ANSI Yellow", "ANSI Yellow Bold",
601 "ANSI Blue", "ANSI Blue Bold",
602 "ANSI Magenta", "ANSI Magenta Bold",
603 "ANSI Cyan", "ANSI Cyan Bold",
604 "ANSI White", "ANSI White Bold"
605};
606
607static void colour_handler(union control *ctrl, void *dlg,
608 void *data, int event)
609{
610 Config *cfg = (Config *)data;
611 struct colour_data *cd =
612 (struct colour_data *)ctrl->generic.context.p;
613 int update = FALSE, r, g, b;
614
615 if (event == EVENT_REFRESH) {
616 if (ctrl == cd->listbox) {
617 int i;
618 dlg_update_start(ctrl, dlg);
619 dlg_listbox_clear(ctrl, dlg);
620 for (i = 0; i < lenof(colours); i++)
621 dlg_listbox_add(ctrl, dlg, colours[i]);
622 dlg_update_done(ctrl, dlg);
18c2f87c 623 dlg_editbox_set(cd->redit, dlg, "");
624 dlg_editbox_set(cd->gedit, dlg, "");
625 dlg_editbox_set(cd->bedit, dlg, "");
fe8abbf4 626 }
627 } else if (event == EVENT_SELCHANGE) {
628 if (ctrl == cd->listbox) {
629 /* The user has selected a colour. Update the RGB text. */
630 int i = dlg_listbox_index(ctrl, dlg);
631 if (i < 0) {
632 dlg_beep(dlg);
633 return;
634 }
635 r = cfg->colours[i][0];
636 g = cfg->colours[i][1];
637 b = cfg->colours[i][2];
638 update = TRUE;
639 }
18c2f87c 640 } else if (event == EVENT_VALCHANGE) {
641 if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) {
642 /* The user has changed the colour using the edit boxes. */
643 char buf[80];
644 int i, cval;
645
646 dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
3d025d91 647 cval = atoi(buf);
648 if (cval > 255) cval = 255;
649 if (cval < 0) cval = 0;
18c2f87c 650
651 i = dlg_listbox_index(cd->listbox, dlg);
652 if (i >= 0) {
653 if (ctrl == cd->redit)
654 cfg->colours[i][0] = cval;
655 else if (ctrl == cd->gedit)
656 cfg->colours[i][1] = cval;
657 else if (ctrl == cd->bedit)
658 cfg->colours[i][2] = cval;
659 }
660 }
fe8abbf4 661 } else if (event == EVENT_ACTION) {
662 if (ctrl == cd->button) {
663 int i = dlg_listbox_index(cd->listbox, dlg);
664 if (i < 0) {
665 dlg_beep(dlg);
666 return;
667 }
668 /*
669 * Start a colour selector, which will send us an
670 * EVENT_CALLBACK when it's finished and allow us to
671 * pick up the results.
672 */
673 dlg_coloursel_start(ctrl, dlg,
674 cfg->colours[i][0],
675 cfg->colours[i][1],
676 cfg->colours[i][2]);
677 }
678 } else if (event == EVENT_CALLBACK) {
679 if (ctrl == cd->button) {
680 int i = dlg_listbox_index(cd->listbox, dlg);
681 /*
682 * Collect the results of the colour selector. Will
683 * return nonzero on success, or zero if the colour
684 * selector did nothing (user hit Cancel, for example).
685 */
686 if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
687 cfg->colours[i][0] = r;
688 cfg->colours[i][1] = g;
689 cfg->colours[i][2] = b;
690 update = TRUE;
691 }
692 }
693 }
694
695 if (update) {
696 char buf[40];
18c2f87c 697 sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
698 sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
699 sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
fe8abbf4 700 }
701}
702
c6ccd5c2 703struct ttymodes_data {
704 union control *modelist, *valradio, *valbox;
705 union control *addbutton, *rembutton, *listbox;
706};
707
708static void ttymodes_handler(union control *ctrl, void *dlg,
709 void *data, int event)
710{
711 Config *cfg = (Config *)data;
712 struct ttymodes_data *td =
713 (struct ttymodes_data *)ctrl->generic.context.p;
714
715 if (event == EVENT_REFRESH) {
716 if (ctrl == td->listbox) {
717 char *p = cfg->ttymodes;
718 dlg_update_start(ctrl, dlg);
719 dlg_listbox_clear(ctrl, dlg);
720 while (*p) {
721 int tabpos = strchr(p, '\t') - p;
722 char *disp = dupprintf("%.*s\t%s", tabpos, p,
723 (p[tabpos+1] == 'A') ? "(auto)" :
724 p+tabpos+2);
725 dlg_listbox_add(ctrl, dlg, disp);
726 p += strlen(p) + 1;
727 sfree(disp);
728 }
729 dlg_update_done(ctrl, dlg);
730 } else if (ctrl == td->modelist) {
731 int i;
732 dlg_update_start(ctrl, dlg);
733 dlg_listbox_clear(ctrl, dlg);
734 for (i = 0; ttymodes[i]; i++)
735 dlg_listbox_add(ctrl, dlg, ttymodes[i]);
736 dlg_listbox_select(ctrl, dlg, 0); /* *shrug* */
737 dlg_update_done(ctrl, dlg);
738 } else if (ctrl == td->valradio) {
739 dlg_radiobutton_set(ctrl, dlg, 0);
740 }
741 } else if (event == EVENT_ACTION) {
742 if (ctrl == td->addbutton) {
743 int ind = dlg_listbox_index(td->modelist, dlg);
744 if (ind >= 0) {
745 char type = dlg_radiobutton_get(td->valradio, dlg) ? 'V' : 'A';
746 int slen, left;
747 char *p, str[lenof(cfg->ttymodes)];
748 /* Construct new entry */
749 memset(str, 0, lenof(str));
750 strncpy(str, ttymodes[ind], lenof(str)-3);
751 slen = strlen(str);
752 str[slen] = '\t';
753 str[slen+1] = type;
754 slen += 2;
755 if (type == 'V') {
756 dlg_editbox_get(td->valbox, dlg, str+slen, lenof(str)-slen);
757 }
758 /* Find end of list, deleting any existing instance */
759 p = cfg->ttymodes;
760 left = lenof(cfg->ttymodes);
761 while (*p) {
762 int t = strchr(p, '\t') - p;
763 if (t == strlen(ttymodes[ind]) &&
764 strncmp(p, ttymodes[ind], t) == 0) {
765 memmove(p, p+strlen(p)+1, left - (strlen(p)+1));
766 continue;
767 }
768 left -= strlen(p) + 1;
769 p += strlen(p) + 1;
770 }
771 /* Append new entry */
772 memset(p, 0, left);
773 strncpy(p, str, left - 2);
774 dlg_refresh(td->listbox, dlg);
775 } else
776 dlg_beep(dlg);
777 } else if (ctrl == td->rembutton) {
778 char *p = cfg->ttymodes;
779 int i = 0, len = lenof(cfg->ttymodes);
780 while (*p) {
781 if (dlg_listbox_issel(td->listbox, dlg, i)) {
782 memmove(p, p+strlen(p)+1, len - (strlen(p)+1));
783 i++;
784 continue;
785 }
786 len -= strlen(p) + 1;
787 p += strlen(p) + 1;
788 i++;
789 }
790 memset(p, 0, lenof(cfg->ttymodes) - len);
791 dlg_refresh(td->listbox, dlg);
792 }
793 }
794}
795
fe8abbf4 796struct environ_data {
797 union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
798};
799
800static void environ_handler(union control *ctrl, void *dlg,
801 void *data, int event)
802{
803 Config *cfg = (Config *)data;
804 struct environ_data *ed =
805 (struct environ_data *)ctrl->generic.context.p;
806
807 if (event == EVENT_REFRESH) {
808 if (ctrl == ed->listbox) {
809 char *p = cfg->environmt;
810 dlg_update_start(ctrl, dlg);
811 dlg_listbox_clear(ctrl, dlg);
812 while (*p) {
813 dlg_listbox_add(ctrl, dlg, p);
814 p += strlen(p) + 1;
815 }
816 dlg_update_done(ctrl, dlg);
817 }
818 } else if (event == EVENT_ACTION) {
819 if (ctrl == ed->addbutton) {
820 char str[sizeof(cfg->environmt)];
821 char *p;
822 dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1);
823 if (!*str) {
824 dlg_beep(dlg);
825 return;
826 }
827 p = str + strlen(str);
828 *p++ = '\t';
829 dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str));
830 if (!*p) {
831 dlg_beep(dlg);
832 return;
833 }
834 p = cfg->environmt;
835 while (*p) {
836 while (*p)
837 p++;
838 p++;
839 }
840 if ((p - cfg->environmt) + strlen(str) + 2 <
841 sizeof(cfg->environmt)) {
842 strcpy(p, str);
843 p[strlen(str) + 1] = '\0';
844 dlg_listbox_add(ed->listbox, dlg, str);
845 dlg_editbox_set(ed->varbox, dlg, "");
846 dlg_editbox_set(ed->valbox, dlg, "");
847 } else {
848 dlg_error_msg(dlg, "Environment too big");
849 }
850 } else if (ctrl == ed->rembutton) {
851 int i = dlg_listbox_index(ed->listbox, dlg);
852 if (i < 0) {
853 dlg_beep(dlg);
854 } else {
855 char *p, *q;
856
857 dlg_listbox_del(ed->listbox, dlg, i);
858 p = cfg->environmt;
859 while (i > 0) {
860 if (!*p)
861 goto disaster;
862 while (*p)
863 p++;
864 p++;
865 i--;
866 }
867 q = p;
868 if (!*p)
869 goto disaster;
870 while (*p)
871 p++;
872 p++;
873 while (*p) {
874 while (*p)
875 *q++ = *p++;
876 *q++ = *p++;
877 }
878 *q = '\0';
879 disaster:;
880 }
881 }
882 }
883}
884
885struct portfwd_data {
886 union control *addbutton, *rembutton, *listbox;
887 union control *sourcebox, *destbox, *direction;
89adc0e2 888#ifndef NO_IPV6
05581745 889 union control *addressfamily;
89adc0e2 890#endif
fe8abbf4 891};
892
893static void portfwd_handler(union control *ctrl, void *dlg,
894 void *data, int event)
895{
896 Config *cfg = (Config *)data;
897 struct portfwd_data *pfd =
898 (struct portfwd_data *)ctrl->generic.context.p;
899
900 if (event == EVENT_REFRESH) {
901 if (ctrl == pfd->listbox) {
902 char *p = cfg->portfwd;
903 dlg_update_start(ctrl, dlg);
904 dlg_listbox_clear(ctrl, dlg);
905 while (*p) {
906 dlg_listbox_add(ctrl, dlg, p);
907 p += strlen(p) + 1;
908 }
909 dlg_update_done(ctrl, dlg);
07e4d76d 910 } else if (ctrl == pfd->direction) {
911 /*
912 * Default is Local.
913 */
914 dlg_radiobutton_set(ctrl, dlg, 0);
89adc0e2 915#ifndef NO_IPV6
916 } else if (ctrl == pfd->addressfamily) {
05581745 917 dlg_radiobutton_set(ctrl, dlg, 0);
89adc0e2 918#endif
fe8abbf4 919 }
920 } else if (event == EVENT_ACTION) {
921 if (ctrl == pfd->addbutton) {
922 char str[sizeof(cfg->portfwd)];
923 char *p;
05581745 924 int i, type;
925 int whichbutton;
926
927 i = 0;
89adc0e2 928#ifndef NO_IPV6
05581745 929 whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
930 if (whichbutton == 1)
931 str[i++] = '4';
932 else if (whichbutton == 2)
933 str[i++] = '6';
89adc0e2 934#endif
05581745 935
936 whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
820ebe3b 937 if (whichbutton == 0)
05581745 938 type = 'L';
820ebe3b 939 else if (whichbutton == 1)
05581745 940 type = 'R';
820ebe3b 941 else
05581745 942 type = 'D';
943 str[i++] = type;
944
945 dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i);
94042edc 946 if (!str[i]) {
fe8abbf4 947 dlg_error_msg(dlg, "You need to specify a source port number");
948 return;
949 }
950 p = str + strlen(str);
05581745 951 if (type != 'D') {
820ebe3b 952 *p++ = '\t';
953 dlg_editbox_get(pfd->destbox, dlg, p,
e49c58ed 954 sizeof(str) - (p - str));
820ebe3b 955 if (!*p || !strchr(p, ':')) {
956 dlg_error_msg(dlg,
957 "You need to specify a destination address\n"
958 "in the form \"host.name:port\"");
959 return;
960 }
961 } else
962 *p = '\0';
fe8abbf4 963 p = cfg->portfwd;
964 while (*p) {
965 while (*p)
966 p++;
967 p++;
968 }
e49c58ed 969 if ((p - cfg->portfwd) + strlen(str) + 2 <=
fe8abbf4 970 sizeof(cfg->portfwd)) {
971 strcpy(p, str);
972 p[strlen(str) + 1] = '\0';
973 dlg_listbox_add(pfd->listbox, dlg, str);
974 dlg_editbox_set(pfd->sourcebox, dlg, "");
975 dlg_editbox_set(pfd->destbox, dlg, "");
976 } else {
977 dlg_error_msg(dlg, "Too many forwardings");
978 }
979 } else if (ctrl == pfd->rembutton) {
980 int i = dlg_listbox_index(pfd->listbox, dlg);
981 if (i < 0)
982 dlg_beep(dlg);
983 else {
984 char *p, *q;
985
986 dlg_listbox_del(pfd->listbox, dlg, i);
987 p = cfg->portfwd;
988 while (i > 0) {
989 if (!*p)
990 goto disaster2;
991 while (*p)
992 p++;
993 p++;
994 i--;
995 }
996 q = p;
997 if (!*p)
998 goto disaster2;
999 while (*p)
1000 p++;
1001 p++;
1002 while (*p) {
1003 while (*p)
1004 *q++ = *p++;
1005 *q++ = *p++;
1006 }
1007 *q = '\0';
1008 disaster2:;
1009 }
1010 }
1011 }
1012}
1013
12745e35 1014void setup_config_box(struct controlbox *b, int midsession,
1015 int protocol, int protcfginfo)
fe8abbf4 1016{
1017 struct controlset *s;
1018 struct sessionsaver_data *ssd;
1019 struct charclass_data *ccd;
1020 struct colour_data *cd;
c6ccd5c2 1021 struct ttymodes_data *td;
fe8abbf4 1022 struct environ_data *ed;
1023 struct portfwd_data *pfd;
1024 union control *c;
f6f450e2 1025 char *str;
fe8abbf4 1026
1027 ssd = (struct sessionsaver_data *)
1028 ctrl_alloc(b, sizeof(struct sessionsaver_data));
56b9b9a7 1029 memset(ssd, 0, sizeof(*ssd));
2e155f47 1030 ssd->midsession = midsession;
fe8abbf4 1031
1032 /*
1033 * The standard panel that appears at the bottom of all panels:
1034 * Open, Cancel, Apply etc.
1035 */
1036 s = ctrl_getset(b, "", "", "");
1037 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
1038 ssd->okbutton = ctrl_pushbutton(s,
1039 (midsession ? "Apply" : "Open"),
1040 (char)(midsession ? 'a' : 'o'),
1041 HELPCTX(no_help),
1042 sessionsaver_handler, P(ssd));
1043 ssd->okbutton->button.isdefault = TRUE;
1044 ssd->okbutton->generic.column = 3;
1045 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
1046 sessionsaver_handler, P(ssd));
0bd8d76d 1047 ssd->cancelbutton->button.iscancel = TRUE;
fe8abbf4 1048 ssd->cancelbutton->generic.column = 4;
1049 /* We carefully don't close the 5-column part, so that platform-
1050 * specific add-ons can put extra buttons alongside Open and Cancel. */
1051
1052 /*
1053 * The Session panel.
1054 */
f6f450e2 1055 str = dupprintf("Basic options for your %s session", appname);
1056 ctrl_settitle(b, "Session", str);
1057 sfree(str);
fe8abbf4 1058
1059 if (!midsession) {
7374c779 1060 struct hostport *hp = (struct hostport *)
1061 ctrl_alloc(b, sizeof(struct hostport));
1062 int i, gotssh;
1063
fe8abbf4 1064 s = ctrl_getset(b, "Session", "hostport",
7374c779 1065 "Specify the destination you want to connect to");
fe8abbf4 1066 ctrl_columns(s, 2, 75, 25);
7374c779 1067 c = ctrl_editbox(s, HOST_BOX_TITLE, 'n', 100,
fe8abbf4 1068 HELPCTX(session_hostname),
7374c779 1069 config_host_handler, I(0), I(0));
fe8abbf4 1070 c->generic.column = 0;
7374c779 1071 hp->host = c;
1072 c = ctrl_editbox(s, PORT_BOX_TITLE, 'p', 100,
1073 HELPCTX(session_hostname),
1074 config_port_handler, I(0), I(0));
fe8abbf4 1075 c->generic.column = 1;
7374c779 1076 hp->port = c;
fe8abbf4 1077 ctrl_columns(s, 1, 100);
7374c779 1078
1079 gotssh = FALSE;
1080 for (i = 0; backends[i].name; i++)
1081 if (backends[i].protocol == PROT_SSH) {
1082 gotssh = TRUE;
1083 break;
1084 }
1085 if (!gotssh) {
1086 ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 3,
fe8abbf4 1087 HELPCTX(session_hostname),
7374c779 1088 config_protocolbuttons_handler, P(hp),
fe8abbf4 1089 "Raw", 'r', I(PROT_RAW),
1090 "Telnet", 't', I(PROT_TELNET),
1091 "Rlogin", 'i', I(PROT_RLOGIN),
1092 NULL);
1093 } else {
7374c779 1094 ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 4,
fe8abbf4 1095 HELPCTX(session_hostname),
7374c779 1096 config_protocolbuttons_handler, P(hp),
fe8abbf4 1097 "Raw", 'r', I(PROT_RAW),
1098 "Telnet", 't', I(PROT_TELNET),
1099 "Rlogin", 'i', I(PROT_RLOGIN),
1100 "SSH", 's', I(PROT_SSH),
1101 NULL);
1102 }
fe8abbf4 1103 }
1104
48c4dd7c 1105 /*
1106 * The Load/Save panel is available even in mid-session.
1107 */
1108 s = ctrl_getset(b, "Session", "savedsessions",
59b8cd5a 1109 midsession ? "Save the current session settings" :
48c4dd7c 1110 "Load, save or delete a stored session");
1111 ctrl_columns(s, 2, 75, 25);
12745e35 1112 get_sesslist(&ssd->sesslist, TRUE);
48c4dd7c 1113 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
1114 HELPCTX(session_saved),
1115 sessionsaver_handler, P(ssd), P(NULL));
1116 ssd->editbox->generic.column = 0;
1117 /* Reset columns so that the buttons are alongside the list, rather
1118 * than alongside that edit box. */
1119 ctrl_columns(s, 1, 100);
1120 ctrl_columns(s, 2, 75, 25);
1121 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1122 HELPCTX(session_saved),
1123 sessionsaver_handler, P(ssd));
1124 ssd->listbox->generic.column = 0;
1125 ssd->listbox->listbox.height = 7;
2e155f47 1126 if (!midsession) {
1127 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
1128 HELPCTX(session_saved),
1129 sessionsaver_handler, P(ssd));
1130 ssd->loadbutton->generic.column = 1;
1131 } else {
1132 /* We can't offer the Load button mid-session, as it would allow the
1133 * user to load and subsequently save settings they can't see. (And
1134 * also change otherwise immutable settings underfoot; that probably
1135 * shouldn't be a problem, but.) */
1136 ssd->loadbutton = NULL;
1137 }
1138 /* "Save" button is permitted mid-session. */
48c4dd7c 1139 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
1140 HELPCTX(session_saved),
1141 sessionsaver_handler, P(ssd));
1142 ssd->savebutton->generic.column = 1;
2e155f47 1143 if (!midsession) {
1144 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
1145 HELPCTX(session_saved),
1146 sessionsaver_handler, P(ssd));
1147 ssd->delbutton->generic.column = 1;
1148 } else {
1149 /* Disable the Delete button mid-session too, for UI consistency. */
1150 ssd->delbutton = NULL;
1151 }
48c4dd7c 1152 ctrl_columns(s, 1, 100);
1153
fe8abbf4 1154 s = ctrl_getset(b, "Session", "otheropts", NULL);
1155 c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
1156 HELPCTX(session_coe),
1157 dlg_stdradiobutton_handler,
1158 I(offsetof(Config, close_on_exit)),
1159 "Always", I(FORCE_ON),
1160 "Never", I(FORCE_OFF),
1161 "Only on clean exit", I(AUTO), NULL);
1162
1163 /*
1164 * The Session/Logging panel.
1165 */
1166 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
1167
1168 s = ctrl_getset(b, "Session/Logging", "main", NULL);
3e547dd8 1169 /*
1170 * The logging buttons change depending on whether SSH packet
1171 * logging can sensibly be available.
1172 */
1173 {
1174 char *sshlogname;
1175 if ((midsession && protocol == PROT_SSH) ||
1176 (!midsession && backends[3].name != NULL))
1177 sshlogname = "Log SSH packet data";
1178 else
1179 sshlogname = NULL; /* this will disable the button */
1180 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 1,
1181 HELPCTX(logging_main),
17556692 1182 loggingbuttons_handler,
3e547dd8 1183 I(offsetof(Config, logtype)),
1184 "Logging turned off completely", 't', I(LGTYP_NONE),
1185 "Log printable output only", 'p', I(LGTYP_ASCII),
1186 "Log all session output", 'l', I(LGTYP_DEBUG),
1187 sshlogname, 's', I(LGTYP_PACKETS),
1188 NULL);
1189 }
fe8abbf4 1190 ctrl_filesel(s, "Log file name:", 'f',
1191 NULL, TRUE, "Select session log file name",
1192 HELPCTX(logging_filename),
1193 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
1194 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
1195 " &T for time, and &H for host name)",
1196 HELPCTX(logging_filename));
1197 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
1198 HELPCTX(logging_exists),
1199 dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
1200 "Always overwrite it", I(LGXF_OVR),
1201 "Always append to the end of it", I(LGXF_APN),
1202 "Ask the user every time", I(LGXF_ASK), NULL);
6d60c791 1203 ctrl_checkbox(s, "Flush log file frequently", 'u',
1204 HELPCTX(logging_flush),
1205 dlg_stdcheckbox_handler, I(offsetof(Config,logflush)));
fe8abbf4 1206
9a10ecf4 1207 if ((midsession && protocol == PROT_SSH) ||
1208 (!midsession && backends[3].name != NULL)) {
1209 s = ctrl_getset(b, "Session/Logging", "ssh",
1210 "Options specific to SSH packet logging");
1211 ctrl_checkbox(s, "Omit known password fields", 'k',
1212 HELPCTX(logging_ssh_omit_password),
1213 dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass)));
1214 ctrl_checkbox(s, "Omit session data", 'd',
1215 HELPCTX(logging_ssh_omit_data),
1216 dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata)));
1217 }
1218
fe8abbf4 1219 /*
1220 * The Terminal panel.
1221 */
1222 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
1223
1224 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
1225 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
1226 HELPCTX(terminal_autowrap),
1227 dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
1228 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
1229 HELPCTX(terminal_decom),
1230 dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
1231 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
1232 HELPCTX(terminal_lfhascr),
1233 dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
1234 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
1235 HELPCTX(terminal_bce),
1236 dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
1237 ctrl_checkbox(s, "Enable blinking text", 'n',
1238 HELPCTX(terminal_blink),
1239 dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
1240 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
1241 HELPCTX(terminal_answerback),
1242 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
1243 I(sizeof(((Config *)0)->answerback)));
1244
1245 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
1246 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
1247 HELPCTX(terminal_localecho),
1248 dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
1249 "Auto", I(AUTO),
1250 "Force on", I(FORCE_ON),
1251 "Force off", I(FORCE_OFF), NULL);
1252 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
1253 HELPCTX(terminal_localedit),
1254 dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
1255 "Auto", I(AUTO),
1256 "Force on", I(FORCE_ON),
1257 "Force off", I(FORCE_OFF), NULL);
1258
1259 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
1260 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
1261 HELPCTX(terminal_printing),
1262 printerbox_handler, P(NULL), P(NULL));
1263
1264 /*
1265 * The Terminal/Keyboard panel.
1266 */
1267 ctrl_settitle(b, "Terminal/Keyboard",
1268 "Options controlling the effects of keys");
1269
1270 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
1271 "Change the sequences sent by:");
1272 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
1273 HELPCTX(keyboard_backspace),
1274 dlg_stdradiobutton_handler,
1275 I(offsetof(Config, bksp_is_delete)),
1276 "Control-H", I(0), "Control-? (127)", I(1), NULL);
1277 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
1278 HELPCTX(keyboard_homeend),
1279 dlg_stdradiobutton_handler,
1280 I(offsetof(Config, rxvt_homeend)),
1281 "Standard", I(0), "rxvt", I(1), NULL);
1282 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
1283 HELPCTX(keyboard_funkeys),
1284 dlg_stdradiobutton_handler,
1285 I(offsetof(Config, funky_type)),
1286 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
1287 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
1288
1289 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
1290 "Application keypad settings:");
1291 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
1292 HELPCTX(keyboard_appcursor),
1293 dlg_stdradiobutton_handler,
1294 I(offsetof(Config, app_cursor)),
1295 "Normal", I(0), "Application", I(1), NULL);
1296 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
1297 HELPCTX(keyboard_appkeypad),
1298 numeric_keypad_handler, P(NULL),
1299 "Normal", I(0), "Application", I(1), "NetHack", I(2),
1300 NULL);
1301
1302 /*
1303 * The Terminal/Bell panel.
1304 */
1305 ctrl_settitle(b, "Terminal/Bell",
1306 "Options controlling the terminal bell");
1307
1308 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
1309 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
1310 HELPCTX(bell_style),
1311 dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
1312 "None (bell disabled)", I(BELL_DISABLED),
1313 "Make default system alert sound", I(BELL_DEFAULT),
1314 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
1315
1316 s = ctrl_getset(b, "Terminal/Bell", "overload",
1317 "Control the bell overload behaviour");
1318 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
1319 HELPCTX(bell_overload),
1320 dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
1321 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
1322 HELPCTX(bell_overload),
1323 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
1324 ctrl_editbox(s, "... in this many seconds", 't', 20,
1325 HELPCTX(bell_overload),
1326 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
62697e04 1327 I(-TICKSPERSEC));
fe8abbf4 1328 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
1329 HELPCTX(bell_overload));
1330 ctrl_editbox(s, "Seconds of silence required", 's', 20,
1331 HELPCTX(bell_overload),
1332 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
62697e04 1333 I(-TICKSPERSEC));
fe8abbf4 1334
1335 /*
1336 * The Terminal/Features panel.
1337 */
1338 ctrl_settitle(b, "Terminal/Features",
1339 "Enabling and disabling advanced terminal features");
1340
1341 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
1342 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
1343 HELPCTX(features_application),
1344 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
1345 ctrl_checkbox(s, "Disable application keypad mode", 'k',
1346 HELPCTX(features_application),
1347 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
1348 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
1349 HELPCTX(features_mouse),
1350 dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
1351 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
1352 HELPCTX(features_resize),
1353 dlg_stdcheckbox_handler,
1354 I(offsetof(Config,no_remote_resize)));
1355 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
1356 HELPCTX(features_altscreen),
1357 dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
1358 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
1359 HELPCTX(features_retitle),
1360 dlg_stdcheckbox_handler,
1361 I(offsetof(Config,no_remote_wintitle)));
7fcdebd3 1362 ctrl_checkbox(s, "Disable remote window title querying (SECURITY)",
1363 'q', HELPCTX(features_qtitle), dlg_stdcheckbox_handler,
1364 I(offsetof(Config,no_remote_qtitle)));
fe8abbf4 1365 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
1366 HELPCTX(features_dbackspace),
1367 dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
1368 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
1369 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
1370 I(offsetof(Config,no_remote_charset)));
f0fccd51 1371 ctrl_checkbox(s, "Disable Arabic text shaping",
f4ec0818 1372 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler,
f0fccd51 1373 I(offsetof(Config, arabicshaping)));
1374 ctrl_checkbox(s, "Disable bidirectional text display",
f4ec0818 1375 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler,
f0fccd51 1376 I(offsetof(Config, bidi)));
fe8abbf4 1377
1378 /*
1379 * The Window panel.
1380 */
f6f450e2 1381 str = dupprintf("Options controlling %s's window", appname);
1382 ctrl_settitle(b, "Window", str);
1383 sfree(str);
fe8abbf4 1384
1385 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
1386 ctrl_columns(s, 2, 50, 50);
1387 c = ctrl_editbox(s, "Rows", 'r', 100,
1388 HELPCTX(window_size),
1389 dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
1390 c->generic.column = 0;
1391 c = ctrl_editbox(s, "Columns", 'm', 100,
1392 HELPCTX(window_size),
1393 dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
1394 c->generic.column = 1;
1395 ctrl_columns(s, 1, 100);
1396
1397 s = ctrl_getset(b, "Window", "scrollback",
1398 "Control the scrollback in the window");
1399 ctrl_editbox(s, "Lines of scrollback", 's', 50,
1400 HELPCTX(window_scrollback),
1401 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
1402 ctrl_checkbox(s, "Display scrollbar", 'd',
1403 HELPCTX(window_scrollback),
1404 dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
fe8abbf4 1405 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
1406 HELPCTX(window_scrollback),
1407 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
1408 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
1409 HELPCTX(window_scrollback),
1410 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
876e5d5e 1411 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
1412 HELPCTX(window_erased),
1413 dlg_stdcheckbox_handler,
1414 I(offsetof(Config,erase_to_scrollback)));
fe8abbf4 1415
1416 /*
1417 * The Window/Appearance panel.
1418 */
f6f450e2 1419 str = dupprintf("Configure the appearance of %s's window", appname);
1420 ctrl_settitle(b, "Window/Appearance", str);
1421 sfree(str);
fe8abbf4 1422
1423 s = ctrl_getset(b, "Window/Appearance", "cursor",
1424 "Adjust the use of the cursor");
1425 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
1426 HELPCTX(appearance_cursor),
1427 dlg_stdradiobutton_handler,
1428 I(offsetof(Config, cursor_type)),
1429 "Block", 'l', I(0),
1430 "Underline", 'u', I(1),
1431 "Vertical line", 'v', I(2), NULL);
1432 ctrl_checkbox(s, "Cursor blinks", 'b',
1433 HELPCTX(appearance_cursor),
1434 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1435
1436 s = ctrl_getset(b, "Window/Appearance", "font",
1437 "Font settings");
1438 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1439 HELPCTX(appearance_font),
1440 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1441
1442 s = ctrl_getset(b, "Window/Appearance", "mouse",
1443 "Adjust the use of the mouse pointer");
1444 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1445 HELPCTX(appearance_hidemouse),
1446 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1447
1448 s = ctrl_getset(b, "Window/Appearance", "border",
1449 "Adjust the window border");
b908db15 1450 ctrl_editbox(s, "Gap between text and window edge:", 'e', 20,
fe8abbf4 1451 HELPCTX(appearance_border),
1452 dlg_stdeditbox_handler,
1453 I(offsetof(Config,window_border)), I(-1));
1454
1455 /*
1456 * The Window/Behaviour panel.
1457 */
f6f450e2 1458 str = dupprintf("Configure the behaviour of %s's window", appname);
1459 ctrl_settitle(b, "Window/Behaviour", str);
1460 sfree(str);
fe8abbf4 1461
1462 s = ctrl_getset(b, "Window/Behaviour", "title",
1463 "Adjust the behaviour of the window title");
1464 ctrl_editbox(s, "Window title:", 't', 100,
1465 HELPCTX(appearance_title),
1466 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1467 I(sizeof(((Config *)0)->wintitle)));
1468 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1469 HELPCTX(appearance_title),
1470 dlg_stdcheckbox_handler,
1471 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1472
1473 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1474 ctrl_checkbox(s, "Warn before closing window", 'w',
1475 HELPCTX(behaviour_closewarn),
1476 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1477
1478 /*
1479 * The Window/Translation panel.
1480 */
1481 ctrl_settitle(b, "Window/Translation",
1482 "Options controlling character set translation");
1483
1484 s = ctrl_getset(b, "Window/Translation", "trans",
1485 "Character set translation on received data");
1486 ctrl_combobox(s, "Received data assumed to be in which character set:",
1487 'r', 100, HELPCTX(translation_codepage),
1488 codepage_handler, P(NULL), P(NULL));
1489
74790953 1490 s = ctrl_getset(b, "Window/Translation", "tweaks", NULL);
1491 ctrl_checkbox(s, "Treat CJK ambiguous characters as wide", 'w',
1492 HELPCTX(translation_cjk_ambig_wide),
1493 dlg_stdcheckbox_handler, I(offsetof(Config,cjk_ambig_wide)));
1494
00381fc7 1495 str = dupprintf("Adjust how %s handles line drawing characters", appname);
f6f450e2 1496 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1497 sfree(str);
fe8abbf4 1498 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1499 HELPCTX(translation_linedraw),
1500 dlg_stdradiobutton_handler,
1501 I(offsetof(Config, vtmode)),
3900c2d6 1502 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
fe8abbf4 1503 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
3900c2d6 1504 NULL);
00381fc7 1505 ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
1506 HELPCTX(selection_linedraw),
1507 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
fe8abbf4 1508
1509 /*
1510 * The Window/Selection panel.
1511 */
1512 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
fe8abbf4 1513
1514 s = ctrl_getset(b, "Window/Selection", "mouse",
1515 "Control use of mouse");
1516 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1517 HELPCTX(selection_shiftdrag),
1518 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1519 ctrl_radiobuttons(s,
1520 "Default selection mode (Alt+drag does the other one):",
1521 NO_SHORTCUT, 2,
1522 HELPCTX(selection_rect),
1523 dlg_stdradiobutton_handler,
1524 I(offsetof(Config, rect_select)),
1525 "Normal", 'n', I(0),
1526 "Rectangular block", 'r', I(1), NULL);
1527
1528 s = ctrl_getset(b, "Window/Selection", "charclass",
1529 "Control the select-one-word-at-a-time mode");
1530 ccd = (struct charclass_data *)
1531 ctrl_alloc(b, sizeof(struct charclass_data));
1532 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1533 HELPCTX(selection_charclasses),
1534 charclass_handler, P(ccd));
1535 ccd->listbox->listbox.multisel = 1;
1536 ccd->listbox->listbox.ncols = 4;
3d88e64d 1537 ccd->listbox->listbox.percentages = snewn(4, int);
fe8abbf4 1538 ccd->listbox->listbox.percentages[0] = 15;
1539 ccd->listbox->listbox.percentages[1] = 25;
1540 ccd->listbox->listbox.percentages[2] = 20;
1541 ccd->listbox->listbox.percentages[3] = 40;
1542 ctrl_columns(s, 2, 67, 33);
1543 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1544 HELPCTX(selection_charclasses),
1545 charclass_handler, P(ccd), P(NULL));
1546 ccd->editbox->generic.column = 0;
1547 ccd->button = ctrl_pushbutton(s, "Set", 's',
1548 HELPCTX(selection_charclasses),
1549 charclass_handler, P(ccd));
1550 ccd->button->generic.column = 1;
1551 ctrl_columns(s, 1, 100);
1552
1553 /*
1554 * The Window/Colours panel.
1555 */
1556 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1557
1558 s = ctrl_getset(b, "Window/Colours", "general",
1559 "General options for colour usage");
c6f1b8ed 1560 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1561 HELPCTX(colours_ansi),
1562 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
cecb13f6 1563 ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
1564 HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
1565 I(offsetof(Config,xterm_256_colour)));
fe8abbf4 1566 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1567 HELPCTX(colours_bold),
1568 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1569
f6f450e2 1570 str = dupprintf("Adjust the precise colours %s displays", appname);
1571 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1572 sfree(str);
fe8abbf4 1573 ctrl_text(s, "Select a colour from the list, and then click the"
1574 " Modify button to change its appearance.",
1575 HELPCTX(colours_config));
1576 ctrl_columns(s, 2, 67, 33);
1577 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1578 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1579 HELPCTX(colours_config), colour_handler, P(cd));
1580 cd->listbox->generic.column = 0;
18c2f87c 1581 cd->listbox->listbox.height = 7;
fe8abbf4 1582 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1583 c->generic.column = 1;
18c2f87c 1584 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1585 colour_handler, P(cd), P(NULL));
1586 cd->redit->generic.column = 1;
1587 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1588 colour_handler, P(cd), P(NULL));
1589 cd->gedit->generic.column = 1;
1590 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1591 colour_handler, P(cd), P(NULL));
1592 cd->bedit->generic.column = 1;
fe8abbf4 1593 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1594 colour_handler, P(cd));
1595 cd->button->generic.column = 1;
1596 ctrl_columns(s, 1, 100);
1597
1598 /*
3e547dd8 1599 * The Connection panel. This doesn't show up if we're in a
1600 * non-network utility such as pterm. We tell this by being
1601 * passed a protocol < 0.
fe8abbf4 1602 */
3e547dd8 1603 if (protocol >= 0) {
1604 ctrl_settitle(b, "Connection", "Options controlling the connection");
1605
05581745 1606 s = ctrl_getset(b, "Connection", "keepalive",
1607 "Sending of null packets to keep session active");
1608 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1609 HELPCTX(connection_keepalive),
1610 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1611 I(-1));
1612
3e547dd8 1613 if (!midsession) {
05581745 1614 s = ctrl_getset(b, "Connection", "tcp",
1615 "Low-level TCP connection options");
1616 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1617 'n', HELPCTX(connection_nodelay),
1618 dlg_stdcheckbox_handler,
1619 I(offsetof(Config,tcp_nodelay)));
1620 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1621 'p', HELPCTX(connection_tcpkeepalive),
1622 dlg_stdcheckbox_handler,
1623 I(offsetof(Config,tcp_keepalives)));
22db244f 1624#ifndef NO_IPV6
05581745 1625 s = ctrl_getset(b, "Connection", "ipversion",
1626 "Internet protocol version");
22db244f 1627 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
05581745 1628 HELPCTX(connection_ipversion),
1629 dlg_stdradiobutton_handler,
1630 I(offsetof(Config, addressfamily)),
b908db15 1631 "Auto", 'u', I(ADDRTYPE_UNSPEC),
1632 "IPv4", '4', I(ADDRTYPE_IPV4),
1633 "IPv6", '6', I(ADDRTYPE_IPV6),
05581745 1634 NULL);
22db244f 1635#endif
05581745 1636 }
1637
1638 /*
1639 * A sub-panel Connection/Data, containing options that
1640 * decide on data to send to the server.
1641 */
1642 if (!midsession) {
1643 ctrl_settitle(b, "Connection/Data", "Data to send to the server");
1644
1645 s = ctrl_getset(b, "Connection/Data", "login",
1646 "Login details");
1647 ctrl_editbox(s, "Auto-login username", 'u', 50,
1648 HELPCTX(connection_username),
1649 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1650 I(sizeof(((Config *)0)->username)));
1651
1652 s = ctrl_getset(b, "Connection/Data", "term",
1653 "Terminal details");
3e547dd8 1654 ctrl_editbox(s, "Terminal-type string", 't', 50,
1655 HELPCTX(connection_termtype),
1656 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1657 I(sizeof(((Config *)0)->termtype)));
a5dd8467 1658 ctrl_editbox(s, "Terminal speeds", 's', 50,
1659 HELPCTX(connection_termspeed),
1660 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1661 I(sizeof(((Config *)0)->termspeed)));
73feed4f 1662
05581745 1663 s = ctrl_getset(b, "Connection/Data", "env",
1664 "Environment variables");
73feed4f 1665 ctrl_columns(s, 2, 80, 20);
1666 ed = (struct environ_data *)
1667 ctrl_alloc(b, sizeof(struct environ_data));
1668 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1669 HELPCTX(telnet_environ),
1670 environ_handler, P(ed), P(NULL));
1671 ed->varbox->generic.column = 0;
1672 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1673 HELPCTX(telnet_environ),
1674 environ_handler, P(ed), P(NULL));
1675 ed->valbox->generic.column = 0;
1676 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1677 HELPCTX(telnet_environ),
1678 environ_handler, P(ed));
1679 ed->addbutton->generic.column = 1;
1680 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1681 HELPCTX(telnet_environ),
1682 environ_handler, P(ed));
1683 ed->rembutton->generic.column = 1;
1684 ctrl_columns(s, 1, 100);
1685 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1686 HELPCTX(telnet_environ),
1687 environ_handler, P(ed));
1688 ed->listbox->listbox.height = 3;
1689 ed->listbox->listbox.ncols = 2;
1690 ed->listbox->listbox.percentages = snewn(2, int);
1691 ed->listbox->listbox.percentages[0] = 30;
1692 ed->listbox->listbox.percentages[1] = 70;
3e547dd8 1693 }
fe8abbf4 1694
fe8abbf4 1695 }
1696
1697 if (!midsession) {
1698 /*
1699 * The Connection/Proxy panel.
1700 */
1701 ctrl_settitle(b, "Connection/Proxy",
1702 "Options controlling proxy usage");
1703
10068a0b 1704 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1705 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
fe8abbf4 1706 HELPCTX(proxy_type),
1707 dlg_stdradiobutton_handler,
1708 I(offsetof(Config, proxy_type)),
0f0a2507 1709 "None", I(PROXY_NONE),
10068a0b 1710 "SOCKS 4", I(PROXY_SOCKS4),
1711 "SOCKS 5", I(PROXY_SOCKS5),
0f0a2507 1712 "HTTP", I(PROXY_HTTP),
0f0a2507 1713 "Telnet", I(PROXY_TELNET),
fe8abbf4 1714 NULL);
1715 ctrl_columns(s, 2, 80, 20);
1716 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1717 HELPCTX(proxy_main),
1718 dlg_stdeditbox_handler,
1719 I(offsetof(Config,proxy_host)),
1720 I(sizeof(((Config *)0)->proxy_host)));
1721 c->generic.column = 0;
1722 c = ctrl_editbox(s, "Port", 'p', 100,
1723 HELPCTX(proxy_main),
1724 dlg_stdeditbox_handler,
1725 I(offsetof(Config,proxy_port)),
1726 I(-1));
1727 c->generic.column = 1;
1728 ctrl_columns(s, 1, 100);
1729 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1730 HELPCTX(proxy_exclude),
1731 dlg_stdeditbox_handler,
1732 I(offsetof(Config,proxy_exclude_list)),
1733 I(sizeof(((Config *)0)->proxy_exclude_list)));
1734 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1735 HELPCTX(proxy_exclude),
1736 dlg_stdcheckbox_handler,
1737 I(offsetof(Config,even_proxy_localhost)));
1738 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1739 HELPCTX(proxy_dns),
1740 dlg_stdradiobutton_handler,
1741 I(offsetof(Config, proxy_dns)),
1742 "No", I(FORCE_OFF),
1743 "Auto", I(AUTO),
1744 "Yes", I(FORCE_ON), NULL);
1745 ctrl_editbox(s, "Username", 'u', 60,
1746 HELPCTX(proxy_auth),
1747 dlg_stdeditbox_handler,
1748 I(offsetof(Config,proxy_username)),
1749 I(sizeof(((Config *)0)->proxy_username)));
1750 c = ctrl_editbox(s, "Password", 'w', 60,
1751 HELPCTX(proxy_auth),
1752 dlg_stdeditbox_handler,
1753 I(offsetof(Config,proxy_password)),
1754 I(sizeof(((Config *)0)->proxy_password)));
1755 c->editbox.password = 1;
fe8abbf4 1756 ctrl_editbox(s, "Telnet command", 'm', 100,
1757 HELPCTX(proxy_command),
1758 dlg_stdeditbox_handler,
1759 I(offsetof(Config,proxy_telnet_command)),
1760 I(sizeof(((Config *)0)->proxy_telnet_command)));
fe8abbf4 1761 }
1762
1763 /*
1764 * The Telnet panel exists in the base config box, and in a
1765 * mid-session reconfig box _if_ we're using Telnet.
1766 */
1767 if (!midsession || protocol == PROT_TELNET) {
1768 /*
1769 * The Connection/Telnet panel.
1770 */
1771 ctrl_settitle(b, "Connection/Telnet",
1772 "Options controlling Telnet connections");
1773
fe8abbf4 1774 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1775 "Telnet protocol adjustments");
1776
1777 if (!midsession) {
1778 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1779 NO_SHORTCUT, 2,
1780 HELPCTX(telnet_oldenviron),
1781 dlg_stdradiobutton_handler,
1782 I(offsetof(Config, rfc_environ)),
1783 "BSD (commonplace)", 'b', I(0),
1784 "RFC 1408 (unusual)", 'f', I(1), NULL);
1785 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1786 HELPCTX(telnet_passive),
1787 dlg_stdradiobutton_handler,
1788 I(offsetof(Config, passive_telnet)),
1789 "Passive", I(1), "Active", I(0), NULL);
1790 }
76d3d354 1791 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
fe8abbf4 1792 HELPCTX(telnet_specialkeys),
1793 dlg_stdcheckbox_handler,
1794 I(offsetof(Config,telnet_keyboard)));
76d3d354 1795 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1796 'm', HELPCTX(telnet_newline),
fe8abbf4 1797 dlg_stdcheckbox_handler,
1798 I(offsetof(Config,telnet_newline)));
1799 }
1800
1801 if (!midsession) {
1802
1803 /*
1804 * The Connection/Rlogin panel.
1805 */
1806 ctrl_settitle(b, "Connection/Rlogin",
1807 "Options controlling Rlogin connections");
1808
1809 s = ctrl_getset(b, "Connection/Rlogin", "data",
1810 "Data to send to the server");
fe8abbf4 1811 ctrl_editbox(s, "Local username:", 'l', 50,
1812 HELPCTX(rlogin_localuser),
1813 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1814 I(sizeof(((Config *)0)->localusername)));
1815
1816 }
1817
1818 /*
fda2feb1 1819 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
1820 * when we're not doing SSH.
fe8abbf4 1821 */
1822
fda2feb1 1823 if (backends[3].name != NULL && (!midsession || protocol == PROT_SSH)) {
fe8abbf4 1824
1825 /*
1826 * The Connection/SSH panel.
1827 */
1828 ctrl_settitle(b, "Connection/SSH",
1829 "Options controlling SSH connections");
1830
e13bba36 1831 if (midsession && protcfginfo == 1) {
fda2feb1 1832 s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
1833 ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
1834 "session; it is only here so that sub-panels of it can "
1835 "exist without looking strange.", HELPCTX(no_help));
1836 }
1837
1838 if (!midsession) {
1839
1840 s = ctrl_getset(b, "Connection/SSH", "data",
1841 "Data to send to the server");
1842 ctrl_editbox(s, "Remote command:", 'r', 100,
1843 HELPCTX(ssh_command),
1844 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1845 I(sizeof(((Config *)0)->remote_cmd)));
1846
1847 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
fda2feb1 1848 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
1849 HELPCTX(ssh_noshell),
1850 dlg_stdcheckbox_handler,
1851 I(offsetof(Config,ssh_no_shell)));
e13bba36 1852 }
1853
1854 if (!midsession || protcfginfo != 1) {
1855 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1856
fda2feb1 1857 ctrl_checkbox(s, "Enable compression", 'e',
1858 HELPCTX(ssh_compress),
1859 dlg_stdcheckbox_handler,
1860 I(offsetof(Config,compression)));
e13bba36 1861 }
1862
1863 if (!midsession) {
1864 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1865
fda2feb1 1866 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1867 HELPCTX(ssh_protocol),
1868 dlg_stdradiobutton_handler,
1869 I(offsetof(Config, sshprot)),
1870 "1 only", 'l', I(0),
1871 "1", '1', I(1),
1872 "2", '2', I(2),
1873 "2 only", 'y', I(3), NULL);
e13bba36 1874 }
fda2feb1 1875
e13bba36 1876 if (!midsession || protcfginfo != 1) {
fda2feb1 1877 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1878 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1879 HELPCTX(ssh_ciphers),
1880 cipherlist_handler, P(NULL));
1881 c->listbox.height = 6;
1882
2e85c969 1883 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i',
bb524800 1884 HELPCTX(ssh_ciphers),
fda2feb1 1885 dlg_stdcheckbox_handler,
1886 I(offsetof(Config,ssh2_des_cbc)));
e6c1536e 1887 }
fe8abbf4 1888
e6c1536e 1889 /*
1890 * The Connection/SSH/Kex panel. (Owing to repeat key
f89c3294 1891 * exchange, this is all meaningful in mid-session _if_
2e85c969 1892 * we're using SSH-2 or haven't decided yet.)
e6c1536e 1893 */
f89c3294 1894 if (protcfginfo != 1) {
1895 ctrl_settitle(b, "Connection/SSH/Kex",
1896 "Options controlling SSH key exchange");
1897
1898 s = ctrl_getset(b, "Connection/SSH/Kex", "main",
1899 "Key exchange algorithm options");
2e077f2e 1900 c = ctrl_draglist(s, "Algorithm selection policy:", 's',
f89c3294 1901 HELPCTX(ssh_kexlist),
1902 kexlist_handler, P(NULL));
1903 c->listbox.height = 5;
1904
1905 s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
1906 "Options controlling key re-exchange");
1907
1908 ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
1909 HELPCTX(ssh_kex_repeat),
1910 dlg_stdeditbox_handler,
1911 I(offsetof(Config,ssh_rekey_time)),
1912 I(-1));
1913 ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
1914 HELPCTX(ssh_kex_repeat),
1915 dlg_stdeditbox_handler,
1916 I(offsetof(Config,ssh_rekey_data)),
1917 I(16));
1918 ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
1919 HELPCTX(ssh_kex_repeat));
1920 }
e6c1536e 1921
1922 if (!midsession) {
83e7d008 1923
fda2feb1 1924 /*
1925 * The Connection/SSH/Auth panel.
1926 */
1927 ctrl_settitle(b, "Connection/SSH/Auth",
1928 "Options controlling SSH authentication");
fe8abbf4 1929
a1a1fae4 1930 s = ctrl_getset(b, "Connection/SSH/Auth", "main", NULL);
1931 ctrl_checkbox(s, "Bypass authentication entirely (SSH-2 only)", 'b',
1932 HELPCTX(ssh_auth_bypass),
1933 dlg_stdcheckbox_handler,
1934 I(offsetof(Config,ssh_no_userauth)));
1935
fda2feb1 1936 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1937 "Authentication methods");
973612f5 1938 ctrl_checkbox(s, "Attempt authentication using Pageant", 'p',
1939 HELPCTX(ssh_auth_pageant),
1940 dlg_stdcheckbox_handler,
1941 I(offsetof(Config,tryagent)));
2e85c969 1942 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
fda2feb1 1943 HELPCTX(ssh_auth_tis),
1944 dlg_stdcheckbox_handler,
1945 I(offsetof(Config,try_tis_auth)));
2e85c969 1946 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH-2)",
fda2feb1 1947 'i', HELPCTX(ssh_auth_ki),
1948 dlg_stdcheckbox_handler,
1949 I(offsetof(Config,try_ki_auth)));
1950
1951 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1952 "Authentication parameters");
1953 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1954 HELPCTX(ssh_auth_agentfwd),
1955 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
2e85c969 1956 ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", 'u',
fda2feb1 1957 HELPCTX(ssh_auth_changeuser),
1958 dlg_stdcheckbox_handler,
1959 I(offsetof(Config,change_username)));
1960 ctrl_filesel(s, "Private key file for authentication:", 'k',
1961 FILTER_KEY_FILES, FALSE, "Select private key file",
1962 HELPCTX(ssh_auth_privkey),
1963 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1964 }
fe8abbf4 1965
fda2feb1 1966 if (!midsession) {
05581745 1967 /*
c6ccd5c2 1968 * The Connection/SSH/TTY panel.
1969 */
1970 ctrl_settitle(b, "Connection/SSH/TTY", "Remote terminal settings");
1971
1972 s = ctrl_getset(b, "Connection/SSH/TTY", "sshtty", NULL);
1973 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1974 HELPCTX(ssh_nopty),
1975 dlg_stdcheckbox_handler,
1976 I(offsetof(Config,nopty)));
1977
1978 s = ctrl_getset(b, "Connection/SSH/TTY", "ttymodes",
1979 "Terminal modes");
1980 td = (struct ttymodes_data *)
1981 ctrl_alloc(b, sizeof(struct ttymodes_data));
1982 ctrl_columns(s, 2, 75, 25);
1983 c = ctrl_text(s, "Terminal modes to send:", HELPCTX(ssh_ttymodes));
1984 c->generic.column = 0;
1985 td->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1986 HELPCTX(ssh_ttymodes),
1987 ttymodes_handler, P(td));
1988 td->rembutton->generic.column = 1;
1989 td->rembutton->generic.tabdelay = 1;
1990 ctrl_columns(s, 1, 100);
1991 td->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1992 HELPCTX(ssh_ttymodes),
1993 ttymodes_handler, P(td));
1994 td->listbox->listbox.multisel = 1;
1995 td->listbox->listbox.height = 4;
1996 td->listbox->listbox.ncols = 2;
1997 td->listbox->listbox.percentages = snewn(2, int);
1998 td->listbox->listbox.percentages[0] = 40;
1999 td->listbox->listbox.percentages[1] = 60;
2000 ctrl_tabdelay(s, td->rembutton);
2001 ctrl_columns(s, 2, 75, 25);
2002 td->modelist = ctrl_droplist(s, "Mode:", 'm', 67,
2003 HELPCTX(ssh_ttymodes),
2004 ttymodes_handler, P(td));
2005 td->modelist->generic.column = 0;
2006 td->addbutton = ctrl_pushbutton(s, "Add", 'd',
2007 HELPCTX(ssh_ttymodes),
2008 ttymodes_handler, P(td));
2009 td->addbutton->generic.column = 1;
2010 td->addbutton->generic.tabdelay = 1;
2011 ctrl_columns(s, 1, 100); /* column break */
2012 /* Bit of a hack to get the value radio buttons and
2013 * edit-box on the same row. */
2014 ctrl_columns(s, 3, 25, 50, 25);
2015 c = ctrl_text(s, "Value:", HELPCTX(ssh_ttymodes));
2016 c->generic.column = 0;
2017 td->valradio = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2,
2018 HELPCTX(ssh_ttymodes),
2019 ttymodes_handler, P(td),
2020 "Auto", NO_SHORTCUT, P(NULL),
2021 "This:", NO_SHORTCUT, P(NULL),
2022 NULL);
2023 td->valradio->generic.column = 1;
2024 td->valbox = ctrl_editbox(s, NULL, NO_SHORTCUT, 100,
2025 HELPCTX(ssh_ttymodes),
2026 ttymodes_handler, P(td), P(NULL));
2027 td->valbox->generic.column = 2;
2028 ctrl_tabdelay(s, td->addbutton);
2029
2030 }
2031
2032 if (!midsession) {
2033 /*
05581745 2034 * The Connection/SSH/X11 panel.
2035 */
2036 ctrl_settitle(b, "Connection/SSH/X11",
2037 "Options controlling SSH X11 forwarding");
2038
2039 s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
fda2feb1 2040 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
2041 HELPCTX(ssh_tunnels_x11),
2042 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
2043 ctrl_editbox(s, "X display location", 'x', 50,
2044 HELPCTX(ssh_tunnels_x11),
2045 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
2046 I(sizeof(((Config *)0)->x11_display)));
2047 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
2048 HELPCTX(ssh_tunnels_x11auth),
2049 dlg_stdradiobutton_handler,
2050 I(offsetof(Config, x11_auth)),
2051 "MIT-Magic-Cookie-1", I(X11_MIT),
2052 "XDM-Authorization-1", I(X11_XDM), NULL);
2053 }
fe8abbf4 2054
05581745 2055 /*
2056 * The Tunnels panel _is_ still available in mid-session.
2057 */
2058 ctrl_settitle(b, "Connection/SSH/Tunnels",
2059 "Options controlling SSH port forwarding");
2060
fe8abbf4 2061 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
2062 "Port forwarding");
2063 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
2064 HELPCTX(ssh_tunnels_portfwd_localhost),
2065 dlg_stdcheckbox_handler,
2066 I(offsetof(Config,lport_acceptall)));
2e85c969 2067 ctrl_checkbox(s, "Remote ports do the same (SSH-2 only)", 'p',
fe8abbf4 2068 HELPCTX(ssh_tunnels_portfwd_localhost),
2069 dlg_stdcheckbox_handler,
2070 I(offsetof(Config,rport_acceptall)));
2071
2072 ctrl_columns(s, 3, 55, 20, 25);
2073 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
2074 c->generic.column = COLUMN_FIELD(0,2);
2075 /* You want to select from the list, _then_ hit Remove. So tab order
2076 * should be that way round. */
2077 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
2078 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
2079 HELPCTX(ssh_tunnels_portfwd),
2080 portfwd_handler, P(pfd));
2081 pfd->rembutton->generic.column = 2;
2082 pfd->rembutton->generic.tabdelay = 1;
2083 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
2084 HELPCTX(ssh_tunnels_portfwd),
2085 portfwd_handler, P(pfd));
2086 pfd->listbox->listbox.height = 3;
37dbf11c 2087 pfd->listbox->listbox.ncols = 2;
3d88e64d 2088 pfd->listbox->listbox.percentages = snewn(2, int);
37dbf11c 2089 pfd->listbox->listbox.percentages[0] = 20;
2090 pfd->listbox->listbox.percentages[1] = 80;
fe8abbf4 2091 ctrl_tabdelay(s, pfd->rembutton);
2092 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
2093 /* You want to enter source, destination and type, _then_ hit Add.
2094 * Again, we adjust the tab order to reflect this. */
2095 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
2096 HELPCTX(ssh_tunnels_portfwd),
2097 portfwd_handler, P(pfd));
2098 pfd->addbutton->generic.column = 2;
2099 pfd->addbutton->generic.tabdelay = 1;
2100 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
2101 HELPCTX(ssh_tunnels_portfwd),
2102 portfwd_handler, P(pfd), P(NULL));
2103 pfd->sourcebox->generic.column = 0;
2104 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
2105 HELPCTX(ssh_tunnels_portfwd),
2106 portfwd_handler, P(pfd), P(NULL));
820ebe3b 2107 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
fe8abbf4 2108 HELPCTX(ssh_tunnels_portfwd),
2109 portfwd_handler, P(pfd),
2110 "Local", 'l', P(NULL),
820ebe3b 2111 "Remote", 'm', P(NULL),
2112 "Dynamic", 'y', P(NULL),
2113 NULL);
05581745 2114#ifndef NO_IPV6
22db244f 2115 pfd->addressfamily =
2116 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
05581745 2117 HELPCTX(ssh_tunnels_portfwd_ipversion),
2118 portfwd_handler, P(pfd),
b908db15 2119 "Auto", 'u', I(ADDRTYPE_UNSPEC),
2120 "IPv4", '4', I(ADDRTYPE_IPV4),
2121 "IPv6", '6', I(ADDRTYPE_IPV6),
05581745 2122 NULL);
22db244f 2123#endif
fe8abbf4 2124 ctrl_tabdelay(s, pfd->addbutton);
2125 ctrl_columns(s, 1, 100);
2126
fda2feb1 2127 if (!midsession) {
2128 /*
2129 * The Connection/SSH/Bugs panel.
2130 */
2131 ctrl_settitle(b, "Connection/SSH/Bugs",
2132 "Workarounds for SSH server bugs");
2133
2134 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
2135 "Detection of known bugs in SSH servers");
2e85c969 2136 ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
fda2feb1 2137 HELPCTX(ssh_bugs_ignore1),
2138 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
2e85c969 2139 ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
fda2feb1 2140 HELPCTX(ssh_bugs_plainpw1),
2141 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
2e85c969 2142 ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
fda2feb1 2143 HELPCTX(ssh_bugs_rsa1),
2144 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
2e85c969 2145 ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
fda2feb1 2146 HELPCTX(ssh_bugs_hmac2),
2147 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
2e85c969 2148 ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
fda2feb1 2149 HELPCTX(ssh_bugs_derivekey2),
2150 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
2e85c969 2151 ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
fda2feb1 2152 HELPCTX(ssh_bugs_rsapad2),
2153 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
19f47a7d 2154 ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
fda2feb1 2155 HELPCTX(ssh_bugs_pksessid2),
2156 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
19f47a7d 2157 ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
f382c87d 2158 HELPCTX(ssh_bugs_rekey2),
2159 sshbug_handler, I(offsetof(Config,sshbug_rekey2)));
fda2feb1 2160 }
fe8abbf4 2161 }
2162}