Jacob points out that TS_EOL is broken in BINARY mode.
[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
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) {
6f87d111 297 int i = dlg_listbox_index(ssd->listbox, dlg);
fe8abbf4 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)));
876e5d5e 983 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
984 HELPCTX(window_erased),
985 dlg_stdcheckbox_handler,
986 I(offsetof(Config,erase_to_scrollback)));
fe8abbf4 987
988 /*
989 * The Window/Appearance panel.
990 */
991 ctrl_settitle(b, "Window/Appearance",
992 "Configure the appearance of PuTTY's window");
993
994 s = ctrl_getset(b, "Window/Appearance", "cursor",
995 "Adjust the use of the cursor");
996 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
997 HELPCTX(appearance_cursor),
998 dlg_stdradiobutton_handler,
999 I(offsetof(Config, cursor_type)),
1000 "Block", 'l', I(0),
1001 "Underline", 'u', I(1),
1002 "Vertical line", 'v', I(2), NULL);
1003 ctrl_checkbox(s, "Cursor blinks", 'b',
1004 HELPCTX(appearance_cursor),
1005 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1006
1007 s = ctrl_getset(b, "Window/Appearance", "font",
1008 "Font settings");
1009 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1010 HELPCTX(appearance_font),
1011 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1012
1013 s = ctrl_getset(b, "Window/Appearance", "mouse",
1014 "Adjust the use of the mouse pointer");
1015 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1016 HELPCTX(appearance_hidemouse),
1017 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1018
1019 s = ctrl_getset(b, "Window/Appearance", "border",
1020 "Adjust the window border");
1021 ctrl_editbox(s, "Gap between text and window edge:", NO_SHORTCUT, 20,
1022 HELPCTX(appearance_border),
1023 dlg_stdeditbox_handler,
1024 I(offsetof(Config,window_border)), I(-1));
1025
1026 /*
1027 * The Window/Behaviour panel.
1028 */
1029 ctrl_settitle(b, "Window/Behaviour",
1030 "Configure the behaviour of PuTTY's window");
1031
1032 s = ctrl_getset(b, "Window/Behaviour", "title",
1033 "Adjust the behaviour of the window title");
1034 ctrl_editbox(s, "Window title:", 't', 100,
1035 HELPCTX(appearance_title),
1036 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1037 I(sizeof(((Config *)0)->wintitle)));
1038 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1039 HELPCTX(appearance_title),
1040 dlg_stdcheckbox_handler,
1041 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1042
1043 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1044 ctrl_checkbox(s, "Warn before closing window", 'w',
1045 HELPCTX(behaviour_closewarn),
1046 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1047
1048 /*
1049 * The Window/Translation panel.
1050 */
1051 ctrl_settitle(b, "Window/Translation",
1052 "Options controlling character set translation");
1053
1054 s = ctrl_getset(b, "Window/Translation", "trans",
1055 "Character set translation on received data");
1056 ctrl_combobox(s, "Received data assumed to be in which character set:",
1057 'r', 100, HELPCTX(translation_codepage),
1058 codepage_handler, P(NULL), P(NULL));
1059
1060 s = ctrl_getset(b, "Window/Translation", "linedraw",
1061 "Adjust how PuTTY displays line drawing characters");
1062 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1063 HELPCTX(translation_linedraw),
1064 dlg_stdradiobutton_handler,
1065 I(offsetof(Config, vtmode)),
1066 "Font has XWindows encoding", 'x', I(VT_XWINDOWS),
1067 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
1068 "Unicode mode", 'u', I(VT_UNICODE), NULL);
1069
1070 /*
1071 * The Window/Selection panel.
1072 */
1073 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
1074
1075 s = ctrl_getset(b, "Window/Selection", "trans",
1076 "Translation of pasted characters");
1077 ctrl_checkbox(s, "Don't translate line drawing chars into +, - and |",'d',
1078 HELPCTX(selection_linedraw),
1079 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
1080
1081 s = ctrl_getset(b, "Window/Selection", "mouse",
1082 "Control use of mouse");
1083 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1084 HELPCTX(selection_shiftdrag),
1085 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1086 ctrl_radiobuttons(s,
1087 "Default selection mode (Alt+drag does the other one):",
1088 NO_SHORTCUT, 2,
1089 HELPCTX(selection_rect),
1090 dlg_stdradiobutton_handler,
1091 I(offsetof(Config, rect_select)),
1092 "Normal", 'n', I(0),
1093 "Rectangular block", 'r', I(1), NULL);
1094
1095 s = ctrl_getset(b, "Window/Selection", "charclass",
1096 "Control the select-one-word-at-a-time mode");
1097 ccd = (struct charclass_data *)
1098 ctrl_alloc(b, sizeof(struct charclass_data));
1099 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1100 HELPCTX(selection_charclasses),
1101 charclass_handler, P(ccd));
1102 ccd->listbox->listbox.multisel = 1;
1103 ccd->listbox->listbox.ncols = 4;
1104 ccd->listbox->listbox.percentages = smalloc(4*sizeof(int));
1105 ccd->listbox->listbox.percentages[0] = 15;
1106 ccd->listbox->listbox.percentages[1] = 25;
1107 ccd->listbox->listbox.percentages[2] = 20;
1108 ccd->listbox->listbox.percentages[3] = 40;
1109 ctrl_columns(s, 2, 67, 33);
1110 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1111 HELPCTX(selection_charclasses),
1112 charclass_handler, P(ccd), P(NULL));
1113 ccd->editbox->generic.column = 0;
1114 ccd->button = ctrl_pushbutton(s, "Set", 's',
1115 HELPCTX(selection_charclasses),
1116 charclass_handler, P(ccd));
1117 ccd->button->generic.column = 1;
1118 ctrl_columns(s, 1, 100);
1119
1120 /*
1121 * The Window/Colours panel.
1122 */
1123 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1124
1125 s = ctrl_getset(b, "Window/Colours", "general",
1126 "General options for colour usage");
1127 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1128 HELPCTX(colours_bold),
1129 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1130
1131 s = ctrl_getset(b, "Window/Colours", "adjust",
1132 "Adjust the precise colours PuTTY displays");
1133 ctrl_text(s, "Select a colour from the list, and then click the"
1134 " Modify button to change its appearance.",
1135 HELPCTX(colours_config));
1136 ctrl_columns(s, 2, 67, 33);
1137 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1138 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1139 HELPCTX(colours_config), colour_handler, P(cd));
1140 cd->listbox->generic.column = 0;
1141 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1142 c->generic.column = 1;
1143 cd->rgbtext = ctrl_text(s, "00/00/00", HELPCTX(colours_config));
1144 cd->rgbtext->generic.column = 1;
1145 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1146 colour_handler, P(cd));
1147 cd->button->generic.column = 1;
1148 ctrl_columns(s, 1, 100);
1149
1150 /*
1151 * The Connection panel.
1152 */
1153 ctrl_settitle(b, "Connection", "Options controlling the connection");
1154
1155 if (!midsession) {
1156 s = ctrl_getset(b, "Connection", "data", "Data to send to the server");
1157 ctrl_editbox(s, "Terminal-type string", 't', 50,
1158 HELPCTX(connection_termtype),
1159 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1160 I(sizeof(((Config *)0)->termtype)));
1161 ctrl_editbox(s, "Auto-login username", 'u', 50,
1162 HELPCTX(connection_username),
1163 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1164 I(sizeof(((Config *)0)->username)));
1165 }
1166
1167 s = ctrl_getset(b, "Connection", "keepalive",
1168 "Sending of null packets to keep session active");
1169 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1170 HELPCTX(connection_keepalive),
1171 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1172 I(-1));
1173
1174 if (!midsession) {
1175 s = ctrl_getset(b, "Connection", "tcp",
1176 "Low-level TCP connection options");
1177 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)", 'n',
1178 HELPCTX(connection_nodelay),
1179 dlg_stdcheckbox_handler,
1180 I(offsetof(Config,tcp_nodelay)));
1181 }
1182
1183 if (!midsession) {
1184 /*
1185 * The Connection/Proxy panel.
1186 */
1187 ctrl_settitle(b, "Connection/Proxy",
1188 "Options controlling proxy usage");
1189
1190 s = ctrl_getset(b, "Connection/Proxy", "basics", "Proxy basics");
1191 ctrl_radiobuttons(s, "Proxy type:", NO_SHORTCUT, 4,
1192 HELPCTX(proxy_type),
1193 dlg_stdradiobutton_handler,
1194 I(offsetof(Config, proxy_type)),
1195 "None", 'n', I(PROXY_NONE),
1196 "HTTP", 't', I(PROXY_HTTP),
1197 "SOCKS", 's', I(PROXY_SOCKS),
1198 "Telnet", 'l', I(PROXY_TELNET),
1199 NULL);
1200 ctrl_columns(s, 2, 80, 20);
1201 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1202 HELPCTX(proxy_main),
1203 dlg_stdeditbox_handler,
1204 I(offsetof(Config,proxy_host)),
1205 I(sizeof(((Config *)0)->proxy_host)));
1206 c->generic.column = 0;
1207 c = ctrl_editbox(s, "Port", 'p', 100,
1208 HELPCTX(proxy_main),
1209 dlg_stdeditbox_handler,
1210 I(offsetof(Config,proxy_port)),
1211 I(-1));
1212 c->generic.column = 1;
1213 ctrl_columns(s, 1, 100);
1214 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1215 HELPCTX(proxy_exclude),
1216 dlg_stdeditbox_handler,
1217 I(offsetof(Config,proxy_exclude_list)),
1218 I(sizeof(((Config *)0)->proxy_exclude_list)));
1219 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1220 HELPCTX(proxy_exclude),
1221 dlg_stdcheckbox_handler,
1222 I(offsetof(Config,even_proxy_localhost)));
1223 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1224 HELPCTX(proxy_dns),
1225 dlg_stdradiobutton_handler,
1226 I(offsetof(Config, proxy_dns)),
1227 "No", I(FORCE_OFF),
1228 "Auto", I(AUTO),
1229 "Yes", I(FORCE_ON), NULL);
1230 ctrl_editbox(s, "Username", 'u', 60,
1231 HELPCTX(proxy_auth),
1232 dlg_stdeditbox_handler,
1233 I(offsetof(Config,proxy_username)),
1234 I(sizeof(((Config *)0)->proxy_username)));
1235 c = ctrl_editbox(s, "Password", 'w', 60,
1236 HELPCTX(proxy_auth),
1237 dlg_stdeditbox_handler,
1238 I(offsetof(Config,proxy_password)),
1239 I(sizeof(((Config *)0)->proxy_password)));
1240 c->editbox.password = 1;
1241
1242 s = ctrl_getset(b, "Connection/Proxy", "misc",
1243 "Miscellaneous proxy settings");
1244 ctrl_editbox(s, "Telnet command", 'm', 100,
1245 HELPCTX(proxy_command),
1246 dlg_stdeditbox_handler,
1247 I(offsetof(Config,proxy_telnet_command)),
1248 I(sizeof(((Config *)0)->proxy_telnet_command)));
1249 ctrl_radiobuttons(s, "SOCKS Version", 'v', 2,
1250 HELPCTX(proxy_socksver),
1251 dlg_stdradiobutton_handler,
1252 I(offsetof(Config, proxy_socks_version)),
1253 "Version 5", I(5), "Version 4", I(4), NULL);
1254 }
1255
1256 /*
1257 * The Telnet panel exists in the base config box, and in a
1258 * mid-session reconfig box _if_ we're using Telnet.
1259 */
1260 if (!midsession || protocol == PROT_TELNET) {
1261 /*
1262 * The Connection/Telnet panel.
1263 */
1264 ctrl_settitle(b, "Connection/Telnet",
1265 "Options controlling Telnet connections");
1266
1267 if (!midsession) {
1268 s = ctrl_getset(b, "Connection/Telnet", "data",
1269 "Data to send to the server");
1270 ctrl_editbox(s, "Terminal-speed string", 's', 50,
1271 HELPCTX(telnet_termspeed),
1272 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1273 I(sizeof(((Config *)0)->termspeed)));
1274 ctrl_text(s, "Environment variables:", HELPCTX(telnet_environ));
1275 ctrl_columns(s, 2, 80, 20);
1276 ed = (struct environ_data *)
1277 ctrl_alloc(b, sizeof(struct environ_data));
1278 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1279 HELPCTX(telnet_environ),
1280 environ_handler, P(ed), P(NULL));
1281 ed->varbox->generic.column = 0;
1282 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1283 HELPCTX(telnet_environ),
1284 environ_handler, P(ed), P(NULL));
1285 ed->valbox->generic.column = 0;
1286 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1287 HELPCTX(telnet_environ),
1288 environ_handler, P(ed));
1289 ed->addbutton->generic.column = 1;
1290 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1291 HELPCTX(telnet_environ),
1292 environ_handler, P(ed));
1293 ed->rembutton->generic.column = 1;
1294 ctrl_columns(s, 1, 100);
1295 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1296 HELPCTX(telnet_environ),
1297 environ_handler, P(ed));
1298 ed->listbox->listbox.height = 3;
1299 }
1300
1301 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1302 "Telnet protocol adjustments");
1303
1304 if (!midsession) {
1305 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1306 NO_SHORTCUT, 2,
1307 HELPCTX(telnet_oldenviron),
1308 dlg_stdradiobutton_handler,
1309 I(offsetof(Config, rfc_environ)),
1310 "BSD (commonplace)", 'b', I(0),
1311 "RFC 1408 (unusual)", 'f', I(1), NULL);
1312 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1313 HELPCTX(telnet_passive),
1314 dlg_stdradiobutton_handler,
1315 I(offsetof(Config, passive_telnet)),
1316 "Passive", I(1), "Active", I(0), NULL);
1317 }
1318 ctrl_checkbox(s, "Keyboard sends telnet Backspace and Interrupt", 'k',
1319 HELPCTX(telnet_specialkeys),
1320 dlg_stdcheckbox_handler,
1321 I(offsetof(Config,telnet_keyboard)));
1322 ctrl_checkbox(s, "Return key sends telnet New Line instead of ^M",
1323 NO_SHORTCUT, HELPCTX(telnet_newline),
1324 dlg_stdcheckbox_handler,
1325 I(offsetof(Config,telnet_newline)));
1326 }
1327
1328 if (!midsession) {
1329
1330 /*
1331 * The Connection/Rlogin panel.
1332 */
1333 ctrl_settitle(b, "Connection/Rlogin",
1334 "Options controlling Rlogin connections");
1335
1336 s = ctrl_getset(b, "Connection/Rlogin", "data",
1337 "Data to send to the server");
1338 ctrl_editbox(s, "Terminal-speed string", 's', 50,
1339 HELPCTX(rlogin_termspeed),
1340 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1341 I(sizeof(((Config *)0)->termspeed)));
1342 ctrl_editbox(s, "Local username:", 'l', 50,
1343 HELPCTX(rlogin_localuser),
1344 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1345 I(sizeof(((Config *)0)->localusername)));
1346
1347 }
1348
1349 /*
1350 * All the SSH stuff is omitted in PuTTYtel.
1351 */
1352
1353 if (!midsession && backends[3].backend != NULL) {
1354
1355 /*
1356 * The Connection/SSH panel.
1357 */
1358 ctrl_settitle(b, "Connection/SSH",
1359 "Options controlling SSH connections");
1360
1361 s = ctrl_getset(b, "Connection/SSH", "data",
1362 "Data to send to the server");
1363 ctrl_editbox(s, "Remote command:", 'r', 100,
1364 HELPCTX(ssh_command),
1365 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1366 I(sizeof(((Config *)0)->remote_cmd)));
1367
1368 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1369 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1370 HELPCTX(ssh_nopty),
1371 dlg_stdcheckbox_handler,
1372 I(offsetof(Config,nopty)));
1373 ctrl_checkbox(s, "Enable compression", 'e',
1374 HELPCTX(ssh_compress),
1375 dlg_stdcheckbox_handler,
1376 I(offsetof(Config,compression)));
1377 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1378 HELPCTX(ssh_protocol),
1379 dlg_stdradiobutton_handler,
1380 I(offsetof(Config, sshprot)),
1381 "1 only", 'l', I(0),
1382 "1", '1', I(1),
1383 "2", '2', I(2),
1384 "2 only", 'n', I(3), NULL);
1385
1386 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1387 ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1388 HELPCTX(ssh_ciphers),
1389 cipherlist_handler, P(NULL));
1390 ctrl_checkbox(s, "Enable non-standard use of single-DES in SSH 2", 'i',
1391 HELPCTX(ssh_ciphers),
1392 dlg_stdcheckbox_handler,
1393 I(offsetof(Config,ssh2_des_cbc)));
1394
1395 /*
1396 * The Connection/SSH/Auth panel.
1397 */
1398 ctrl_settitle(b, "Connection/SSH/Auth",
1399 "Options controlling SSH authentication");
1400
1401 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1402 "Authentication methods");
1403 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH1)", 'm',
1404 HELPCTX(ssh_auth_tis),
1405 dlg_stdcheckbox_handler,
1406 I(offsetof(Config,try_tis_auth)));
1407 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH2)",
1408 'i', HELPCTX(ssh_auth_ki),
1409 dlg_stdcheckbox_handler,
1410 I(offsetof(Config,try_ki_auth)));
1411
1412 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1413 "Authentication parameters");
1414 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1415 HELPCTX(ssh_auth_agentfwd),
1416 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
1417 ctrl_checkbox(s, "Allow attempted changes of username in SSH2", 'u',
1418 HELPCTX(ssh_auth_changeuser),
1419 dlg_stdcheckbox_handler,
1420 I(offsetof(Config,change_username)));
1421 ctrl_filesel(s, "Private key file for authentication:", 'k',
1422 FILTER_KEY_FILES, FALSE, "Select private key file",
1423 HELPCTX(ssh_auth_privkey),
1424 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1425
1426 /*
1427 * The Connection/SSH/Tunnels panel.
1428 */
1429 ctrl_settitle(b, "Connection/SSH/Tunnels",
1430 "Options controlling SSH tunnelling");
1431
1432 s = ctrl_getset(b, "Connection/SSH/Tunnels", "x11", "X11 forwarding");
1433 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1434 HELPCTX(ssh_tunnels_x11),
1435 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1436 ctrl_editbox(s, "X display location", 'x', 50,
1437 HELPCTX(ssh_tunnels_x11),
1438 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1439 I(sizeof(((Config *)0)->x11_display)));
1440 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1441 HELPCTX(ssh_tunnels_x11auth),
1442 dlg_stdradiobutton_handler,
1443 I(offsetof(Config, x11_auth)),
1444 "MIT-Magic-Cookie-1", I(X11_MIT),
1445 "XDM-Authorization-1", I(X11_XDM), NULL);
1446
1447 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1448 "Port forwarding");
1449 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1450 HELPCTX(ssh_tunnels_portfwd_localhost),
1451 dlg_stdcheckbox_handler,
1452 I(offsetof(Config,lport_acceptall)));
1453 ctrl_checkbox(s, "Remote ports do the same (SSH v2 only)", 'p',
1454 HELPCTX(ssh_tunnels_portfwd_localhost),
1455 dlg_stdcheckbox_handler,
1456 I(offsetof(Config,rport_acceptall)));
1457
1458 ctrl_columns(s, 3, 55, 20, 25);
1459 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1460 c->generic.column = COLUMN_FIELD(0,2);
1461 /* You want to select from the list, _then_ hit Remove. So tab order
1462 * should be that way round. */
1463 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1464 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1465 HELPCTX(ssh_tunnels_portfwd),
1466 portfwd_handler, P(pfd));
1467 pfd->rembutton->generic.column = 2;
1468 pfd->rembutton->generic.tabdelay = 1;
1469 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1470 HELPCTX(ssh_tunnels_portfwd),
1471 portfwd_handler, P(pfd));
1472 pfd->listbox->listbox.height = 3;
1473 ctrl_tabdelay(s, pfd->rembutton);
1474 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
1475 /* You want to enter source, destination and type, _then_ hit Add.
1476 * Again, we adjust the tab order to reflect this. */
1477 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
1478 HELPCTX(ssh_tunnels_portfwd),
1479 portfwd_handler, P(pfd));
1480 pfd->addbutton->generic.column = 2;
1481 pfd->addbutton->generic.tabdelay = 1;
1482 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
1483 HELPCTX(ssh_tunnels_portfwd),
1484 portfwd_handler, P(pfd), P(NULL));
1485 pfd->sourcebox->generic.column = 0;
1486 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
1487 HELPCTX(ssh_tunnels_portfwd),
1488 portfwd_handler, P(pfd), P(NULL));
1489 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2,
1490 HELPCTX(ssh_tunnels_portfwd),
1491 portfwd_handler, P(pfd),
1492 "Local", 'l', P(NULL),
1493 "Remote", 'm', P(NULL), NULL);
1494 ctrl_tabdelay(s, pfd->addbutton);
1495 ctrl_columns(s, 1, 100);
1496
1497 /*
1498 * The Connection/SSH/Bugs panel.
1499 */
1500 ctrl_settitle(b, "Connection/SSH/Bugs",
1501 "Workarounds for SSH server bugs");
1502
1503 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
1504 "Detection of known bugs in SSH servers");
1505 ctrl_droplist(s, "Chokes on SSH1 ignore messages", 'i', 20,
1506 HELPCTX(ssh_bugs_ignore1),
1507 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
1508 ctrl_droplist(s, "Refuses all SSH1 password camouflage", 's', 20,
1509 HELPCTX(ssh_bugs_plainpw1),
1510 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
1511 ctrl_droplist(s, "Chokes on SSH1 RSA authentication", 'r', 20,
1512 HELPCTX(ssh_bugs_rsa1),
1513 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
1514 ctrl_droplist(s, "Miscomputes SSH2 HMAC keys", 'm', 20,
1515 HELPCTX(ssh_bugs_hmac2),
1516 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
1517 ctrl_droplist(s, "Miscomputes SSH2 encryption keys", 'e', 20,
1518 HELPCTX(ssh_bugs_derivekey2),
1519 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
1520 ctrl_droplist(s, "Requires padding on SSH2 RSA signatures", 'p', 20,
1521 HELPCTX(ssh_bugs_rsapad2),
1522 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
1523 ctrl_droplist(s, "Chokes on Diffie-Hellman group exchange", 'd', 20,
1524 HELPCTX(ssh_bugs_dhgex2),
1525 sshbug_handler, I(offsetof(Config,sshbug_dhgex2)));
1526 ctrl_droplist(s, "Misuses the session ID in PK auth", 'n', 20,
1527 HELPCTX(ssh_bugs_pksessid2),
1528 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
1529 }
1530}