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