As usual, gcc is better at warnings than MSVC, so here are some
[sgt/putty] / config.c
CommitLineData
fe8abbf4 1/*
2 * config.c - the platform-independent parts of the PuTTY
3 * configuration box.
4 */
5
6#include <assert.h>
7#include <stdlib.h>
8
9#include "putty.h"
10#include "dialog.h"
11#include "storage.h"
12
13#define PRINTER_DISABLED_STRING "None (printing disabled)"
14
15static void protocolbuttons_handler(union control *ctrl, void *dlg,
16 void *data, int event)
17{
18 int button, defport;
19 Config *cfg = (Config *)data;
20 /*
21 * This function works just like the standard radio-button
22 * handler, except that it also has to change the setting of
23 * the port box. We expect the context parameter to point at
24 * the `union control' structure for the port box.
25 */
26 if (event == EVENT_REFRESH) {
27 for (button = 0; button < ctrl->radio.nbuttons; button++)
28 if (cfg->protocol == ctrl->radio.buttondata[button].i)
29 break;
30 /* We expected that `break' to happen, in all circumstances. */
31 assert(button < ctrl->radio.nbuttons);
32 dlg_radiobutton_set(ctrl, dlg, button);
33 } else if (event == EVENT_VALCHANGE) {
34 int oldproto = cfg->protocol;
35 button = dlg_radiobutton_get(ctrl, dlg);
36 assert(button >= 0 && button < ctrl->radio.nbuttons);
37 cfg->protocol = ctrl->radio.buttondata[button].i;
38 if (oldproto != cfg->protocol) {
39 defport = -1;
40 switch (cfg->protocol) {
41 case PROT_SSH: defport = 22; break;
42 case PROT_TELNET: defport = 23; break;
43 case PROT_RLOGIN: defport = 513; break;
44 }
45 if (defport > 0 && cfg->port != defport) {
46 cfg->port = defport;
47 dlg_refresh((union control *)ctrl->radio.context.p, dlg);
48 }
49 }
50 }
51}
52
53static void numeric_keypad_handler(union control *ctrl, void *dlg,
54 void *data, int event)
55{
56 int button;
57 Config *cfg = (Config *)data;
58 /*
59 * This function works much like the standard radio button
60 * handler, but it has to handle two fields in Config.
61 */
62 if (event == EVENT_REFRESH) {
63 if (cfg->nethack_keypad)
64 button = 2;
65 else if (cfg->app_keypad)
66 button = 1;
67 else
68 button = 0;
69 assert(button < ctrl->radio.nbuttons);
70 dlg_radiobutton_set(ctrl, dlg, button);
71 } else if (event == EVENT_VALCHANGE) {
72 button = dlg_radiobutton_get(ctrl, dlg);
73 assert(button >= 0 && button < ctrl->radio.nbuttons);
74 if (button == 2) {
75 cfg->app_keypad = FALSE;
76 cfg->nethack_keypad = TRUE;
77 } else {
78 cfg->app_keypad = (button != 0);
79 cfg->nethack_keypad = FALSE;
80 }
81 }
82}
83
84static void cipherlist_handler(union control *ctrl, void *dlg,
85 void *data, int event)
86{
87 Config *cfg = (Config *)data;
88 if (event == EVENT_REFRESH) {
89 int i;
90
91 static const struct { char *s; int c; } ciphers[] = {
92 { "3DES", CIPHER_3DES },
93 { "Blowfish", CIPHER_BLOWFISH },
94 { "DES", CIPHER_DES },
95 { "AES (SSH 2 only)", CIPHER_AES },
96 { "-- warn below here --", CIPHER_WARN }
97 };
98
99 /* Set up the "selected ciphers" box. */
100 /* (cipherlist assumed to contain all ciphers) */
101 dlg_update_start(ctrl, dlg);
102 dlg_listbox_clear(ctrl, dlg);
103 for (i = 0; i < CIPHER_MAX; i++) {
104 int c = cfg->ssh_cipherlist[i];
105 int j;
106 char *cstr = NULL;
107 for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
108 if (ciphers[j].c == c) {
109 cstr = ciphers[j].s;
110 break;
111 }
112 }
113 dlg_listbox_addwithindex(ctrl, dlg, cstr, c);
114 }
115 dlg_update_done(ctrl, dlg);
116
117 } else if (event == EVENT_VALCHANGE) {
118 int i;
119
120 /* Update array to match the list box. */
121 for (i=0; i < CIPHER_MAX; i++)
122 cfg->ssh_cipherlist[i] = dlg_listbox_getid(ctrl, dlg, i);
123
124 }
125}
126
127static void printerbox_handler(union control *ctrl, void *dlg,
128 void *data, int event)
129{
130 Config *cfg = (Config *)data;
131 if (event == EVENT_REFRESH) {
132 int nprinters, i;
133 printer_enum *pe;
134
135 dlg_update_start(ctrl, dlg);
136 dlg_listbox_clear(ctrl, dlg);
137 dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING);
138 pe = printer_start_enum(&nprinters);
139 for (i = 0; i < nprinters; i++)
140 dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i));
141 printer_finish_enum(pe);
142 dlg_editbox_set(ctrl, dlg,
143 (*cfg->printer ? cfg->printer :
144 PRINTER_DISABLED_STRING));
145 dlg_update_done(ctrl, dlg);
146 } else if (event == EVENT_VALCHANGE) {
147 dlg_editbox_get(ctrl, dlg, cfg->printer, sizeof(cfg->printer));
148 if (!strcmp(cfg->printer, PRINTER_DISABLED_STRING))
149 *cfg->printer = '\0';
150 }
151}
152
153static void codepage_handler(union control *ctrl, void *dlg,
154 void *data, int event)
155{
156 Config *cfg = (Config *)data;
157 if (event == EVENT_REFRESH) {
158 int i;
159 char *cp;
160 dlg_update_start(ctrl, dlg);
161 strcpy(cfg->line_codepage,
162 cp_name(decode_codepage(cfg->line_codepage)));
163 dlg_listbox_clear(ctrl, dlg);
164 for (i = 0; (cp = cp_enumerate(i)) != NULL; i++)
165 dlg_listbox_add(ctrl, dlg, cp);
166 dlg_editbox_set(ctrl, dlg, cfg->line_codepage);
167 dlg_update_done(ctrl, dlg);
168 } else if (event == EVENT_VALCHANGE) {
169 dlg_editbox_get(ctrl, dlg, cfg->line_codepage,
170 sizeof(cfg->line_codepage));
171 strcpy(cfg->line_codepage,
172 cp_name(decode_codepage(cfg->line_codepage)));
173 }
174}
175
176static void sshbug_handler(union control *ctrl, void *dlg,
177 void *data, int event)
178{
179 if (event == EVENT_REFRESH) {
180 dlg_update_start(ctrl, dlg);
181 dlg_listbox_clear(ctrl, dlg);
182 dlg_listbox_addwithindex(ctrl, dlg, "Auto", AUTO);
183 dlg_listbox_addwithindex(ctrl, dlg, "Off", FORCE_OFF);
184 dlg_listbox_addwithindex(ctrl, dlg, "On", FORCE_ON);
185 switch (*(int *)ATOFFSET(data, ctrl->listbox.context.i)) {
186 case AUTO: dlg_listbox_select(ctrl, dlg, 0); break;
187 case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break;
188 case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break;
189 }
190 dlg_update_done(ctrl, dlg);
191 } else if (event == EVENT_SELCHANGE) {
192 int i = dlg_listbox_index(ctrl, dlg);
193 if (i < 0)
194 i = AUTO;
195 else
196 i = dlg_listbox_getid(ctrl, dlg, i);
197 *(int *)ATOFFSET(data, ctrl->listbox.context.i) = i;
198 }
199}
200
201struct sessionsaver_data {
202 union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
203 union control *okbutton, *cancelbutton;
204 char savedsession[2048];
205 struct sesslist *sesslist;
206};
207
208/*
209 * Helper function to load the session selected in the list box, if
210 * any, as this is done in more than one place below. Returns 0 for
211 * failure.
212 */
213static int load_selected_session(struct sessionsaver_data *ssd,
214 void *dlg, Config *cfg)
215{
216 int i = dlg_listbox_index(ssd->listbox, dlg);
217 int isdef;
218 if (i < 0) {
219 dlg_beep(dlg);
220 return 0;
221 }
222 isdef = !strcmp(ssd->sesslist->sessions[i], "Default Settings");
223 load_settings(ssd->sesslist->sessions[i], !isdef, cfg);
224 if (!isdef) {
225 strncpy(ssd->savedsession, ssd->sesslist->sessions[i],
226 sizeof(ssd->savedsession));
227 ssd->savedsession[sizeof(ssd->savedsession)-1] = '\0';
228 } else {
229 ssd->savedsession[0] = '\0';
230 }
231 dlg_refresh(NULL, dlg);
232 /* Restore the selection, which might have been clobbered by
233 * changing the value of the edit box. */
234 dlg_listbox_select(ssd->listbox, dlg, i);
235 return 1;
236}
237
238static void sessionsaver_handler(union control *ctrl, void *dlg,
239 void *data, int event)
240{
241 Config *cfg = (Config *)data;
242 struct sessionsaver_data *ssd =
243 (struct sessionsaver_data *)ctrl->generic.context.p;
244
245 if (event == EVENT_REFRESH) {
246 if (ctrl == ssd->editbox) {
247 dlg_editbox_set(ctrl, dlg, ssd->savedsession);
248 } else if (ctrl == ssd->listbox) {
249 int i;
250 dlg_update_start(ctrl, dlg);
251 dlg_listbox_clear(ctrl, dlg);
252 for (i = 0; i < ssd->sesslist->nsessions; i++)
253 dlg_listbox_add(ctrl, dlg, ssd->sesslist->sessions[i]);
254 dlg_update_done(ctrl, dlg);
255 }
256 } else if (event == EVENT_VALCHANGE) {
257 if (ctrl == ssd->editbox) {
258 dlg_editbox_get(ctrl, dlg, ssd->savedsession,
259 sizeof(ssd->savedsession));
260 }
261 } else if (event == EVENT_ACTION) {
262 if (ctrl == ssd->listbox || ctrl == ssd->loadbutton) {
263 /*
264 * The user has double-clicked a session, or hit Load.
265 * We must load the selected session, and then
266 * terminate the configuration dialog _if_ there was a
267 * double-click on the list box _and_ that session
268 * contains a hostname.
269 */
270 if (load_selected_session(ssd, dlg, cfg) &&
271 (ctrl == ssd->listbox && cfg->host[0])) {
272 dlg_end(dlg, 1); /* it's all over, and succeeded */
273 }
274 } else if (ctrl == ssd->savebutton) {
275 int isdef = !strcmp(ssd->savedsession, "Default Settings");
276 if (!ssd->savedsession[0]) {
277 int i = dlg_listbox_index(ctrl, dlg);
278 if (i < 0) {
279 dlg_beep(dlg);
280 return;
281 }
282 isdef = !strcmp(ssd->sesslist->sessions[i], "Default Settings");
283 if (!isdef) {
284 strncpy(ssd->savedsession, ssd->sesslist->sessions[i],
285 sizeof(ssd->savedsession));
286 ssd->savedsession[sizeof(ssd->savedsession)-1] = '\0';
287 } else {
288 ssd->savedsession[0] = '\0';
289 }
290 }
291 save_settings(ssd->savedsession, isdef, cfg);
292 get_sesslist(ssd->sesslist, FALSE);
293 get_sesslist(ssd->sesslist, TRUE);
294 dlg_refresh(ssd->editbox, dlg);
295 dlg_refresh(ssd->listbox, dlg);
296 } else if (ctrl == ssd->delbutton) {
297 int i = dlg_listbox_index(ctrl, dlg);
298 if (i <= 0) {
299 dlg_beep(dlg);
300 } else {
301 del_settings(ssd->sesslist->sessions[i]);
302 get_sesslist(ssd->sesslist, FALSE);
303 get_sesslist(ssd->sesslist, TRUE);
304 dlg_refresh(ssd->listbox, dlg);
305 }
306 } else if (ctrl == ssd->okbutton) {
307 /*
308 * Annoying special case. If the `Open' button is
309 * pressed while no host name is currently set, _and_
310 * the session list previously had the focus, _and_
311 * there was a session selected in that which had a
312 * valid host name in it, then load it and go.
313 */
314 if (dlg_last_focused(dlg) == ssd->listbox && !*cfg->host) {
315 Config cfg2;
316 if (!load_selected_session(ssd, dlg, &cfg2)) {
317 dlg_beep(dlg);
318 return;
319 }
320 /* If at this point we have a valid session, go! */
321 if (*cfg2.host) {
322 *cfg = cfg2; /* structure copy */
323 dlg_end(dlg, 1);
324 } else
325 dlg_beep(dlg);
326 }
327
328 /*
329 * Otherwise, do the normal thing: if we have a valid
330 * session, get going.
331 */
332 if (*cfg->host) {
333 dlg_end(dlg, 1);
334 } else
335 dlg_beep(dlg);
336 } else if (ctrl == ssd->cancelbutton) {
337 dlg_end(dlg, 0);
338 }
339 }
340}
341
342struct charclass_data {
343 union control *listbox, *editbox, *button;
344};
345
346static void charclass_handler(union control *ctrl, void *dlg,
347 void *data, int event)
348{
349 Config *cfg = (Config *)data;
350 struct charclass_data *ccd =
351 (struct charclass_data *)ctrl->generic.context.p;
352
353 if (event == EVENT_REFRESH) {
354 if (ctrl == ccd->listbox) {
355 int i;
356 dlg_update_start(ctrl, dlg);
357 dlg_listbox_clear(ctrl, dlg);
358 for (i = 0; i < 128; i++) {
359 char str[100];
360 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
361 (i >= 0x21 && i != 0x7F) ? i : ' ', cfg->wordness[i]);
362 dlg_listbox_add(ctrl, dlg, str);
363 }
364 dlg_update_done(ctrl, dlg);
365 }
366 } else if (event == EVENT_ACTION) {
367 if (ctrl == ccd->button) {
368 char str[100];
369 int i, n;
370 dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str));
371 n = atoi(str);
372 for (i = 0; i < 128; i++) {
373 if (dlg_listbox_issel(ccd->listbox, dlg, i))
374 cfg->wordness[i] = n;
375 }
376 dlg_refresh(ccd->listbox, dlg);
377 }
378 }
379}
380
381struct colour_data {
382 union control *listbox, *rgbtext, *button;
383};
384
385static const char *const colours[] = {
386 "Default Foreground", "Default Bold Foreground",
387 "Default Background", "Default Bold Background",
388 "Cursor Text", "Cursor Colour",
389 "ANSI Black", "ANSI Black Bold",
390 "ANSI Red", "ANSI Red Bold",
391 "ANSI Green", "ANSI Green Bold",
392 "ANSI Yellow", "ANSI Yellow Bold",
393 "ANSI Blue", "ANSI Blue Bold",
394 "ANSI Magenta", "ANSI Magenta Bold",
395 "ANSI Cyan", "ANSI Cyan Bold",
396 "ANSI White", "ANSI White Bold"
397};
398
399static void colour_handler(union control *ctrl, void *dlg,
400 void *data, int event)
401{
402 Config *cfg = (Config *)data;
403 struct colour_data *cd =
404 (struct colour_data *)ctrl->generic.context.p;
405 int update = FALSE, r, g, b;
406
407 if (event == EVENT_REFRESH) {
408 if (ctrl == cd->listbox) {
409 int i;
410 dlg_update_start(ctrl, dlg);
411 dlg_listbox_clear(ctrl, dlg);
412 for (i = 0; i < lenof(colours); i++)
413 dlg_listbox_add(ctrl, dlg, colours[i]);
414 dlg_update_done(ctrl, dlg);
415 dlg_text_set(cd->rgbtext, dlg, "");
416 }
417 } else if (event == EVENT_SELCHANGE) {
418 if (ctrl == cd->listbox) {
419 /* The user has selected a colour. Update the RGB text. */
420 int i = dlg_listbox_index(ctrl, dlg);
421 if (i < 0) {
422 dlg_beep(dlg);
423 return;
424 }
425 r = cfg->colours[i][0];
426 g = cfg->colours[i][1];
427 b = cfg->colours[i][2];
428 update = TRUE;
429 }
430 } else if (event == EVENT_ACTION) {
431 if (ctrl == cd->button) {
432 int i = dlg_listbox_index(cd->listbox, dlg);
433 if (i < 0) {
434 dlg_beep(dlg);
435 return;
436 }
437 /*
438 * Start a colour selector, which will send us an
439 * EVENT_CALLBACK when it's finished and allow us to
440 * pick up the results.
441 */
442 dlg_coloursel_start(ctrl, dlg,
443 cfg->colours[i][0],
444 cfg->colours[i][1],
445 cfg->colours[i][2]);
446 }
447 } else if (event == EVENT_CALLBACK) {
448 if (ctrl == cd->button) {
449 int i = dlg_listbox_index(cd->listbox, dlg);
450 /*
451 * Collect the results of the colour selector. Will
452 * return nonzero on success, or zero if the colour
453 * selector did nothing (user hit Cancel, for example).
454 */
455 if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
456 cfg->colours[i][0] = r;
457 cfg->colours[i][1] = g;
458 cfg->colours[i][2] = b;
459 update = TRUE;
460 }
461 }
462 }
463
464 if (update) {
465 char buf[40];
466 sprintf(buf, "%02x/%02x/%02x", r, g, b);
467 dlg_text_set(cd->rgbtext, dlg, buf);
468 }
469}
470
471struct environ_data {
472 union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
473};
474
475static void environ_handler(union control *ctrl, void *dlg,
476 void *data, int event)
477{
478 Config *cfg = (Config *)data;
479 struct environ_data *ed =
480 (struct environ_data *)ctrl->generic.context.p;
481
482 if (event == EVENT_REFRESH) {
483 if (ctrl == ed->listbox) {
484 char *p = cfg->environmt;
485 dlg_update_start(ctrl, dlg);
486 dlg_listbox_clear(ctrl, dlg);
487 while (*p) {
488 dlg_listbox_add(ctrl, dlg, p);
489 p += strlen(p) + 1;
490 }
491 dlg_update_done(ctrl, dlg);
492 }
493 } else if (event == EVENT_ACTION) {
494 if (ctrl == ed->addbutton) {
495 char str[sizeof(cfg->environmt)];
496 char *p;
497 dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1);
498 if (!*str) {
499 dlg_beep(dlg);
500 return;
501 }
502 p = str + strlen(str);
503 *p++ = '\t';
504 dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str));
505 if (!*p) {
506 dlg_beep(dlg);
507 return;
508 }
509 p = cfg->environmt;
510 while (*p) {
511 while (*p)
512 p++;
513 p++;
514 }
515 if ((p - cfg->environmt) + strlen(str) + 2 <
516 sizeof(cfg->environmt)) {
517 strcpy(p, str);
518 p[strlen(str) + 1] = '\0';
519 dlg_listbox_add(ed->listbox, dlg, str);
520 dlg_editbox_set(ed->varbox, dlg, "");
521 dlg_editbox_set(ed->valbox, dlg, "");
522 } else {
523 dlg_error_msg(dlg, "Environment too big");
524 }
525 } else if (ctrl == ed->rembutton) {
526 int i = dlg_listbox_index(ed->listbox, dlg);
527 if (i < 0) {
528 dlg_beep(dlg);
529 } else {
530 char *p, *q;
531
532 dlg_listbox_del(ed->listbox, dlg, i);
533 p = cfg->environmt;
534 while (i > 0) {
535 if (!*p)
536 goto disaster;
537 while (*p)
538 p++;
539 p++;
540 i--;
541 }
542 q = p;
543 if (!*p)
544 goto disaster;
545 while (*p)
546 p++;
547 p++;
548 while (*p) {
549 while (*p)
550 *q++ = *p++;
551 *q++ = *p++;
552 }
553 *q = '\0';
554 disaster:;
555 }
556 }
557 }
558}
559
560struct portfwd_data {
561 union control *addbutton, *rembutton, *listbox;
562 union control *sourcebox, *destbox, *direction;
563};
564
565static void portfwd_handler(union control *ctrl, void *dlg,
566 void *data, int event)
567{
568 Config *cfg = (Config *)data;
569 struct portfwd_data *pfd =
570 (struct portfwd_data *)ctrl->generic.context.p;
571
572 if (event == EVENT_REFRESH) {
573 if (ctrl == pfd->listbox) {
574 char *p = cfg->portfwd;
575 dlg_update_start(ctrl, dlg);
576 dlg_listbox_clear(ctrl, dlg);
577 while (*p) {
578 dlg_listbox_add(ctrl, dlg, p);
579 p += strlen(p) + 1;
580 }
581 dlg_update_done(ctrl, dlg);
582 }
583 } else if (event == EVENT_ACTION) {
584 if (ctrl == pfd->addbutton) {
585 char str[sizeof(cfg->portfwd)];
586 char *p;
587 if (dlg_radiobutton_get(pfd->direction, dlg) == 0)
588 str[0] = 'L';
589 else
590 str[0] = 'R';
591 dlg_editbox_get(pfd->sourcebox, dlg, str+1, sizeof(str) - 2);
592 if (!str[1]) {
593 dlg_error_msg(dlg, "You need to specify a source port number");
594 return;
595 }
596 p = str + strlen(str);
597 *p++ = '\t';
598 dlg_editbox_get(pfd->destbox, dlg, p, sizeof(str)-1 - (p - str));
599 if (!*p || !strchr(p, ':')) {
600 dlg_error_msg(dlg,
601 "You need to specify a destination address\n"
602 "in the form \"host.name:port\"");
603 return;
604 }
605 p = cfg->portfwd;
606 while (*p) {
607 while (*p)
608 p++;
609 p++;
610 }
611 if ((p - cfg->portfwd) + strlen(str) + 2 <
612 sizeof(cfg->portfwd)) {
613 strcpy(p, str);
614 p[strlen(str) + 1] = '\0';
615 dlg_listbox_add(pfd->listbox, dlg, str);
616 dlg_editbox_set(pfd->sourcebox, dlg, "");
617 dlg_editbox_set(pfd->destbox, dlg, "");
618 } else {
619 dlg_error_msg(dlg, "Too many forwardings");
620 }
621 } else if (ctrl == pfd->rembutton) {
622 int i = dlg_listbox_index(pfd->listbox, dlg);
623 if (i < 0)
624 dlg_beep(dlg);
625 else {
626 char *p, *q;
627
628 dlg_listbox_del(pfd->listbox, dlg, i);
629 p = cfg->portfwd;
630 while (i > 0) {
631 if (!*p)
632 goto disaster2;
633 while (*p)
634 p++;
635 p++;
636 i--;
637 }
638 q = p;
639 if (!*p)
640 goto disaster2;
641 while (*p)
642 p++;
643 p++;
644 while (*p) {
645 while (*p)
646 *q++ = *p++;
647 *q++ = *p++;
648 }
649 *q = '\0';
650 disaster2:;
651 }
652 }
653 }
654}
655
656void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
657 int midsession, int protocol)
658{
659 struct controlset *s;
660 struct sessionsaver_data *ssd;
661 struct charclass_data *ccd;
662 struct colour_data *cd;
663 struct environ_data *ed;
664 struct portfwd_data *pfd;
665 union control *c;
666
667 ssd = (struct sessionsaver_data *)
668 ctrl_alloc(b, sizeof(struct sessionsaver_data));
669 ssd->sesslist = (midsession ? NULL : sesslist);
670
671 /*
672 * The standard panel that appears at the bottom of all panels:
673 * Open, Cancel, Apply etc.
674 */
675 s = ctrl_getset(b, "", "", "");
676 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
677 ssd->okbutton = ctrl_pushbutton(s,
678 (midsession ? "Apply" : "Open"),
679 (char)(midsession ? 'a' : 'o'),
680 HELPCTX(no_help),
681 sessionsaver_handler, P(ssd));
682 ssd->okbutton->button.isdefault = TRUE;
683 ssd->okbutton->generic.column = 3;
684 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
685 sessionsaver_handler, P(ssd));
686 ssd->cancelbutton->generic.column = 4;
687 /* We carefully don't close the 5-column part, so that platform-
688 * specific add-ons can put extra buttons alongside Open and Cancel. */
689
690 /*
691 * The Session panel.
692 */
693 ctrl_settitle(b, "Session", "Basic options for your PuTTY session");
694
695 if (!midsession) {
696 s = ctrl_getset(b, "Session", "hostport",
697 "Specify your connection by host name or IP address");
698 ctrl_columns(s, 2, 75, 25);
699 c = ctrl_editbox(s, "Host Name (or IP address)", 'n', 100,
700 HELPCTX(session_hostname),
701 dlg_stdeditbox_handler, I(offsetof(Config,host)),
702 I(sizeof(((Config *)0)->host)));
703 c->generic.column = 0;
704 c = ctrl_editbox(s, "Port", 'p', 100, HELPCTX(session_hostname),
705 dlg_stdeditbox_handler,
706 I(offsetof(Config,port)), I(-1));
707 c->generic.column = 1;
708 ctrl_columns(s, 1, 100);
709 if (backends[3].backend == NULL) {
710 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 3,
711 HELPCTX(session_hostname),
712 protocolbuttons_handler, P(c),
713 "Raw", 'r', I(PROT_RAW),
714 "Telnet", 't', I(PROT_TELNET),
715 "Rlogin", 'i', I(PROT_RLOGIN),
716 NULL);
717 } else {
718 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 4,
719 HELPCTX(session_hostname),
720 protocolbuttons_handler, P(c),
721 "Raw", 'r', I(PROT_RAW),
722 "Telnet", 't', I(PROT_TELNET),
723 "Rlogin", 'i', I(PROT_RLOGIN),
724 "SSH", 's', I(PROT_SSH),
725 NULL);
726 }
727
728 s = ctrl_getset(b, "Session", "savedsessions",
729 "Load, save or delete a stored session");
730 ctrl_columns(s, 2, 75, 25);
731 ssd->savedsession[0] = '\0';
732 ssd->sesslist = sesslist;
733 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
734 HELPCTX(session_saved),
735 sessionsaver_handler, P(ssd), P(NULL));
736 ssd->editbox->generic.column = 0;
737 /* Reset columns so that the buttons are alongside the list, rather
738 * than alongside that edit box. */
739 ctrl_columns(s, 1, 100);
740 ctrl_columns(s, 2, 75, 25);
741 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
742 HELPCTX(session_saved),
743 sessionsaver_handler, P(ssd));
744 ssd->loadbutton->generic.column = 1;
745 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
746 HELPCTX(session_saved),
747 sessionsaver_handler, P(ssd));
748 ssd->savebutton->generic.column = 1;
749 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
750 HELPCTX(session_saved),
751 sessionsaver_handler, P(ssd));
752 ssd->delbutton->generic.column = 1;
753 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
754 HELPCTX(session_saved),
755 sessionsaver_handler, P(ssd));
756 ssd->listbox->generic.column = 0;
757 ssd->listbox->listbox.height = 7;
758 ctrl_columns(s, 1, 100);
759 }
760
761 s = ctrl_getset(b, "Session", "otheropts", NULL);
762 c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
763 HELPCTX(session_coe),
764 dlg_stdradiobutton_handler,
765 I(offsetof(Config, close_on_exit)),
766 "Always", I(FORCE_ON),
767 "Never", I(FORCE_OFF),
768 "Only on clean exit", I(AUTO), NULL);
769
770 /*
771 * The Session/Logging panel.
772 */
773 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
774
775 s = ctrl_getset(b, "Session/Logging", "main", NULL);
776 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 1,
777 HELPCTX(logging_main),
778 dlg_stdradiobutton_handler, I(offsetof(Config, logtype)),
779 "Logging turned off completely", 't', I(LGTYP_NONE),
780 "Log printable output only", 'p', I(LGTYP_ASCII),
781 "Log all session output", 'l', I(LGTYP_DEBUG),
782 "Log SSH packet data", 's', I(LGTYP_PACKETS),
783 NULL);
784 ctrl_filesel(s, "Log file name:", 'f',
785 NULL, TRUE, "Select session log file name",
786 HELPCTX(logging_filename),
787 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
788 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
789 " &T for time, and &H for host name)",
790 HELPCTX(logging_filename));
791 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
792 HELPCTX(logging_exists),
793 dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
794 "Always overwrite it", I(LGXF_OVR),
795 "Always append to the end of it", I(LGXF_APN),
796 "Ask the user every time", I(LGXF_ASK), NULL);
797
798 /*
799 * The Terminal panel.
800 */
801 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
802
803 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
804 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
805 HELPCTX(terminal_autowrap),
806 dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
807 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
808 HELPCTX(terminal_decom),
809 dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
810 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
811 HELPCTX(terminal_lfhascr),
812 dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
813 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
814 HELPCTX(terminal_bce),
815 dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
816 ctrl_checkbox(s, "Enable blinking text", 'n',
817 HELPCTX(terminal_blink),
818 dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
819 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
820 HELPCTX(terminal_answerback),
821 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
822 I(sizeof(((Config *)0)->answerback)));
823
824 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
825 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
826 HELPCTX(terminal_localecho),
827 dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
828 "Auto", I(AUTO),
829 "Force on", I(FORCE_ON),
830 "Force off", I(FORCE_OFF), NULL);
831 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
832 HELPCTX(terminal_localedit),
833 dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
834 "Auto", I(AUTO),
835 "Force on", I(FORCE_ON),
836 "Force off", I(FORCE_OFF), NULL);
837
838 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
839 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
840 HELPCTX(terminal_printing),
841 printerbox_handler, P(NULL), P(NULL));
842
843 /*
844 * The Terminal/Keyboard panel.
845 */
846 ctrl_settitle(b, "Terminal/Keyboard",
847 "Options controlling the effects of keys");
848
849 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
850 "Change the sequences sent by:");
851 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
852 HELPCTX(keyboard_backspace),
853 dlg_stdradiobutton_handler,
854 I(offsetof(Config, bksp_is_delete)),
855 "Control-H", I(0), "Control-? (127)", I(1), NULL);
856 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
857 HELPCTX(keyboard_homeend),
858 dlg_stdradiobutton_handler,
859 I(offsetof(Config, rxvt_homeend)),
860 "Standard", I(0), "rxvt", I(1), NULL);
861 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
862 HELPCTX(keyboard_funkeys),
863 dlg_stdradiobutton_handler,
864 I(offsetof(Config, funky_type)),
865 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
866 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
867
868 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
869 "Application keypad settings:");
870 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
871 HELPCTX(keyboard_appcursor),
872 dlg_stdradiobutton_handler,
873 I(offsetof(Config, app_cursor)),
874 "Normal", I(0), "Application", I(1), NULL);
875 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
876 HELPCTX(keyboard_appkeypad),
877 numeric_keypad_handler, P(NULL),
878 "Normal", I(0), "Application", I(1), "NetHack", I(2),
879 NULL);
880
881 /*
882 * The Terminal/Bell panel.
883 */
884 ctrl_settitle(b, "Terminal/Bell",
885 "Options controlling the terminal bell");
886
887 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
888 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
889 HELPCTX(bell_style),
890 dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
891 "None (bell disabled)", I(BELL_DISABLED),
892 "Make default system alert sound", I(BELL_DEFAULT),
893 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
894
895 s = ctrl_getset(b, "Terminal/Bell", "overload",
896 "Control the bell overload behaviour");
897 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
898 HELPCTX(bell_overload),
899 dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
900 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
901 HELPCTX(bell_overload),
902 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
903 ctrl_editbox(s, "... in this many seconds", 't', 20,
904 HELPCTX(bell_overload),
905 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
906 I(-1000));
907 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
908 HELPCTX(bell_overload));
909 ctrl_editbox(s, "Seconds of silence required", 's', 20,
910 HELPCTX(bell_overload),
911 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
912 I(-1000));
913
914 /*
915 * The Terminal/Features panel.
916 */
917 ctrl_settitle(b, "Terminal/Features",
918 "Enabling and disabling advanced terminal features");
919
920 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
921 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
922 HELPCTX(features_application),
923 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
924 ctrl_checkbox(s, "Disable application keypad mode", 'k',
925 HELPCTX(features_application),
926 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
927 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
928 HELPCTX(features_mouse),
929 dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
930 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
931 HELPCTX(features_resize),
932 dlg_stdcheckbox_handler,
933 I(offsetof(Config,no_remote_resize)));
934 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
935 HELPCTX(features_altscreen),
936 dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
937 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
938 HELPCTX(features_retitle),
939 dlg_stdcheckbox_handler,
940 I(offsetof(Config,no_remote_wintitle)));
941 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
942 HELPCTX(features_dbackspace),
943 dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
944 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
945 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
946 I(offsetof(Config,no_remote_charset)));
947
948 /*
949 * The Window panel.
950 */
951 ctrl_settitle(b, "Window", "Options controlling PuTTY's window");
952
953 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
954 ctrl_columns(s, 2, 50, 50);
955 c = ctrl_editbox(s, "Rows", 'r', 100,
956 HELPCTX(window_size),
957 dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
958 c->generic.column = 0;
959 c = ctrl_editbox(s, "Columns", 'm', 100,
960 HELPCTX(window_size),
961 dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
962 c->generic.column = 1;
963 ctrl_columns(s, 1, 100);
964
965 s = ctrl_getset(b, "Window", "scrollback",
966 "Control the scrollback in the window");
967 ctrl_editbox(s, "Lines of scrollback", 's', 50,
968 HELPCTX(window_scrollback),
969 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
970 ctrl_checkbox(s, "Display scrollbar", 'd',
971 HELPCTX(window_scrollback),
972 dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
973 ctrl_checkbox(s, "Display scrollbar in full screen mode", 'i',
974 HELPCTX(window_scrollback),
975 dlg_stdcheckbox_handler,
976 I(offsetof(Config,scrollbar_in_fullscreen)));
977 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
978 HELPCTX(window_scrollback),
979 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
980 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
981 HELPCTX(window_scrollback),
982 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
983
984 /*
985 * The Window/Appearance panel.
986 */
987 ctrl_settitle(b, "Window/Appearance",
988 "Configure the appearance of PuTTY's window");
989
990 s = ctrl_getset(b, "Window/Appearance", "cursor",
991 "Adjust the use of the cursor");
992 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
993 HELPCTX(appearance_cursor),
994 dlg_stdradiobutton_handler,
995 I(offsetof(Config, cursor_type)),
996 "Block", 'l', I(0),
997 "Underline", 'u', I(1),
998 "Vertical line", 'v', I(2), NULL);
999 ctrl_checkbox(s, "Cursor blinks", 'b',
1000 HELPCTX(appearance_cursor),
1001 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1002
1003 s = ctrl_getset(b, "Window/Appearance", "font",
1004 "Font settings");
1005 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1006 HELPCTX(appearance_font),
1007 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1008
1009 s = ctrl_getset(b, "Window/Appearance", "mouse",
1010 "Adjust the use of the mouse pointer");
1011 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1012 HELPCTX(appearance_hidemouse),
1013 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1014
1015 s = ctrl_getset(b, "Window/Appearance", "border",
1016 "Adjust the window border");
1017 ctrl_editbox(s, "Gap between text and window edge:", NO_SHORTCUT, 20,
1018 HELPCTX(appearance_border),
1019 dlg_stdeditbox_handler,
1020 I(offsetof(Config,window_border)), I(-1));
1021
1022 /*
1023 * The Window/Behaviour panel.
1024 */
1025 ctrl_settitle(b, "Window/Behaviour",
1026 "Configure the behaviour of PuTTY's window");
1027
1028 s = ctrl_getset(b, "Window/Behaviour", "title",
1029 "Adjust the behaviour of the window title");
1030 ctrl_editbox(s, "Window title:", 't', 100,
1031 HELPCTX(appearance_title),
1032 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1033 I(sizeof(((Config *)0)->wintitle)));
1034 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1035 HELPCTX(appearance_title),
1036 dlg_stdcheckbox_handler,
1037 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1038
1039 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1040 ctrl_checkbox(s, "Warn before closing window", 'w',
1041 HELPCTX(behaviour_closewarn),
1042 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1043
1044 /*
1045 * The Window/Translation panel.
1046 */
1047 ctrl_settitle(b, "Window/Translation",
1048 "Options controlling character set translation");
1049
1050 s = ctrl_getset(b, "Window/Translation", "trans",
1051 "Character set translation on received data");
1052 ctrl_combobox(s, "Received data assumed to be in which character set:",
1053 'r', 100, HELPCTX(translation_codepage),
1054 codepage_handler, P(NULL), P(NULL));
1055
1056 s = ctrl_getset(b, "Window/Translation", "linedraw",
1057 "Adjust how PuTTY displays line drawing characters");
1058 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1059 HELPCTX(translation_linedraw),
1060 dlg_stdradiobutton_handler,
1061 I(offsetof(Config, vtmode)),
1062 "Font has XWindows encoding", 'x', I(VT_XWINDOWS),
1063 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
1064 "Unicode mode", 'u', I(VT_UNICODE), NULL);
1065
1066 /*
1067 * The Window/Selection panel.
1068 */
1069 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
1070
1071 s = ctrl_getset(b, "Window/Selection", "trans",
1072 "Translation of pasted characters");
1073 ctrl_checkbox(s, "Don't translate line drawing chars into +, - and |",'d',
1074 HELPCTX(selection_linedraw),
1075 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
1076
1077 s = ctrl_getset(b, "Window/Selection", "mouse",
1078 "Control use of mouse");
1079 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1080 HELPCTX(selection_shiftdrag),
1081 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1082 ctrl_radiobuttons(s,
1083 "Default selection mode (Alt+drag does the other one):",
1084 NO_SHORTCUT, 2,
1085 HELPCTX(selection_rect),
1086 dlg_stdradiobutton_handler,
1087 I(offsetof(Config, rect_select)),
1088 "Normal", 'n', I(0),
1089 "Rectangular block", 'r', I(1), NULL);
1090
1091 s = ctrl_getset(b, "Window/Selection", "charclass",
1092 "Control the select-one-word-at-a-time mode");
1093 ccd = (struct charclass_data *)
1094 ctrl_alloc(b, sizeof(struct charclass_data));
1095 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1096 HELPCTX(selection_charclasses),
1097 charclass_handler, P(ccd));
1098 ccd->listbox->listbox.multisel = 1;
1099 ccd->listbox->listbox.ncols = 4;
1100 ccd->listbox->listbox.percentages = smalloc(4*sizeof(int));
1101 ccd->listbox->listbox.percentages[0] = 15;
1102 ccd->listbox->listbox.percentages[1] = 25;
1103 ccd->listbox->listbox.percentages[2] = 20;
1104 ccd->listbox->listbox.percentages[3] = 40;
1105 ctrl_columns(s, 2, 67, 33);
1106 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1107 HELPCTX(selection_charclasses),
1108 charclass_handler, P(ccd), P(NULL));
1109 ccd->editbox->generic.column = 0;
1110 ccd->button = ctrl_pushbutton(s, "Set", 's',
1111 HELPCTX(selection_charclasses),
1112 charclass_handler, P(ccd));
1113 ccd->button->generic.column = 1;
1114 ctrl_columns(s, 1, 100);
1115
1116 /*
1117 * The Window/Colours panel.
1118 */
1119 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1120
1121 s = ctrl_getset(b, "Window/Colours", "general",
1122 "General options for colour usage");
1123 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1124 HELPCTX(colours_bold),
1125 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1126
1127 s = ctrl_getset(b, "Window/Colours", "adjust",
1128 "Adjust the precise colours PuTTY displays");
1129 ctrl_text(s, "Select a colour from the list, and then click the"
1130 " Modify button to change its appearance.",
1131 HELPCTX(colours_config));
1132 ctrl_columns(s, 2, 67, 33);
1133 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1134 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1135 HELPCTX(colours_config), colour_handler, P(cd));
1136 cd->listbox->generic.column = 0;
1137 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1138 c->generic.column = 1;
1139 cd->rgbtext = ctrl_text(s, "00/00/00", HELPCTX(colours_config));
1140 cd->rgbtext->generic.column = 1;
1141 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1142 colour_handler, P(cd));
1143 cd->button->generic.column = 1;
1144 ctrl_columns(s, 1, 100);
1145
1146 /*
1147 * The Connection panel.
1148 */
1149 ctrl_settitle(b, "Connection", "Options controlling the connection");
1150
1151 if (!midsession) {
1152 s = ctrl_getset(b, "Connection", "data", "Data to send to the server");
1153 ctrl_editbox(s, "Terminal-type string", 't', 50,
1154 HELPCTX(connection_termtype),
1155 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1156 I(sizeof(((Config *)0)->termtype)));
1157 ctrl_editbox(s, "Auto-login username", 'u', 50,
1158 HELPCTX(connection_username),
1159 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1160 I(sizeof(((Config *)0)->username)));
1161 }
1162
1163 s = ctrl_getset(b, "Connection", "keepalive",
1164 "Sending of null packets to keep session active");
1165 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1166 HELPCTX(connection_keepalive),
1167 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1168 I(-1));
1169
1170 if (!midsession) {
1171 s = ctrl_getset(b, "Connection", "tcp",
1172 "Low-level TCP connection options");
1173 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)", 'n',
1174 HELPCTX(connection_nodelay),
1175 dlg_stdcheckbox_handler,
1176 I(offsetof(Config,tcp_nodelay)));
1177 }
1178
1179 if (!midsession) {
1180 /*
1181 * The Connection/Proxy panel.
1182 */
1183 ctrl_settitle(b, "Connection/Proxy",
1184 "Options controlling proxy usage");
1185
1186 s = ctrl_getset(b, "Connection/Proxy", "basics", "Proxy basics");
1187 ctrl_radiobuttons(s, "Proxy type:", NO_SHORTCUT, 4,
1188 HELPCTX(proxy_type),
1189 dlg_stdradiobutton_handler,
1190 I(offsetof(Config, proxy_type)),
1191 "None", 'n', I(PROXY_NONE),
1192 "HTTP", 't', I(PROXY_HTTP),
1193 "SOCKS", 's', I(PROXY_SOCKS),
1194 "Telnet", 'l', I(PROXY_TELNET),
1195 NULL);
1196 ctrl_columns(s, 2, 80, 20);
1197 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1198 HELPCTX(proxy_main),
1199 dlg_stdeditbox_handler,
1200 I(offsetof(Config,proxy_host)),
1201 I(sizeof(((Config *)0)->proxy_host)));
1202 c->generic.column = 0;
1203 c = ctrl_editbox(s, "Port", 'p', 100,
1204 HELPCTX(proxy_main),
1205 dlg_stdeditbox_handler,
1206 I(offsetof(Config,proxy_port)),
1207 I(-1));
1208 c->generic.column = 1;
1209 ctrl_columns(s, 1, 100);
1210 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1211 HELPCTX(proxy_exclude),
1212 dlg_stdeditbox_handler,
1213 I(offsetof(Config,proxy_exclude_list)),
1214 I(sizeof(((Config *)0)->proxy_exclude_list)));
1215 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1216 HELPCTX(proxy_exclude),
1217 dlg_stdcheckbox_handler,
1218 I(offsetof(Config,even_proxy_localhost)));
1219 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1220 HELPCTX(proxy_dns),
1221 dlg_stdradiobutton_handler,
1222 I(offsetof(Config, proxy_dns)),
1223 "No", I(FORCE_OFF),
1224 "Auto", I(AUTO),
1225 "Yes", I(FORCE_ON), NULL);
1226 ctrl_editbox(s, "Username", 'u', 60,
1227 HELPCTX(proxy_auth),
1228 dlg_stdeditbox_handler,
1229 I(offsetof(Config,proxy_username)),
1230 I(sizeof(((Config *)0)->proxy_username)));
1231 c = ctrl_editbox(s, "Password", 'w', 60,
1232 HELPCTX(proxy_auth),
1233 dlg_stdeditbox_handler,
1234 I(offsetof(Config,proxy_password)),
1235 I(sizeof(((Config *)0)->proxy_password)));
1236 c->editbox.password = 1;
1237
1238 s = ctrl_getset(b, "Connection/Proxy", "misc",
1239 "Miscellaneous proxy settings");
1240 ctrl_editbox(s, "Telnet command", 'm', 100,
1241 HELPCTX(proxy_command),
1242 dlg_stdeditbox_handler,
1243 I(offsetof(Config,proxy_telnet_command)),
1244 I(sizeof(((Config *)0)->proxy_telnet_command)));
1245 ctrl_radiobuttons(s, "SOCKS Version", 'v', 2,
1246 HELPCTX(proxy_socksver),
1247 dlg_stdradiobutton_handler,
1248 I(offsetof(Config, proxy_socks_version)),
1249 "Version 5", I(5), "Version 4", I(4), NULL);
1250 }
1251
1252 /*
1253 * The Telnet panel exists in the base config box, and in a
1254 * mid-session reconfig box _if_ we're using Telnet.
1255 */
1256 if (!midsession || protocol == PROT_TELNET) {
1257 /*
1258 * The Connection/Telnet panel.
1259 */
1260 ctrl_settitle(b, "Connection/Telnet",
1261 "Options controlling Telnet connections");
1262
1263 if (!midsession) {
1264 s = ctrl_getset(b, "Connection/Telnet", "data",
1265 "Data to send to the server");
1266 ctrl_editbox(s, "Terminal-speed string", 's', 50,
1267 HELPCTX(telnet_termspeed),
1268 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1269 I(sizeof(((Config *)0)->termspeed)));
1270 ctrl_text(s, "Environment variables:", HELPCTX(telnet_environ));
1271 ctrl_columns(s, 2, 80, 20);
1272 ed = (struct environ_data *)
1273 ctrl_alloc(b, sizeof(struct environ_data));
1274 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1275 HELPCTX(telnet_environ),
1276 environ_handler, P(ed), P(NULL));
1277 ed->varbox->generic.column = 0;
1278 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1279 HELPCTX(telnet_environ),
1280 environ_handler, P(ed), P(NULL));
1281 ed->valbox->generic.column = 0;
1282 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1283 HELPCTX(telnet_environ),
1284 environ_handler, P(ed));
1285 ed->addbutton->generic.column = 1;
1286 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1287 HELPCTX(telnet_environ),
1288 environ_handler, P(ed));
1289 ed->rembutton->generic.column = 1;
1290 ctrl_columns(s, 1, 100);
1291 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1292 HELPCTX(telnet_environ),
1293 environ_handler, P(ed));
1294 ed->listbox->listbox.height = 3;
1295 }
1296
1297 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1298 "Telnet protocol adjustments");
1299
1300 if (!midsession) {
1301 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1302 NO_SHORTCUT, 2,
1303 HELPCTX(telnet_oldenviron),
1304 dlg_stdradiobutton_handler,
1305 I(offsetof(Config, rfc_environ)),
1306 "BSD (commonplace)", 'b', I(0),
1307 "RFC 1408 (unusual)", 'f', I(1), NULL);
1308 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1309 HELPCTX(telnet_passive),
1310 dlg_stdradiobutton_handler,
1311 I(offsetof(Config, passive_telnet)),
1312 "Passive", I(1), "Active", I(0), NULL);
1313 }
1314 ctrl_checkbox(s, "Keyboard sends telnet Backspace and Interrupt", 'k',
1315 HELPCTX(telnet_specialkeys),
1316 dlg_stdcheckbox_handler,
1317 I(offsetof(Config,telnet_keyboard)));
1318 ctrl_checkbox(s, "Return key sends telnet New Line instead of ^M",
1319 NO_SHORTCUT, HELPCTX(telnet_newline),
1320 dlg_stdcheckbox_handler,
1321 I(offsetof(Config,telnet_newline)));
1322 }
1323
1324 if (!midsession) {
1325
1326 /*
1327 * The Connection/Rlogin panel.
1328 */
1329 ctrl_settitle(b, "Connection/Rlogin",
1330 "Options controlling Rlogin connections");
1331
1332 s = ctrl_getset(b, "Connection/Rlogin", "data",
1333 "Data to send to the server");
1334 ctrl_editbox(s, "Terminal-speed string", 's', 50,
1335 HELPCTX(rlogin_termspeed),
1336 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1337 I(sizeof(((Config *)0)->termspeed)));
1338 ctrl_editbox(s, "Local username:", 'l', 50,
1339 HELPCTX(rlogin_localuser),
1340 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1341 I(sizeof(((Config *)0)->localusername)));
1342
1343 }
1344
1345 /*
1346 * All the SSH stuff is omitted in PuTTYtel.
1347 */
1348
1349 if (!midsession && backends[3].backend != NULL) {
1350
1351 /*
1352 * The Connection/SSH panel.
1353 */
1354 ctrl_settitle(b, "Connection/SSH",
1355 "Options controlling SSH connections");
1356
1357 s = ctrl_getset(b, "Connection/SSH", "data",
1358 "Data to send to the server");
1359 ctrl_editbox(s, "Remote command:", 'r', 100,
1360 HELPCTX(ssh_command),
1361 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1362 I(sizeof(((Config *)0)->remote_cmd)));
1363
1364 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1365 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1366 HELPCTX(ssh_nopty),
1367 dlg_stdcheckbox_handler,
1368 I(offsetof(Config,nopty)));
1369 ctrl_checkbox(s, "Enable compression", 'e',
1370 HELPCTX(ssh_compress),
1371 dlg_stdcheckbox_handler,
1372 I(offsetof(Config,compression)));
1373 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1374 HELPCTX(ssh_protocol),
1375 dlg_stdradiobutton_handler,
1376 I(offsetof(Config, sshprot)),
1377 "1 only", 'l', I(0),
1378 "1", '1', I(1),
1379 "2", '2', I(2),
1380 "2 only", 'n', I(3), NULL);
1381
1382 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1383 ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1384 HELPCTX(ssh_ciphers),
1385 cipherlist_handler, P(NULL));
1386 ctrl_checkbox(s, "Enable non-standard use of single-DES in SSH 2", 'i',
1387 HELPCTX(ssh_ciphers),
1388 dlg_stdcheckbox_handler,
1389 I(offsetof(Config,ssh2_des_cbc)));
1390
1391 /*
1392 * The Connection/SSH/Auth panel.
1393 */
1394 ctrl_settitle(b, "Connection/SSH/Auth",
1395 "Options controlling SSH authentication");
1396
1397 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1398 "Authentication methods");
1399 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH1)", 'm',
1400 HELPCTX(ssh_auth_tis),
1401 dlg_stdcheckbox_handler,
1402 I(offsetof(Config,try_tis_auth)));
1403 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH2)",
1404 'i', HELPCTX(ssh_auth_ki),
1405 dlg_stdcheckbox_handler,
1406 I(offsetof(Config,try_ki_auth)));
1407
1408 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1409 "Authentication parameters");
1410 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1411 HELPCTX(ssh_auth_agentfwd),
1412 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
1413 ctrl_checkbox(s, "Allow attempted changes of username in SSH2", 'u',
1414 HELPCTX(ssh_auth_changeuser),
1415 dlg_stdcheckbox_handler,
1416 I(offsetof(Config,change_username)));
1417 ctrl_filesel(s, "Private key file for authentication:", 'k',
1418 FILTER_KEY_FILES, FALSE, "Select private key file",
1419 HELPCTX(ssh_auth_privkey),
1420 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1421
1422 /*
1423 * The Connection/SSH/Tunnels panel.
1424 */
1425 ctrl_settitle(b, "Connection/SSH/Tunnels",
1426 "Options controlling SSH tunnelling");
1427
1428 s = ctrl_getset(b, "Connection/SSH/Tunnels", "x11", "X11 forwarding");
1429 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1430 HELPCTX(ssh_tunnels_x11),
1431 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1432 ctrl_editbox(s, "X display location", 'x', 50,
1433 HELPCTX(ssh_tunnels_x11),
1434 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1435 I(sizeof(((Config *)0)->x11_display)));
1436 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1437 HELPCTX(ssh_tunnels_x11auth),
1438 dlg_stdradiobutton_handler,
1439 I(offsetof(Config, x11_auth)),
1440 "MIT-Magic-Cookie-1", I(X11_MIT),
1441 "XDM-Authorization-1", I(X11_XDM), NULL);
1442
1443 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1444 "Port forwarding");
1445 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1446 HELPCTX(ssh_tunnels_portfwd_localhost),
1447 dlg_stdcheckbox_handler,
1448 I(offsetof(Config,lport_acceptall)));
1449 ctrl_checkbox(s, "Remote ports do the same (SSH v2 only)", 'p',
1450 HELPCTX(ssh_tunnels_portfwd_localhost),
1451 dlg_stdcheckbox_handler,
1452 I(offsetof(Config,rport_acceptall)));
1453
1454 ctrl_columns(s, 3, 55, 20, 25);
1455 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1456 c->generic.column = COLUMN_FIELD(0,2);
1457 /* You want to select from the list, _then_ hit Remove. So tab order
1458 * should be that way round. */
1459 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1460 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1461 HELPCTX(ssh_tunnels_portfwd),
1462 portfwd_handler, P(pfd));
1463 pfd->rembutton->generic.column = 2;
1464 pfd->rembutton->generic.tabdelay = 1;
1465 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1466 HELPCTX(ssh_tunnels_portfwd),
1467 portfwd_handler, P(pfd));
1468 pfd->listbox->listbox.height = 3;
1469 ctrl_tabdelay(s, pfd->rembutton);
1470 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
1471 /* You want to enter source, destination and type, _then_ hit Add.
1472 * Again, we adjust the tab order to reflect this. */
1473 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
1474 HELPCTX(ssh_tunnels_portfwd),
1475 portfwd_handler, P(pfd));
1476 pfd->addbutton->generic.column = 2;
1477 pfd->addbutton->generic.tabdelay = 1;
1478 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
1479 HELPCTX(ssh_tunnels_portfwd),
1480 portfwd_handler, P(pfd), P(NULL));
1481 pfd->sourcebox->generic.column = 0;
1482 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
1483 HELPCTX(ssh_tunnels_portfwd),
1484 portfwd_handler, P(pfd), P(NULL));
1485 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2,
1486 HELPCTX(ssh_tunnels_portfwd),
1487 portfwd_handler, P(pfd),
1488 "Local", 'l', P(NULL),
1489 "Remote", 'm', P(NULL), NULL);
1490 ctrl_tabdelay(s, pfd->addbutton);
1491 ctrl_columns(s, 1, 100);
1492
1493 /*
1494 * The Connection/SSH/Bugs panel.
1495 */
1496 ctrl_settitle(b, "Connection/SSH/Bugs",
1497 "Workarounds for SSH server bugs");
1498
1499 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
1500 "Detection of known bugs in SSH servers");
1501 ctrl_droplist(s, "Chokes on SSH1 ignore messages", 'i', 20,
1502 HELPCTX(ssh_bugs_ignore1),
1503 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
1504 ctrl_droplist(s, "Refuses all SSH1 password camouflage", 's', 20,
1505 HELPCTX(ssh_bugs_plainpw1),
1506 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
1507 ctrl_droplist(s, "Chokes on SSH1 RSA authentication", 'r', 20,
1508 HELPCTX(ssh_bugs_rsa1),
1509 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
1510 ctrl_droplist(s, "Miscomputes SSH2 HMAC keys", 'm', 20,
1511 HELPCTX(ssh_bugs_hmac2),
1512 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
1513 ctrl_droplist(s, "Miscomputes SSH2 encryption keys", 'e', 20,
1514 HELPCTX(ssh_bugs_derivekey2),
1515 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
1516 ctrl_droplist(s, "Requires padding on SSH2 RSA signatures", 'p', 20,
1517 HELPCTX(ssh_bugs_rsapad2),
1518 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
1519 ctrl_droplist(s, "Chokes on Diffie-Hellman group exchange", 'd', 20,
1520 HELPCTX(ssh_bugs_dhgex2),
1521 sshbug_handler, I(offsetof(Config,sshbug_dhgex2)));
1522 ctrl_droplist(s, "Misuses the session ID in PK auth", 'n', 20,
1523 HELPCTX(ssh_bugs_pksessid2),
1524 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
1525 }
1526}