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