#define PRINTER_DISABLED_STRING "None (printing disabled)"
-static void protocolbuttons_handler(union control *ctrl, void *dlg,
+#define HOST_BOX_TITLE "Host Name (or IP address)"
+#define PORT_BOX_TITLE "Port"
+
+static void config_host_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ Config *cfg = (Config *)data;
+
+ /*
+ * This function works just like the standard edit box handler,
+ * only it has to choose the control's label and text from two
+ * different places depending on the protocol.
+ */
+ if (event == EVENT_REFRESH) {
+ if (cfg->protocol == PROT_SERIAL) {
+ /*
+ * This label text is carefully chosen to contain an n,
+ * since that's the shortcut for the host name control.
+ */
+ dlg_label_change(ctrl, dlg, "Serial line");
+ dlg_editbox_set(ctrl, dlg, cfg->serline);
+ } else {
+ dlg_label_change(ctrl, dlg, HOST_BOX_TITLE);
+ dlg_editbox_set(ctrl, dlg, cfg->host);
+ }
+ } else if (event == EVENT_VALCHANGE) {
+ if (cfg->protocol == PROT_SERIAL)
+ dlg_editbox_get(ctrl, dlg, cfg->serline, lenof(cfg->serline));
+ else
+ dlg_editbox_get(ctrl, dlg, cfg->host, lenof(cfg->host));
+ }
+}
+
+static void config_port_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ Config *cfg = (Config *)data;
+ char buf[80];
+
+ /*
+ * This function works just like the standard edit box handler,
+ * only it has to choose the control's label and text from two
+ * different places depending on the protocol.
+ */
+ if (event == EVENT_REFRESH) {
+ if (cfg->protocol == PROT_SERIAL) {
+ /*
+ * This label text is carefully chosen to contain a p,
+ * since that's the shortcut for the port control.
+ */
+ dlg_label_change(ctrl, dlg, "Speed");
+ sprintf(buf, "%d", cfg->serspeed);
+ } else {
+ dlg_label_change(ctrl, dlg, PORT_BOX_TITLE);
+ sprintf(buf, "%d", cfg->port);
+ }
+ dlg_editbox_set(ctrl, dlg, buf);
+ } else if (event == EVENT_VALCHANGE) {
+ dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
+ if (cfg->protocol == PROT_SERIAL)
+ cfg->serspeed = atoi(buf);
+ else
+ cfg->port = atoi(buf);
+ }
+}
+
+struct hostport {
+ union control *host, *port;
+};
+
+/*
+ * We export this function so that platform-specific config
+ * routines can use it to conveniently identify the protocol radio
+ * buttons in order to add to them.
+ */
+void config_protocolbuttons_handler(union control *ctrl, void *dlg,
void *data, int event)
{
- int button, defport;
+ int button;
Config *cfg = (Config *)data;
+ struct hostport *hp = (struct hostport *)ctrl->radio.context.p;
+
/*
* This function works just like the standard radio-button
* handler, except that it also has to change the setting of
- * the port box. We expect the context parameter to point at
- * the `union control' structure for the port box.
+ * the port box, and refresh both host and port boxes when. We
+ * expect the context parameter to point at a hostport
+ * structure giving the `union control's for both.
*/
if (event == EVENT_REFRESH) {
for (button = 0; button < ctrl->radio.nbuttons; button++)
assert(button >= 0 && button < ctrl->radio.nbuttons);
cfg->protocol = ctrl->radio.buttondata[button].i;
if (oldproto != cfg->protocol) {
- defport = -1;
- switch (cfg->protocol) {
- case PROT_SSH: defport = 22; break;
- case PROT_TELNET: defport = 23; break;
- case PROT_RLOGIN: defport = 513; break;
- }
- if (defport > 0 && cfg->port != defport) {
- cfg->port = defport;
- dlg_refresh((union control *)ctrl->radio.context.p, dlg);
- }
+ Backend *ob = backend_from_proto(oldproto);
+ Backend *nb = backend_from_proto(cfg->protocol);
+ assert(ob);
+ assert(nb);
+ /* Iff the user hasn't changed the port from the protocol
+ * default (if any), update it with the new protocol's
+ * default.
+ * (XXX: this isn't perfect; a default can become permanent
+ * by going via the serial backend. However, it helps with
+ * the common case of tabbing through the controls in order
+ * and setting a non-default port.) */
+ if (cfg->port == ob->default_port &&
+ cfg->port > 0 && nb->default_port > 0)
+ cfg->port = nb->default_port;
}
+ dlg_refresh(hp->host, dlg);
+ dlg_refresh(hp->port, dlg);
}
}
}
}
+#ifndef NO_GSSAPI
+static void gsslist_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ Config *cfg = (Config *)data;
+ if (event == EVENT_REFRESH) {
+ int i;
+
+ dlg_update_start(ctrl, dlg);
+ dlg_listbox_clear(ctrl, dlg);
+ for (i = 0; i < ngsslibs; i++) {
+ int id = cfg->ssh_gsslist[i];
+ assert(id >= 0 && id < ngsslibs);
+ dlg_listbox_addwithid(ctrl, dlg, gsslibnames[id], id);
+ }
+ dlg_update_done(ctrl, dlg);
+
+ } else if (event == EVENT_VALCHANGE) {
+ int i;
+
+ /* Update array to match the list box. */
+ for (i=0; i < ngsslibs; i++)
+ cfg->ssh_gsslist[i] = dlg_listbox_getid(ctrl, dlg, i);
+ }
+}
+#endif
+
static void kexlist_handler(union control *ctrl, void *dlg,
void *data, int event)
{
{ "Diffie-Hellman group 1", KEX_DHGROUP1 },
{ "Diffie-Hellman group 14", KEX_DHGROUP14 },
{ "Diffie-Hellman group exchange", KEX_DHGEX },
+ { "RSA-based key exchange", KEX_RSA },
{ "-- warn below here --", KEX_WARN }
};
Config *cfg = (Config *)data;
if (event == EVENT_REFRESH) {
int i;
- const char *cp;
+ const char *cp, *thiscp;
dlg_update_start(ctrl, dlg);
- strcpy(cfg->line_codepage,
- cp_name(decode_codepage(cfg->line_codepage)));
+ thiscp = cp_name(decode_codepage(cfg->line_codepage));
dlg_listbox_clear(ctrl, dlg);
for (i = 0; (cp = cp_enumerate(i)) != NULL; i++)
dlg_listbox_add(ctrl, dlg, cp);
- dlg_editbox_set(ctrl, dlg, cfg->line_codepage);
+ dlg_editbox_set(ctrl, dlg, thiscp);
+ strcpy(cfg->line_codepage, thiscp);
dlg_update_done(ctrl, dlg);
} else if (event == EVENT_VALCHANGE) {
dlg_editbox_get(ctrl, dlg, cfg->line_codepage,
*/
static int load_selected_session(struct sessionsaver_data *ssd,
char *savedsession,
- void *dlg, Config *cfg)
+ void *dlg, Config *cfg, int *maybe_launch)
{
int i = dlg_listbox_index(ssd->listbox, dlg);
int isdef;
return 0;
}
isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
- load_settings(ssd->sesslist.sessions[i], !isdef, cfg);
+ load_settings(ssd->sesslist.sessions[i], cfg);
if (!isdef) {
strncpy(savedsession, ssd->sesslist.sessions[i],
SAVEDSESSION_LEN);
savedsession[SAVEDSESSION_LEN-1] = '\0';
+ if (maybe_launch)
+ *maybe_launch = TRUE;
} else {
savedsession[0] = '\0';
+ if (maybe_launch)
+ *maybe_launch = FALSE;
}
dlg_refresh(NULL, dlg);
/* Restore the selection, which might have been clobbered by
dlg_listbox_select(ssd->listbox, dlg, top);
}
} else if (event == EVENT_ACTION) {
+ int mbl = FALSE;
if (!ssd->midsession &&
(ctrl == ssd->listbox ||
(ssd->loadbutton && ctrl == ssd->loadbutton))) {
* double-click on the list box _and_ that session
* contains a hostname.
*/
- if (load_selected_session(ssd, savedsession, dlg, cfg) &&
- (ctrl == ssd->listbox && cfg->host[0])) {
+ if (load_selected_session(ssd, savedsession, dlg, cfg, &mbl) &&
+ (mbl && ctrl == ssd->listbox && cfg_launchable(cfg))) {
dlg_end(dlg, 1); /* it's all over, and succeeded */
}
} else if (ctrl == ssd->savebutton) {
}
}
{
- char *errmsg = save_settings(savedsession, !isdef, cfg);
+ char *errmsg = save_settings(savedsession, cfg);
if (errmsg) {
dlg_error_msg(dlg, errmsg);
sfree(errmsg);
* there was a session selected in that which had a
* valid host name in it, then load it and go.
*/
- if (dlg_last_focused(ctrl, dlg) == ssd->listbox && !*cfg->host) {
+ if (dlg_last_focused(ctrl, dlg) == ssd->listbox &&
+ !cfg_launchable(cfg)) {
Config cfg2;
- if (!load_selected_session(ssd, savedsession, dlg, &cfg2)) {
+ int mbl = FALSE;
+ if (!load_selected_session(ssd, savedsession, dlg,
+ &cfg2, &mbl)) {
dlg_beep(dlg);
return;
}
/* If at this point we have a valid session, go! */
- if (*cfg2.host) {
+ if (mbl && cfg_launchable(&cfg2)) {
*cfg = cfg2; /* structure copy */
cfg->remote_cmd_ptr = NULL;
dlg_end(dlg, 1);
* Otherwise, do the normal thing: if we have a valid
* session, get going.
*/
- if (*cfg->host) {
+ if (cfg_launchable(cfg)) {
dlg_end(dlg, 1);
} else
dlg_beep(dlg);
Config *cfg = (Config *)data;
struct colour_data *cd =
(struct colour_data *)ctrl->generic.context.p;
- int update = FALSE, r, g, b;
+ int update = FALSE, clear = FALSE, r, g, b;
if (event == EVENT_REFRESH) {
if (ctrl == cd->listbox) {
for (i = 0; i < lenof(colours); i++)
dlg_listbox_add(ctrl, dlg, colours[i]);
dlg_update_done(ctrl, dlg);
- dlg_editbox_set(cd->redit, dlg, "");
- dlg_editbox_set(cd->gedit, dlg, "");
- dlg_editbox_set(cd->bedit, dlg, "");
+ clear = TRUE;
+ update = TRUE;
}
} else if (event == EVENT_SELCHANGE) {
if (ctrl == cd->listbox) {
/* The user has selected a colour. Update the RGB text. */
int i = dlg_listbox_index(ctrl, dlg);
if (i < 0) {
- dlg_beep(dlg);
- return;
+ clear = TRUE;
+ } else {
+ clear = FALSE;
+ r = cfg->colours[i][0];
+ g = cfg->colours[i][1];
+ b = cfg->colours[i][2];
}
- r = cfg->colours[i][0];
- g = cfg->colours[i][1];
- b = cfg->colours[i][2];
update = TRUE;
}
} else if (event == EVENT_VALCHANGE) {
int i, cval;
dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
- cval = atoi(buf) & 255;
+ cval = atoi(buf);
+ if (cval > 255) cval = 255;
+ if (cval < 0) cval = 0;
i = dlg_listbox_index(cd->listbox, dlg);
if (i >= 0) {
cfg->colours[i][0] = r;
cfg->colours[i][1] = g;
cfg->colours[i][2] = b;
+ clear = FALSE;
update = TRUE;
}
}
}
if (update) {
- char buf[40];
- sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
- sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
- sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
+ if (clear) {
+ dlg_editbox_set(cd->redit, dlg, "");
+ dlg_editbox_set(cd->gedit, dlg, "");
+ dlg_editbox_set(cd->bedit, dlg, "");
+ } else {
+ char buf[40];
+ sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
+ sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
+ sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
+ }
}
}
char *p = cfg->ttymodes;
int i = 0, len = lenof(cfg->ttymodes);
while (*p) {
+ int multisel = dlg_listbox_index(td->listbox, dlg) < 0;
if (dlg_listbox_issel(td->listbox, dlg, i)) {
+ if (!multisel) {
+ /* Populate controls with entry we're about to
+ * delete, for ease of editing.
+ * (If multiple entries were selected, don't
+ * touch the controls.) */
+ char *val = strchr(p, '\t');
+ if (val) {
+ int ind = 0;
+ val++;
+ while (ttymodes[ind]) {
+ if (strlen(ttymodes[ind]) == val-p-1 &&
+ !strncmp(ttymodes[ind], p, val-p-1))
+ break;
+ ind++;
+ }
+ dlg_listbox_select(td->modelist, dlg, ind);
+ dlg_radiobutton_set(td->valradio, dlg,
+ (*val == 'V'));
+ dlg_editbox_set(td->valbox, dlg, val+1);
+ }
+ }
memmove(p, p+strlen(p)+1, len - (strlen(p)+1));
i++;
continue;
if (i < 0) {
dlg_beep(dlg);
} else {
- char *p, *q;
+ char *p, *q, *str;
dlg_listbox_del(ed->listbox, dlg, i);
p = cfg->environmt;
q = p;
if (!*p)
goto disaster;
- while (*p)
- p++;
+ /* Populate controls with the entry we're about to delete
+ * for ease of editing */
+ str = p;
+ p = strchr(p, '\t');
+ if (!p)
+ goto disaster;
+ *p = '\0';
+ dlg_editbox_set(ed->varbox, dlg, str);
+ p++;
+ str = p;
+ dlg_editbox_set(ed->valbox, dlg, str);
+ p = strchr(p, '\0');
+ if (!p)
+ goto disaster;
p++;
while (*p) {
while (*p)
*p = '\0';
p = cfg->portfwd;
while (*p) {
+ if (strcmp(p,str) == 0) {
+ dlg_error_msg(dlg, "Specified forwarding already exists");
+ break;
+ }
while (*p)
p++;
p++;
}
- if ((p - cfg->portfwd) + strlen(str) + 2 <=
- sizeof(cfg->portfwd)) {
- strcpy(p, str);
- p[strlen(str) + 1] = '\0';
- dlg_listbox_add(pfd->listbox, dlg, str);
- dlg_editbox_set(pfd->sourcebox, dlg, "");
- dlg_editbox_set(pfd->destbox, dlg, "");
- } else {
- dlg_error_msg(dlg, "Too many forwardings");
+ if (!*p) {
+ if ((p - cfg->portfwd) + strlen(str) + 2 <=
+ sizeof(cfg->portfwd)) {
+ strcpy(p, str);
+ p[strlen(str) + 1] = '\0';
+ dlg_listbox_add(pfd->listbox, dlg, str);
+ dlg_editbox_set(pfd->sourcebox, dlg, "");
+ dlg_editbox_set(pfd->destbox, dlg, "");
+ } else {
+ dlg_error_msg(dlg, "Too many forwardings");
+ }
}
} else if (ctrl == pfd->rembutton) {
int i = dlg_listbox_index(pfd->listbox, dlg);
if (i < 0)
dlg_beep(dlg);
else {
- char *p, *q;
+ char *p, *q, *src, *dst;
+ char dir;
dlg_listbox_del(pfd->listbox, dlg, i);
p = cfg->portfwd;
q = p;
if (!*p)
goto disaster2;
- while (*p)
+ /* Populate the controls with the entry we're about to
+ * delete, for ease of editing. */
+ {
+ static const char *const afs = "A46";
+ char *afp = strchr(afs, *p);
+#ifndef NO_IPV6
+ int idx = afp ? afp-afs : 0;
+#endif
+ if (afp)
+ p++;
+#ifndef NO_IPV6
+ dlg_radiobutton_set(pfd->addressfamily, dlg, idx);
+#endif
+ }
+ {
+ static const char *const dirs = "LRD";
+ dir = *p;
+ dlg_radiobutton_set(pfd->direction, dlg,
+ strchr(dirs, dir) - dirs);
+ }
+ p++;
+ if (dir != 'D') {
+ src = p;
+ p = strchr(p, '\t');
+ if (!p)
+ goto disaster2;
+ *p = '\0';
p++;
+ dst = p;
+ } else {
+ src = p;
+ dst = "";
+ }
+ p = strchr(p, '\0');
+ if (!p)
+ goto disaster2;
+ dlg_editbox_set(pfd->sourcebox, dlg, src);
+ dlg_editbox_set(pfd->destbox, dlg, dst);
p++;
while (*p) {
while (*p)
sfree(str);
if (!midsession) {
+ struct hostport *hp = (struct hostport *)
+ ctrl_alloc(b, sizeof(struct hostport));
+
s = ctrl_getset(b, "Session", "hostport",
- "Specify your connection by host name or IP address");
+ "Specify the destination you want to connect to");
ctrl_columns(s, 2, 75, 25);
- c = ctrl_editbox(s, "Host Name (or IP address)", 'n', 100,
+ c = ctrl_editbox(s, HOST_BOX_TITLE, 'n', 100,
HELPCTX(session_hostname),
- dlg_stdeditbox_handler, I(offsetof(Config,host)),
- I(sizeof(((Config *)0)->host)));
+ config_host_handler, I(0), I(0));
c->generic.column = 0;
- c = ctrl_editbox(s, "Port", 'p', 100, HELPCTX(session_hostname),
- dlg_stdeditbox_handler,
- I(offsetof(Config,port)), I(-1));
+ hp->host = c;
+ c = ctrl_editbox(s, PORT_BOX_TITLE, 'p', 100,
+ HELPCTX(session_hostname),
+ config_port_handler, I(0), I(0));
c->generic.column = 1;
+ hp->port = c;
ctrl_columns(s, 1, 100);
- if (backends[3].name == NULL) {
- ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 3,
+
+ if (!backend_from_proto(PROT_SSH)) {
+ ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 3,
HELPCTX(session_hostname),
- protocolbuttons_handler, P(c),
- "Raw", 'r', I(PROT_RAW),
+ config_protocolbuttons_handler, P(hp),
+ "Raw", 'w', I(PROT_RAW),
"Telnet", 't', I(PROT_TELNET),
"Rlogin", 'i', I(PROT_RLOGIN),
NULL);
} else {
- ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 4,
+ ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 4,
HELPCTX(session_hostname),
- protocolbuttons_handler, P(c),
- "Raw", 'r', I(PROT_RAW),
+ config_protocolbuttons_handler, P(hp),
+ "Raw", 'w', I(PROT_RAW),
"Telnet", 't', I(PROT_TELNET),
"Rlogin", 'i', I(PROT_RLOGIN),
"SSH", 's', I(PROT_SSH),
ctrl_columns(s, 1, 100);
s = ctrl_getset(b, "Session", "otheropts", NULL);
- c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
+ c = ctrl_radiobuttons(s, "Close window on exit:", 'x', 4,
HELPCTX(session_coe),
dlg_stdradiobutton_handler,
I(offsetof(Config, close_on_exit)),
* logging can sensibly be available.
*/
{
- char *sshlogname;
+ char *sshlogname, *sshrawlogname;
if ((midsession && protocol == PROT_SSH) ||
- (!midsession && backends[3].name != NULL))
- sshlogname = "Log SSH packet data";
- else
- sshlogname = NULL; /* this will disable the button */
- ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 1,
+ (!midsession && backend_from_proto(PROT_SSH))) {
+ sshlogname = "SSH packets";
+ sshrawlogname = "SSH packets and raw data";
+ } else {
+ sshlogname = NULL; /* this will disable both buttons */
+ sshrawlogname = NULL; /* this will just placate optimisers */
+ }
+ ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 2,
HELPCTX(logging_main),
loggingbuttons_handler,
I(offsetof(Config, logtype)),
- "Logging turned off completely", 't', I(LGTYP_NONE),
- "Log printable output only", 'p', I(LGTYP_ASCII),
- "Log all session output", 'l', I(LGTYP_DEBUG),
+ "None", 't', I(LGTYP_NONE),
+ "Printable output", 'p', I(LGTYP_ASCII),
+ "All session output", 'l', I(LGTYP_DEBUG),
sshlogname, 's', I(LGTYP_PACKETS),
+ sshrawlogname, 'r', I(LGTYP_SSHRAW),
NULL);
}
ctrl_filesel(s, "Log file name:", 'f',
dlg_stdcheckbox_handler, I(offsetof(Config,logflush)));
if ((midsession && protocol == PROT_SSH) ||
- (!midsession && backends[3].name != NULL)) {
+ (!midsession && backend_from_proto(PROT_SSH))) {
s = ctrl_getset(b, "Session/Logging", "ssh",
"Options specific to SSH packet logging");
ctrl_checkbox(s, "Omit known password fields", 'k',
ctrl_checkbox(s, "Implicit CR in every LF", 'r',
HELPCTX(terminal_lfhascr),
dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
+ ctrl_checkbox(s, "Implicit LF in every CR", 'f',
+ HELPCTX(terminal_crhaslf),
+ dlg_stdcheckbox_handler, I(offsetof(Config,crhaslf)));
ctrl_checkbox(s, "Use background colour to erase screen", 'e',
HELPCTX(terminal_bce),
dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
HELPCTX(features_retitle),
dlg_stdcheckbox_handler,
I(offsetof(Config,no_remote_wintitle)));
- ctrl_checkbox(s, "Disable remote window title querying (SECURITY)",
- 'q', HELPCTX(features_qtitle), dlg_stdcheckbox_handler,
- I(offsetof(Config,no_remote_qtitle)));
+ ctrl_radiobuttons(s, "Response to remote title query (SECURITY):", 'q', 3,
+ HELPCTX(features_qtitle),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config,remote_qtitle_action)),
+ "None", I(TITLE_NONE),
+ "Empty string", I(TITLE_EMPTY),
+ "Window title", I(TITLE_REAL), NULL);
ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
HELPCTX(features_dbackspace),
dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
s = ctrl_getset(b, "Window", "size", "Set the size of the window");
ctrl_columns(s, 2, 50, 50);
- c = ctrl_editbox(s, "Rows", 'r', 100,
- HELPCTX(window_size),
- dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
- c->generic.column = 0;
c = ctrl_editbox(s, "Columns", 'm', 100,
HELPCTX(window_size),
dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
+ c->generic.column = 0;
+ c = ctrl_editbox(s, "Rows", 'r', 100,
+ HELPCTX(window_size),
+ dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
c->generic.column = 1;
ctrl_columns(s, 1, 100);
"Options controlling character set translation");
s = ctrl_getset(b, "Window/Translation", "trans",
- "Character set translation on received data");
- ctrl_combobox(s, "Received data assumed to be in which character set:",
+ "Character set translation");
+ ctrl_combobox(s, "Remote character set:",
'r', 100, HELPCTX(translation_codepage),
codepage_handler, P(NULL), P(NULL));
"IPv6", '6', I(ADDRTYPE_IPV6),
NULL);
#endif
+
+ {
+ char *label = backend_from_proto(PROT_SSH) ?
+ "Logical name of remote host (e.g. for SSH key lookup):" :
+ "Logical name of remote host:";
+ s = ctrl_getset(b, "Connection", "identity",
+ "Logical name of remote host");
+ ctrl_editbox(s, label, 'm', 100,
+ HELPCTX(connection_loghost),
+ dlg_stdeditbox_handler, I(offsetof(Config,loghost)),
+ I(sizeof(((Config *)0)->loghost)));
+ }
}
/*
HELPCTX(connection_username),
dlg_stdeditbox_handler, I(offsetof(Config,username)),
I(sizeof(((Config *)0)->username)));
+ {
+ /* We assume the local username is sufficiently stable
+ * to include on the dialog box. */
+ char *user = get_username();
+ char *userlabel = dupprintf("Use system username (%s)",
+ user ? user : "");
+ sfree(user);
+ ctrl_radiobuttons(s, "When username is not specified:", 'n', 4,
+ HELPCTX(connection_username_from_env),
+ dlg_stdradiobutton_handler,
+ I(offsetof(Config, username_from_env)),
+ "Prompt", I(FALSE),
+ userlabel, I(TRUE),
+ NULL);
+ sfree(userlabel);
+ }
s = ctrl_getset(b, "Connection/Data", "term",
"Terminal details");
* when we're not doing SSH.
*/
- if (backends[3].name != NULL && (!midsession || protocol == PROT_SSH)) {
+ if (backend_from_proto(PROT_SSH) && (!midsession || protocol == PROT_SSH)) {
/*
* The Connection/SSH panel.
ctrl_checkbox(s, "Allow agent forwarding", 'f',
HELPCTX(ssh_auth_agentfwd),
dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
- ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", 'u',
+ ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", NO_SHORTCUT,
HELPCTX(ssh_auth_changeuser),
dlg_stdcheckbox_handler,
I(offsetof(Config,change_username)));
FILTER_KEY_FILES, FALSE, "Select private key file",
HELPCTX(ssh_auth_privkey),
dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
+
+#ifndef NO_GSSAPI
+ /*
+ * Connection/SSH/Auth/GSSAPI, which sadly won't fit on
+ * the main Auth panel.
+ */
+ ctrl_settitle(b, "Connection/SSH/Auth/GSSAPI",
+ "Options controlling GSSAPI authentication");
+ s = ctrl_getset(b, "Connection/SSH/Auth/GSSAPI", "gssapi", NULL);
+
+ ctrl_checkbox(s, "Attempt GSSAPI authentication (SSH-2 only)",
+ NO_SHORTCUT, HELPCTX(ssh_gssapi),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,try_gssapi_auth)));
+
+ ctrl_checkbox(s, "Allow GSSAPI credential delegation", NO_SHORTCUT,
+ HELPCTX(ssh_gssapi_delegation),
+ dlg_stdcheckbox_handler,
+ I(offsetof(Config,gssapifwd)));
+
+ /*
+ * GSSAPI library selection.
+ */
+ if (ngsslibs > 1) {
+ c = ctrl_draglist(s, "Preference order for GSSAPI libraries:", NO_SHORTCUT,
+ HELPCTX(ssh_gssapi_libraries),
+ gsslist_handler, P(NULL));
+ c->listbox.height = ngsslibs;
+
+ /*
+ * I currently assume that if more than one GSS
+ * library option is available, then one of them is
+ * 'user-supplied' and so we should present the
+ * following file selector. This is at least half-
+ * reasonable, because if we're using statically
+ * linked GSSAPI then there will only be one option
+ * and no way to load from a user-supplied library,
+ * whereas if we're using dynamic libraries then
+ * there will almost certainly be some default
+ * option in addition to a user-supplied path. If
+ * anyone ever ports PuTTY to a system on which
+ * dynamic-library GSSAPI is available but there is
+ * absolutely no consensus on where to keep the
+ * libraries, there'll need to be a flag alongside
+ * ngsslibs to control whether the file selector is
+ * displayed.
+ */
+
+ ctrl_filesel(s, "User-supplied GSSAPI library path:", 'l',
+ FILTER_DYNLIB_FILES, FALSE, "Select library file",
+ HELPCTX(ssh_gssapi_libraries),
+ dlg_stdfilesel_handler,
+ I(offsetof(Config, ssh_gss_custom)));
+ }
+#endif
}
if (!midsession) {
ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
HELPCTX(ssh_bugs_rsa1),
sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
+ ctrl_droplist(s, "Chokes on SSH-2 ignore messages", '2', 20,
+ HELPCTX(ssh_bugs_ignore2),
+ sshbug_handler, I(offsetof(Config,sshbug_ignore2)));
ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
HELPCTX(ssh_bugs_hmac2),
sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
HELPCTX(ssh_bugs_rekey2),
sshbug_handler, I(offsetof(Config,sshbug_rekey2)));
+ ctrl_droplist(s, "Ignores SSH-2 maximum packet size", 'x', 20,
+ HELPCTX(ssh_bugs_maxpkt2),
+ sshbug_handler, I(offsetof(Config,sshbug_maxpkt2)));
}
}
}