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