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