Fiddle with the cmdline_saved mechanism: the `-load' option is now
[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);
07e4d76d 599 } else if (ctrl == pfd->direction) {
600 /*
601 * Default is Local.
602 */
603 dlg_radiobutton_set(ctrl, dlg, 0);
fe8abbf4 604 }
605 } else if (event == EVENT_ACTION) {
606 if (ctrl == pfd->addbutton) {
607 char str[sizeof(cfg->portfwd)];
608 char *p;
609 if (dlg_radiobutton_get(pfd->direction, dlg) == 0)
610 str[0] = 'L';
611 else
612 str[0] = 'R';
613 dlg_editbox_get(pfd->sourcebox, dlg, str+1, sizeof(str) - 2);
614 if (!str[1]) {
615 dlg_error_msg(dlg, "You need to specify a source port number");
616 return;
617 }
618 p = str + strlen(str);
619 *p++ = '\t';
620 dlg_editbox_get(pfd->destbox, dlg, p, sizeof(str)-1 - (p - str));
621 if (!*p || !strchr(p, ':')) {
622 dlg_error_msg(dlg,
623 "You need to specify a destination address\n"
624 "in the form \"host.name:port\"");
625 return;
626 }
627 p = cfg->portfwd;
628 while (*p) {
629 while (*p)
630 p++;
631 p++;
632 }
633 if ((p - cfg->portfwd) + strlen(str) + 2 <
634 sizeof(cfg->portfwd)) {
635 strcpy(p, str);
636 p[strlen(str) + 1] = '\0';
637 dlg_listbox_add(pfd->listbox, dlg, str);
638 dlg_editbox_set(pfd->sourcebox, dlg, "");
639 dlg_editbox_set(pfd->destbox, dlg, "");
640 } else {
641 dlg_error_msg(dlg, "Too many forwardings");
642 }
643 } else if (ctrl == pfd->rembutton) {
644 int i = dlg_listbox_index(pfd->listbox, dlg);
645 if (i < 0)
646 dlg_beep(dlg);
647 else {
648 char *p, *q;
649
650 dlg_listbox_del(pfd->listbox, dlg, i);
651 p = cfg->portfwd;
652 while (i > 0) {
653 if (!*p)
654 goto disaster2;
655 while (*p)
656 p++;
657 p++;
658 i--;
659 }
660 q = p;
661 if (!*p)
662 goto disaster2;
663 while (*p)
664 p++;
665 p++;
666 while (*p) {
667 while (*p)
668 *q++ = *p++;
669 *q++ = *p++;
670 }
671 *q = '\0';
672 disaster2:;
673 }
674 }
675 }
676}
677
678void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
679 int midsession, int protocol)
680{
681 struct controlset *s;
682 struct sessionsaver_data *ssd;
683 struct charclass_data *ccd;
684 struct colour_data *cd;
685 struct environ_data *ed;
686 struct portfwd_data *pfd;
687 union control *c;
688
689 ssd = (struct sessionsaver_data *)
690 ctrl_alloc(b, sizeof(struct sessionsaver_data));
691 ssd->sesslist = (midsession ? NULL : sesslist);
692
693 /*
694 * The standard panel that appears at the bottom of all panels:
695 * Open, Cancel, Apply etc.
696 */
697 s = ctrl_getset(b, "", "", "");
698 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
699 ssd->okbutton = ctrl_pushbutton(s,
700 (midsession ? "Apply" : "Open"),
701 (char)(midsession ? 'a' : 'o'),
702 HELPCTX(no_help),
703 sessionsaver_handler, P(ssd));
704 ssd->okbutton->button.isdefault = TRUE;
705 ssd->okbutton->generic.column = 3;
706 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
707 sessionsaver_handler, P(ssd));
0bd8d76d 708 ssd->cancelbutton->button.iscancel = TRUE;
fe8abbf4 709 ssd->cancelbutton->generic.column = 4;
710 /* We carefully don't close the 5-column part, so that platform-
711 * specific add-ons can put extra buttons alongside Open and Cancel. */
712
713 /*
714 * The Session panel.
715 */
716 ctrl_settitle(b, "Session", "Basic options for your PuTTY session");
717
718 if (!midsession) {
719 s = ctrl_getset(b, "Session", "hostport",
720 "Specify your connection by host name or IP address");
721 ctrl_columns(s, 2, 75, 25);
722 c = ctrl_editbox(s, "Host Name (or IP address)", 'n', 100,
723 HELPCTX(session_hostname),
724 dlg_stdeditbox_handler, I(offsetof(Config,host)),
725 I(sizeof(((Config *)0)->host)));
726 c->generic.column = 0;
727 c = ctrl_editbox(s, "Port", 'p', 100, HELPCTX(session_hostname),
728 dlg_stdeditbox_handler,
729 I(offsetof(Config,port)), I(-1));
730 c->generic.column = 1;
731 ctrl_columns(s, 1, 100);
d9b15094 732 if (backends[3].name == NULL) {
fe8abbf4 733 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 3,
734 HELPCTX(session_hostname),
735 protocolbuttons_handler, P(c),
736 "Raw", 'r', I(PROT_RAW),
737 "Telnet", 't', I(PROT_TELNET),
738 "Rlogin", 'i', I(PROT_RLOGIN),
739 NULL);
740 } else {
741 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 4,
742 HELPCTX(session_hostname),
743 protocolbuttons_handler, P(c),
744 "Raw", 'r', I(PROT_RAW),
745 "Telnet", 't', I(PROT_TELNET),
746 "Rlogin", 'i', I(PROT_RLOGIN),
747 "SSH", 's', I(PROT_SSH),
748 NULL);
749 }
750
751 s = ctrl_getset(b, "Session", "savedsessions",
752 "Load, save or delete a stored session");
753 ctrl_columns(s, 2, 75, 25);
fe8abbf4 754 ssd->sesslist = sesslist;
755 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
756 HELPCTX(session_saved),
757 sessionsaver_handler, P(ssd), P(NULL));
758 ssd->editbox->generic.column = 0;
759 /* Reset columns so that the buttons are alongside the list, rather
760 * than alongside that edit box. */
761 ctrl_columns(s, 1, 100);
762 ctrl_columns(s, 2, 75, 25);
0bd8d76d 763 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
764 HELPCTX(session_saved),
765 sessionsaver_handler, P(ssd));
766 ssd->listbox->generic.column = 0;
767 ssd->listbox->listbox.height = 7;
fe8abbf4 768 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
769 HELPCTX(session_saved),
770 sessionsaver_handler, P(ssd));
771 ssd->loadbutton->generic.column = 1;
772 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
773 HELPCTX(session_saved),
774 sessionsaver_handler, P(ssd));
775 ssd->savebutton->generic.column = 1;
776 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
777 HELPCTX(session_saved),
778 sessionsaver_handler, P(ssd));
779 ssd->delbutton->generic.column = 1;
fe8abbf4 780 ctrl_columns(s, 1, 100);
781 }
782
783 s = ctrl_getset(b, "Session", "otheropts", NULL);
784 c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
785 HELPCTX(session_coe),
786 dlg_stdradiobutton_handler,
787 I(offsetof(Config, close_on_exit)),
788 "Always", I(FORCE_ON),
789 "Never", I(FORCE_OFF),
790 "Only on clean exit", I(AUTO), NULL);
791
792 /*
793 * The Session/Logging panel.
794 */
795 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
796
797 s = ctrl_getset(b, "Session/Logging", "main", NULL);
798 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 1,
799 HELPCTX(logging_main),
800 dlg_stdradiobutton_handler, I(offsetof(Config, logtype)),
801 "Logging turned off completely", 't', I(LGTYP_NONE),
802 "Log printable output only", 'p', I(LGTYP_ASCII),
803 "Log all session output", 'l', I(LGTYP_DEBUG),
804 "Log SSH packet data", 's', I(LGTYP_PACKETS),
805 NULL);
806 ctrl_filesel(s, "Log file name:", 'f',
807 NULL, TRUE, "Select session log file name",
808 HELPCTX(logging_filename),
809 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
810 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
811 " &T for time, and &H for host name)",
812 HELPCTX(logging_filename));
813 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
814 HELPCTX(logging_exists),
815 dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
816 "Always overwrite it", I(LGXF_OVR),
817 "Always append to the end of it", I(LGXF_APN),
818 "Ask the user every time", I(LGXF_ASK), NULL);
819
820 /*
821 * The Terminal panel.
822 */
823 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
824
825 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
826 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
827 HELPCTX(terminal_autowrap),
828 dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
829 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
830 HELPCTX(terminal_decom),
831 dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
832 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
833 HELPCTX(terminal_lfhascr),
834 dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
835 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
836 HELPCTX(terminal_bce),
837 dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
838 ctrl_checkbox(s, "Enable blinking text", 'n',
839 HELPCTX(terminal_blink),
840 dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
841 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
842 HELPCTX(terminal_answerback),
843 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
844 I(sizeof(((Config *)0)->answerback)));
845
846 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
847 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
848 HELPCTX(terminal_localecho),
849 dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
850 "Auto", I(AUTO),
851 "Force on", I(FORCE_ON),
852 "Force off", I(FORCE_OFF), NULL);
853 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
854 HELPCTX(terminal_localedit),
855 dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
856 "Auto", I(AUTO),
857 "Force on", I(FORCE_ON),
858 "Force off", I(FORCE_OFF), NULL);
859
860 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
861 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
862 HELPCTX(terminal_printing),
863 printerbox_handler, P(NULL), P(NULL));
864
865 /*
866 * The Terminal/Keyboard panel.
867 */
868 ctrl_settitle(b, "Terminal/Keyboard",
869 "Options controlling the effects of keys");
870
871 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
872 "Change the sequences sent by:");
873 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
874 HELPCTX(keyboard_backspace),
875 dlg_stdradiobutton_handler,
876 I(offsetof(Config, bksp_is_delete)),
877 "Control-H", I(0), "Control-? (127)", I(1), NULL);
878 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
879 HELPCTX(keyboard_homeend),
880 dlg_stdradiobutton_handler,
881 I(offsetof(Config, rxvt_homeend)),
882 "Standard", I(0), "rxvt", I(1), NULL);
883 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
884 HELPCTX(keyboard_funkeys),
885 dlg_stdradiobutton_handler,
886 I(offsetof(Config, funky_type)),
887 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
888 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
889
890 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
891 "Application keypad settings:");
892 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
893 HELPCTX(keyboard_appcursor),
894 dlg_stdradiobutton_handler,
895 I(offsetof(Config, app_cursor)),
896 "Normal", I(0), "Application", I(1), NULL);
897 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
898 HELPCTX(keyboard_appkeypad),
899 numeric_keypad_handler, P(NULL),
900 "Normal", I(0), "Application", I(1), "NetHack", I(2),
901 NULL);
902
903 /*
904 * The Terminal/Bell panel.
905 */
906 ctrl_settitle(b, "Terminal/Bell",
907 "Options controlling the terminal bell");
908
909 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
910 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
911 HELPCTX(bell_style),
912 dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
913 "None (bell disabled)", I(BELL_DISABLED),
914 "Make default system alert sound", I(BELL_DEFAULT),
915 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
916
917 s = ctrl_getset(b, "Terminal/Bell", "overload",
918 "Control the bell overload behaviour");
919 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
920 HELPCTX(bell_overload),
921 dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
922 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
923 HELPCTX(bell_overload),
924 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
925 ctrl_editbox(s, "... in this many seconds", 't', 20,
926 HELPCTX(bell_overload),
927 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
62697e04 928 I(-TICKSPERSEC));
fe8abbf4 929 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
930 HELPCTX(bell_overload));
931 ctrl_editbox(s, "Seconds of silence required", 's', 20,
932 HELPCTX(bell_overload),
933 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
62697e04 934 I(-TICKSPERSEC));
fe8abbf4 935
936 /*
937 * The Terminal/Features panel.
938 */
939 ctrl_settitle(b, "Terminal/Features",
940 "Enabling and disabling advanced terminal features");
941
942 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
943 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
944 HELPCTX(features_application),
945 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
946 ctrl_checkbox(s, "Disable application keypad mode", 'k',
947 HELPCTX(features_application),
948 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
949 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
950 HELPCTX(features_mouse),
951 dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
952 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
953 HELPCTX(features_resize),
954 dlg_stdcheckbox_handler,
955 I(offsetof(Config,no_remote_resize)));
956 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
957 HELPCTX(features_altscreen),
958 dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
959 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
960 HELPCTX(features_retitle),
961 dlg_stdcheckbox_handler,
962 I(offsetof(Config,no_remote_wintitle)));
963 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
964 HELPCTX(features_dbackspace),
965 dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
966 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
967 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
968 I(offsetof(Config,no_remote_charset)));
969
970 /*
971 * The Window panel.
972 */
973 ctrl_settitle(b, "Window", "Options controlling PuTTY's window");
974
975 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
976 ctrl_columns(s, 2, 50, 50);
977 c = ctrl_editbox(s, "Rows", 'r', 100,
978 HELPCTX(window_size),
979 dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
980 c->generic.column = 0;
981 c = ctrl_editbox(s, "Columns", 'm', 100,
982 HELPCTX(window_size),
983 dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
984 c->generic.column = 1;
985 ctrl_columns(s, 1, 100);
986
987 s = ctrl_getset(b, "Window", "scrollback",
988 "Control the scrollback in the window");
989 ctrl_editbox(s, "Lines of scrollback", 's', 50,
990 HELPCTX(window_scrollback),
991 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
992 ctrl_checkbox(s, "Display scrollbar", 'd',
993 HELPCTX(window_scrollback),
994 dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
fe8abbf4 995 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
996 HELPCTX(window_scrollback),
997 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
998 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
999 HELPCTX(window_scrollback),
1000 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
876e5d5e 1001 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
1002 HELPCTX(window_erased),
1003 dlg_stdcheckbox_handler,
1004 I(offsetof(Config,erase_to_scrollback)));
fe8abbf4 1005
1006 /*
1007 * The Window/Appearance panel.
1008 */
1009 ctrl_settitle(b, "Window/Appearance",
1010 "Configure the appearance of PuTTY's window");
1011
1012 s = ctrl_getset(b, "Window/Appearance", "cursor",
1013 "Adjust the use of the cursor");
1014 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
1015 HELPCTX(appearance_cursor),
1016 dlg_stdradiobutton_handler,
1017 I(offsetof(Config, cursor_type)),
1018 "Block", 'l', I(0),
1019 "Underline", 'u', I(1),
1020 "Vertical line", 'v', I(2), NULL);
1021 ctrl_checkbox(s, "Cursor blinks", 'b',
1022 HELPCTX(appearance_cursor),
1023 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1024
1025 s = ctrl_getset(b, "Window/Appearance", "font",
1026 "Font settings");
1027 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1028 HELPCTX(appearance_font),
1029 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1030
1031 s = ctrl_getset(b, "Window/Appearance", "mouse",
1032 "Adjust the use of the mouse pointer");
1033 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1034 HELPCTX(appearance_hidemouse),
1035 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1036
1037 s = ctrl_getset(b, "Window/Appearance", "border",
1038 "Adjust the window border");
1039 ctrl_editbox(s, "Gap between text and window edge:", NO_SHORTCUT, 20,
1040 HELPCTX(appearance_border),
1041 dlg_stdeditbox_handler,
1042 I(offsetof(Config,window_border)), I(-1));
1043
1044 /*
1045 * The Window/Behaviour panel.
1046 */
1047 ctrl_settitle(b, "Window/Behaviour",
1048 "Configure the behaviour of PuTTY's window");
1049
1050 s = ctrl_getset(b, "Window/Behaviour", "title",
1051 "Adjust the behaviour of the window title");
1052 ctrl_editbox(s, "Window title:", 't', 100,
1053 HELPCTX(appearance_title),
1054 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1055 I(sizeof(((Config *)0)->wintitle)));
1056 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1057 HELPCTX(appearance_title),
1058 dlg_stdcheckbox_handler,
1059 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1060
1061 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1062 ctrl_checkbox(s, "Warn before closing window", 'w',
1063 HELPCTX(behaviour_closewarn),
1064 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1065
1066 /*
1067 * The Window/Translation panel.
1068 */
1069 ctrl_settitle(b, "Window/Translation",
1070 "Options controlling character set translation");
1071
1072 s = ctrl_getset(b, "Window/Translation", "trans",
1073 "Character set translation on received data");
1074 ctrl_combobox(s, "Received data assumed to be in which character set:",
1075 'r', 100, HELPCTX(translation_codepage),
1076 codepage_handler, P(NULL), P(NULL));
1077
1078 s = ctrl_getset(b, "Window/Translation", "linedraw",
1079 "Adjust how PuTTY displays line drawing characters");
1080 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1081 HELPCTX(translation_linedraw),
1082 dlg_stdradiobutton_handler,
1083 I(offsetof(Config, vtmode)),
1084 "Font has XWindows encoding", 'x', I(VT_XWINDOWS),
1085 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
1086 "Unicode mode", 'u', I(VT_UNICODE), NULL);
1087
1088 /*
1089 * The Window/Selection panel.
1090 */
1091 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
1092
1093 s = ctrl_getset(b, "Window/Selection", "trans",
1094 "Translation of pasted characters");
1095 ctrl_checkbox(s, "Don't translate line drawing chars into +, - and |",'d',
1096 HELPCTX(selection_linedraw),
1097 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
1098
1099 s = ctrl_getset(b, "Window/Selection", "mouse",
1100 "Control use of mouse");
1101 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1102 HELPCTX(selection_shiftdrag),
1103 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1104 ctrl_radiobuttons(s,
1105 "Default selection mode (Alt+drag does the other one):",
1106 NO_SHORTCUT, 2,
1107 HELPCTX(selection_rect),
1108 dlg_stdradiobutton_handler,
1109 I(offsetof(Config, rect_select)),
1110 "Normal", 'n', I(0),
1111 "Rectangular block", 'r', I(1), NULL);
1112
1113 s = ctrl_getset(b, "Window/Selection", "charclass",
1114 "Control the select-one-word-at-a-time mode");
1115 ccd = (struct charclass_data *)
1116 ctrl_alloc(b, sizeof(struct charclass_data));
1117 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1118 HELPCTX(selection_charclasses),
1119 charclass_handler, P(ccd));
1120 ccd->listbox->listbox.multisel = 1;
1121 ccd->listbox->listbox.ncols = 4;
1122 ccd->listbox->listbox.percentages = smalloc(4*sizeof(int));
1123 ccd->listbox->listbox.percentages[0] = 15;
1124 ccd->listbox->listbox.percentages[1] = 25;
1125 ccd->listbox->listbox.percentages[2] = 20;
1126 ccd->listbox->listbox.percentages[3] = 40;
1127 ctrl_columns(s, 2, 67, 33);
1128 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1129 HELPCTX(selection_charclasses),
1130 charclass_handler, P(ccd), P(NULL));
1131 ccd->editbox->generic.column = 0;
1132 ccd->button = ctrl_pushbutton(s, "Set", 's',
1133 HELPCTX(selection_charclasses),
1134 charclass_handler, P(ccd));
1135 ccd->button->generic.column = 1;
1136 ctrl_columns(s, 1, 100);
1137
1138 /*
1139 * The Window/Colours panel.
1140 */
1141 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1142
1143 s = ctrl_getset(b, "Window/Colours", "general",
1144 "General options for colour usage");
1145 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1146 HELPCTX(colours_bold),
1147 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1148
1149 s = ctrl_getset(b, "Window/Colours", "adjust",
1150 "Adjust the precise colours PuTTY displays");
1151 ctrl_text(s, "Select a colour from the list, and then click the"
1152 " Modify button to change its appearance.",
1153 HELPCTX(colours_config));
1154 ctrl_columns(s, 2, 67, 33);
1155 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1156 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1157 HELPCTX(colours_config), colour_handler, P(cd));
1158 cd->listbox->generic.column = 0;
1159 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1160 c->generic.column = 1;
1161 cd->rgbtext = ctrl_text(s, "00/00/00", HELPCTX(colours_config));
1162 cd->rgbtext->generic.column = 1;
1163 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1164 colour_handler, P(cd));
1165 cd->button->generic.column = 1;
1166 ctrl_columns(s, 1, 100);
1167
1168 /*
1169 * The Connection panel.
1170 */
1171 ctrl_settitle(b, "Connection", "Options controlling the connection");
1172
1173 if (!midsession) {
1174 s = ctrl_getset(b, "Connection", "data", "Data to send to the server");
1175 ctrl_editbox(s, "Terminal-type string", 't', 50,
1176 HELPCTX(connection_termtype),
1177 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1178 I(sizeof(((Config *)0)->termtype)));
1179 ctrl_editbox(s, "Auto-login username", 'u', 50,
1180 HELPCTX(connection_username),
1181 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1182 I(sizeof(((Config *)0)->username)));
1183 }
1184
1185 s = ctrl_getset(b, "Connection", "keepalive",
1186 "Sending of null packets to keep session active");
1187 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1188 HELPCTX(connection_keepalive),
1189 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1190 I(-1));
1191
1192 if (!midsession) {
1193 s = ctrl_getset(b, "Connection", "tcp",
1194 "Low-level TCP connection options");
1195 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)", 'n',
1196 HELPCTX(connection_nodelay),
1197 dlg_stdcheckbox_handler,
1198 I(offsetof(Config,tcp_nodelay)));
1199 }
1200
1201 if (!midsession) {
1202 /*
1203 * The Connection/Proxy panel.
1204 */
1205 ctrl_settitle(b, "Connection/Proxy",
1206 "Options controlling proxy usage");
1207
1208 s = ctrl_getset(b, "Connection/Proxy", "basics", "Proxy basics");
1209 ctrl_radiobuttons(s, "Proxy type:", NO_SHORTCUT, 4,
1210 HELPCTX(proxy_type),
1211 dlg_stdradiobutton_handler,
1212 I(offsetof(Config, proxy_type)),
1213 "None", 'n', I(PROXY_NONE),
1214 "HTTP", 't', I(PROXY_HTTP),
1215 "SOCKS", 's', I(PROXY_SOCKS),
1216 "Telnet", 'l', I(PROXY_TELNET),
1217 NULL);
1218 ctrl_columns(s, 2, 80, 20);
1219 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1220 HELPCTX(proxy_main),
1221 dlg_stdeditbox_handler,
1222 I(offsetof(Config,proxy_host)),
1223 I(sizeof(((Config *)0)->proxy_host)));
1224 c->generic.column = 0;
1225 c = ctrl_editbox(s, "Port", 'p', 100,
1226 HELPCTX(proxy_main),
1227 dlg_stdeditbox_handler,
1228 I(offsetof(Config,proxy_port)),
1229 I(-1));
1230 c->generic.column = 1;
1231 ctrl_columns(s, 1, 100);
1232 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1233 HELPCTX(proxy_exclude),
1234 dlg_stdeditbox_handler,
1235 I(offsetof(Config,proxy_exclude_list)),
1236 I(sizeof(((Config *)0)->proxy_exclude_list)));
1237 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1238 HELPCTX(proxy_exclude),
1239 dlg_stdcheckbox_handler,
1240 I(offsetof(Config,even_proxy_localhost)));
1241 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1242 HELPCTX(proxy_dns),
1243 dlg_stdradiobutton_handler,
1244 I(offsetof(Config, proxy_dns)),
1245 "No", I(FORCE_OFF),
1246 "Auto", I(AUTO),
1247 "Yes", I(FORCE_ON), NULL);
1248 ctrl_editbox(s, "Username", 'u', 60,
1249 HELPCTX(proxy_auth),
1250 dlg_stdeditbox_handler,
1251 I(offsetof(Config,proxy_username)),
1252 I(sizeof(((Config *)0)->proxy_username)));
1253 c = ctrl_editbox(s, "Password", 'w', 60,
1254 HELPCTX(proxy_auth),
1255 dlg_stdeditbox_handler,
1256 I(offsetof(Config,proxy_password)),
1257 I(sizeof(((Config *)0)->proxy_password)));
1258 c->editbox.password = 1;
1259
1260 s = ctrl_getset(b, "Connection/Proxy", "misc",
1261 "Miscellaneous proxy settings");
1262 ctrl_editbox(s, "Telnet command", 'm', 100,
1263 HELPCTX(proxy_command),
1264 dlg_stdeditbox_handler,
1265 I(offsetof(Config,proxy_telnet_command)),
1266 I(sizeof(((Config *)0)->proxy_telnet_command)));
1267 ctrl_radiobuttons(s, "SOCKS Version", 'v', 2,
1268 HELPCTX(proxy_socksver),
1269 dlg_stdradiobutton_handler,
1270 I(offsetof(Config, proxy_socks_version)),
1271 "Version 5", I(5), "Version 4", I(4), NULL);
1272 }
1273
1274 /*
1275 * The Telnet panel exists in the base config box, and in a
1276 * mid-session reconfig box _if_ we're using Telnet.
1277 */
1278 if (!midsession || protocol == PROT_TELNET) {
1279 /*
1280 * The Connection/Telnet panel.
1281 */
1282 ctrl_settitle(b, "Connection/Telnet",
1283 "Options controlling Telnet connections");
1284
1285 if (!midsession) {
1286 s = ctrl_getset(b, "Connection/Telnet", "data",
1287 "Data to send to the server");
1288 ctrl_editbox(s, "Terminal-speed string", 's', 50,
1289 HELPCTX(telnet_termspeed),
1290 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1291 I(sizeof(((Config *)0)->termspeed)));
1292 ctrl_text(s, "Environment variables:", HELPCTX(telnet_environ));
1293 ctrl_columns(s, 2, 80, 20);
1294 ed = (struct environ_data *)
1295 ctrl_alloc(b, sizeof(struct environ_data));
1296 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1297 HELPCTX(telnet_environ),
1298 environ_handler, P(ed), P(NULL));
1299 ed->varbox->generic.column = 0;
1300 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1301 HELPCTX(telnet_environ),
1302 environ_handler, P(ed), P(NULL));
1303 ed->valbox->generic.column = 0;
1304 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1305 HELPCTX(telnet_environ),
1306 environ_handler, P(ed));
1307 ed->addbutton->generic.column = 1;
1308 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1309 HELPCTX(telnet_environ),
1310 environ_handler, P(ed));
1311 ed->rembutton->generic.column = 1;
1312 ctrl_columns(s, 1, 100);
1313 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1314 HELPCTX(telnet_environ),
1315 environ_handler, P(ed));
1316 ed->listbox->listbox.height = 3;
d437fc9d 1317 ed->listbox->listbox.ncols = 2;
1318 ed->listbox->listbox.percentages = smalloc(2*sizeof(int));
1319 ed->listbox->listbox.percentages[0] = 30;
1320 ed->listbox->listbox.percentages[1] = 70;
fe8abbf4 1321 }
1322
1323 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1324 "Telnet protocol adjustments");
1325
1326 if (!midsession) {
1327 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1328 NO_SHORTCUT, 2,
1329 HELPCTX(telnet_oldenviron),
1330 dlg_stdradiobutton_handler,
1331 I(offsetof(Config, rfc_environ)),
1332 "BSD (commonplace)", 'b', I(0),
1333 "RFC 1408 (unusual)", 'f', I(1), NULL);
1334 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1335 HELPCTX(telnet_passive),
1336 dlg_stdradiobutton_handler,
1337 I(offsetof(Config, passive_telnet)),
1338 "Passive", I(1), "Active", I(0), NULL);
1339 }
1340 ctrl_checkbox(s, "Keyboard sends telnet Backspace and Interrupt", 'k',
1341 HELPCTX(telnet_specialkeys),
1342 dlg_stdcheckbox_handler,
1343 I(offsetof(Config,telnet_keyboard)));
1344 ctrl_checkbox(s, "Return key sends telnet New Line instead of ^M",
1345 NO_SHORTCUT, HELPCTX(telnet_newline),
1346 dlg_stdcheckbox_handler,
1347 I(offsetof(Config,telnet_newline)));
1348 }
1349
1350 if (!midsession) {
1351
1352 /*
1353 * The Connection/Rlogin panel.
1354 */
1355 ctrl_settitle(b, "Connection/Rlogin",
1356 "Options controlling Rlogin connections");
1357
1358 s = ctrl_getset(b, "Connection/Rlogin", "data",
1359 "Data to send to the server");
1360 ctrl_editbox(s, "Terminal-speed string", 's', 50,
1361 HELPCTX(rlogin_termspeed),
1362 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1363 I(sizeof(((Config *)0)->termspeed)));
1364 ctrl_editbox(s, "Local username:", 'l', 50,
1365 HELPCTX(rlogin_localuser),
1366 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1367 I(sizeof(((Config *)0)->localusername)));
1368
1369 }
1370
1371 /*
1372 * All the SSH stuff is omitted in PuTTYtel.
1373 */
1374
d9b15094 1375 if (!midsession && backends[3].name != NULL) {
fe8abbf4 1376
1377 /*
1378 * The Connection/SSH panel.
1379 */
1380 ctrl_settitle(b, "Connection/SSH",
1381 "Options controlling SSH connections");
1382
1383 s = ctrl_getset(b, "Connection/SSH", "data",
1384 "Data to send to the server");
1385 ctrl_editbox(s, "Remote command:", 'r', 100,
1386 HELPCTX(ssh_command),
1387 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1388 I(sizeof(((Config *)0)->remote_cmd)));
1389
1390 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1391 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1392 HELPCTX(ssh_nopty),
1393 dlg_stdcheckbox_handler,
1394 I(offsetof(Config,nopty)));
1395 ctrl_checkbox(s, "Enable compression", 'e',
1396 HELPCTX(ssh_compress),
1397 dlg_stdcheckbox_handler,
1398 I(offsetof(Config,compression)));
1399 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1400 HELPCTX(ssh_protocol),
1401 dlg_stdradiobutton_handler,
1402 I(offsetof(Config, sshprot)),
1403 "1 only", 'l', I(0),
1404 "1", '1', I(1),
1405 "2", '2', I(2),
1406 "2 only", 'n', I(3), NULL);
1407
1408 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
bb524800 1409 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1410 HELPCTX(ssh_ciphers),
1411 cipherlist_handler, P(NULL));
1412 c->listbox.height = 6;
1413
fe8abbf4 1414 ctrl_checkbox(s, "Enable non-standard use of single-DES in SSH 2", 'i',
1415 HELPCTX(ssh_ciphers),
1416 dlg_stdcheckbox_handler,
1417 I(offsetof(Config,ssh2_des_cbc)));
1418
1419 /*
1420 * The Connection/SSH/Auth panel.
1421 */
1422 ctrl_settitle(b, "Connection/SSH/Auth",
1423 "Options controlling SSH authentication");
1424
1425 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1426 "Authentication methods");
1427 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH1)", 'm',
1428 HELPCTX(ssh_auth_tis),
1429 dlg_stdcheckbox_handler,
1430 I(offsetof(Config,try_tis_auth)));
1431 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH2)",
1432 'i', HELPCTX(ssh_auth_ki),
1433 dlg_stdcheckbox_handler,
1434 I(offsetof(Config,try_ki_auth)));
1435
1436 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1437 "Authentication parameters");
1438 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1439 HELPCTX(ssh_auth_agentfwd),
1440 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
1441 ctrl_checkbox(s, "Allow attempted changes of username in SSH2", 'u',
1442 HELPCTX(ssh_auth_changeuser),
1443 dlg_stdcheckbox_handler,
1444 I(offsetof(Config,change_username)));
1445 ctrl_filesel(s, "Private key file for authentication:", 'k',
1446 FILTER_KEY_FILES, FALSE, "Select private key file",
1447 HELPCTX(ssh_auth_privkey),
1448 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1449
1450 /*
1451 * The Connection/SSH/Tunnels panel.
1452 */
1453 ctrl_settitle(b, "Connection/SSH/Tunnels",
1454 "Options controlling SSH tunnelling");
1455
1456 s = ctrl_getset(b, "Connection/SSH/Tunnels", "x11", "X11 forwarding");
1457 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1458 HELPCTX(ssh_tunnels_x11),
1459 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1460 ctrl_editbox(s, "X display location", 'x', 50,
1461 HELPCTX(ssh_tunnels_x11),
1462 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1463 I(sizeof(((Config *)0)->x11_display)));
1464 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1465 HELPCTX(ssh_tunnels_x11auth),
1466 dlg_stdradiobutton_handler,
1467 I(offsetof(Config, x11_auth)),
1468 "MIT-Magic-Cookie-1", I(X11_MIT),
1469 "XDM-Authorization-1", I(X11_XDM), NULL);
1470
1471 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1472 "Port forwarding");
1473 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1474 HELPCTX(ssh_tunnels_portfwd_localhost),
1475 dlg_stdcheckbox_handler,
1476 I(offsetof(Config,lport_acceptall)));
1477 ctrl_checkbox(s, "Remote ports do the same (SSH v2 only)", 'p',
1478 HELPCTX(ssh_tunnels_portfwd_localhost),
1479 dlg_stdcheckbox_handler,
1480 I(offsetof(Config,rport_acceptall)));
1481
1482 ctrl_columns(s, 3, 55, 20, 25);
1483 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1484 c->generic.column = COLUMN_FIELD(0,2);
1485 /* You want to select from the list, _then_ hit Remove. So tab order
1486 * should be that way round. */
1487 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1488 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1489 HELPCTX(ssh_tunnels_portfwd),
1490 portfwd_handler, P(pfd));
1491 pfd->rembutton->generic.column = 2;
1492 pfd->rembutton->generic.tabdelay = 1;
1493 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1494 HELPCTX(ssh_tunnels_portfwd),
1495 portfwd_handler, P(pfd));
1496 pfd->listbox->listbox.height = 3;
37dbf11c 1497 pfd->listbox->listbox.ncols = 2;
1498 pfd->listbox->listbox.percentages = smalloc(2*sizeof(int));
1499 pfd->listbox->listbox.percentages[0] = 20;
1500 pfd->listbox->listbox.percentages[1] = 80;
fe8abbf4 1501 ctrl_tabdelay(s, pfd->rembutton);
1502 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
1503 /* You want to enter source, destination and type, _then_ hit Add.
1504 * Again, we adjust the tab order to reflect this. */
1505 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
1506 HELPCTX(ssh_tunnels_portfwd),
1507 portfwd_handler, P(pfd));
1508 pfd->addbutton->generic.column = 2;
1509 pfd->addbutton->generic.tabdelay = 1;
1510 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
1511 HELPCTX(ssh_tunnels_portfwd),
1512 portfwd_handler, P(pfd), P(NULL));
1513 pfd->sourcebox->generic.column = 0;
1514 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
1515 HELPCTX(ssh_tunnels_portfwd),
1516 portfwd_handler, P(pfd), P(NULL));
1517 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2,
1518 HELPCTX(ssh_tunnels_portfwd),
1519 portfwd_handler, P(pfd),
1520 "Local", 'l', P(NULL),
1521 "Remote", 'm', P(NULL), NULL);
1522 ctrl_tabdelay(s, pfd->addbutton);
1523 ctrl_columns(s, 1, 100);
1524
1525 /*
1526 * The Connection/SSH/Bugs panel.
1527 */
1528 ctrl_settitle(b, "Connection/SSH/Bugs",
1529 "Workarounds for SSH server bugs");
1530
1531 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
1532 "Detection of known bugs in SSH servers");
1533 ctrl_droplist(s, "Chokes on SSH1 ignore messages", 'i', 20,
1534 HELPCTX(ssh_bugs_ignore1),
1535 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
1536 ctrl_droplist(s, "Refuses all SSH1 password camouflage", 's', 20,
1537 HELPCTX(ssh_bugs_plainpw1),
1538 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
1539 ctrl_droplist(s, "Chokes on SSH1 RSA authentication", 'r', 20,
1540 HELPCTX(ssh_bugs_rsa1),
1541 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
1542 ctrl_droplist(s, "Miscomputes SSH2 HMAC keys", 'm', 20,
1543 HELPCTX(ssh_bugs_hmac2),
1544 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
1545 ctrl_droplist(s, "Miscomputes SSH2 encryption keys", 'e', 20,
1546 HELPCTX(ssh_bugs_derivekey2),
1547 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
1548 ctrl_droplist(s, "Requires padding on SSH2 RSA signatures", 'p', 20,
1549 HELPCTX(ssh_bugs_rsapad2),
1550 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
1551 ctrl_droplist(s, "Chokes on Diffie-Hellman group exchange", 'd', 20,
1552 HELPCTX(ssh_bugs_dhgex2),
1553 sshbug_handler, I(offsetof(Config,sshbug_dhgex2)));
1554 ctrl_droplist(s, "Misuses the session ID in PK auth", 'n', 20,
1555 HELPCTX(ssh_bugs_pksessid2),
1556 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
1557 }
1558}