📄 config.c
字号:
/*
* config.c - the platform-independent parts of the PuTTY
* configuration box.
*/
#include <assert.h>
#include <stdlib.h>
#include "putty.h"
#include "dialog.h"
#include "storage.h"
#define PRINTER_DISABLED_STRING "None (printing disabled)"
#define HOST_BOX_TITLE "Host Name (or IP address)"
#define PORT_BOX_TITLE "Port"
/*
* Convenience function: determine whether this binary supports a
* given backend.
*/
static int have_backend(int protocol)
{
struct backend_list *p = backends;
for (p = backends; p->name; p++) {
if (p->protocol == protocol)
return 1;
}
return 0;
}
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;
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, 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++)
if (cfg->protocol == ctrl->radio.buttondata[button].i)
break;
/* We expected that `break' to happen, in all circumstances. */
assert(button < ctrl->radio.nbuttons);
dlg_radiobutton_set(ctrl, dlg, button);
} else if (event == EVENT_VALCHANGE) {
int oldproto = cfg->protocol;
button = dlg_radiobutton_get(ctrl, dlg);
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(hp->host, dlg);
dlg_refresh(hp->port, dlg);
}
}
static void loggingbuttons_handler(union control *ctrl, void *dlg,
void *data, int event)
{
int button;
Config *cfg = (Config *)data;
/* This function works just like the standard radio-button handler,
* but it has to fall back to "no logging" in situations where the
* configured logging type isn't applicable.
*/
if (event == EVENT_REFRESH) {
for (button = 0; button < ctrl->radio.nbuttons; button++)
if (cfg->logtype == ctrl->radio.buttondata[button].i)
break;
/* We fell off the end, so we lack the configured logging type */
if (button == ctrl->radio.nbuttons) {
button=0;
cfg->logtype=LGTYP_NONE;
}
dlg_radiobutton_set(ctrl, dlg, button);
} else if (event == EVENT_VALCHANGE) {
button = dlg_radiobutton_get(ctrl, dlg);
assert(button >= 0 && button < ctrl->radio.nbuttons);
cfg->logtype = ctrl->radio.buttondata[button].i;
}
}
static void numeric_keypad_handler(union control *ctrl, void *dlg,
void *data, int event)
{
int button;
Config *cfg = (Config *)data;
/*
* This function works much like the standard radio button
* handler, but it has to handle two fields in Config.
*/
if (event == EVENT_REFRESH) {
if (cfg->nethack_keypad)
button = 2;
else if (cfg->app_keypad)
button = 1;
else
button = 0;
assert(button < ctrl->radio.nbuttons);
dlg_radiobutton_set(ctrl, dlg, button);
} else if (event == EVENT_VALCHANGE) {
button = dlg_radiobutton_get(ctrl, dlg);
assert(button >= 0 && button < ctrl->radio.nbuttons);
if (button == 2) {
cfg->app_keypad = FALSE;
cfg->nethack_keypad = TRUE;
} else {
cfg->app_keypad = (button != 0);
cfg->nethack_keypad = FALSE;
}
}
}
static void cipherlist_handler(union control *ctrl, void *dlg,
void *data, int event)
{
Config *cfg = (Config *)data;
if (event == EVENT_REFRESH) {
int i;
static const struct { char *s; int c; } ciphers[] = {
{ "3DES", CIPHER_3DES },
{ "Blowfish", CIPHER_BLOWFISH },
{ "DES", CIPHER_DES },
{ "AES (SSH-2 only)", CIPHER_AES },
{ "Arcfour (SSH-2 only)", CIPHER_ARCFOUR },
{ "-- warn below here --", CIPHER_WARN }
};
/* Set up the "selected ciphers" box. */
/* (cipherlist assumed to contain all ciphers) */
dlg_update_start(ctrl, dlg);
dlg_listbox_clear(ctrl, dlg);
for (i = 0; i < CIPHER_MAX; i++) {
int c = cfg->ssh_cipherlist[i];
int j;
char *cstr = NULL;
for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
if (ciphers[j].c == c) {
cstr = ciphers[j].s;
break;
}
}
dlg_listbox_addwithid(ctrl, dlg, cstr, c);
}
dlg_update_done(ctrl, dlg);
} else if (event == EVENT_VALCHANGE) {
int i;
/* Update array to match the list box. */
for (i=0; i < CIPHER_MAX; i++)
cfg->ssh_cipherlist[i] = dlg_listbox_getid(ctrl, dlg, i);
}
}
static void kexlist_handler(union control *ctrl, void *dlg,
void *data, int event)
{
Config *cfg = (Config *)data;
if (event == EVENT_REFRESH) {
int i;
static const struct { char *s; int k; } kexes[] = {
{ "Diffie-Hellman group 1", KEX_DHGROUP1 },
{ "Diffie-Hellman group 14", KEX_DHGROUP14 },
{ "Diffie-Hellman group exchange", KEX_DHGEX },
{ "-- warn below here --", KEX_WARN }
};
/* Set up the "kex preference" box. */
/* (kexlist assumed to contain all algorithms) */
dlg_update_start(ctrl, dlg);
dlg_listbox_clear(ctrl, dlg);
for (i = 0; i < KEX_MAX; i++) {
int k = cfg->ssh_kexlist[i];
int j;
char *kstr = NULL;
for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) {
if (kexes[j].k == k) {
kstr = kexes[j].s;
break;
}
}
dlg_listbox_addwithid(ctrl, dlg, kstr, k);
}
dlg_update_done(ctrl, dlg);
} else if (event == EVENT_VALCHANGE) {
int i;
/* Update array to match the list box. */
for (i=0; i < KEX_MAX; i++)
cfg->ssh_kexlist[i] = dlg_listbox_getid(ctrl, dlg, i);
}
}
static void printerbox_handler(union control *ctrl, void *dlg,
void *data, int event)
{
Config *cfg = (Config *)data;
if (event == EVENT_REFRESH) {
int nprinters, i;
printer_enum *pe;
dlg_update_start(ctrl, dlg);
/*
* Some backends may wish to disable the drop-down list on
* this edit box. Be prepared for this.
*/
if (ctrl->editbox.has_list) {
dlg_listbox_clear(ctrl, dlg);
dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING);
pe = printer_start_enum(&nprinters);
for (i = 0; i < nprinters; i++)
dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i));
printer_finish_enum(pe);
}
dlg_editbox_set(ctrl, dlg,
(*cfg->printer ? cfg->printer :
PRINTER_DISABLED_STRING));
dlg_update_done(ctrl, dlg);
} else if (event == EVENT_VALCHANGE) {
dlg_editbox_get(ctrl, dlg, cfg->printer, sizeof(cfg->printer));
if (!strcmp(cfg->printer, PRINTER_DISABLED_STRING))
*cfg->printer = '\0';
}
}
static void codepage_handler(union control *ctrl, void *dlg,
void *data, int event)
{
Config *cfg = (Config *)data;
if (event == EVENT_REFRESH) {
int i;
const char *cp;
dlg_update_start(ctrl, dlg);
strcpy(cfg->line_codepage,
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_update_done(ctrl, dlg);
} else if (event == EVENT_VALCHANGE) {
dlg_editbox_get(ctrl, dlg, cfg->line_codepage,
sizeof(cfg->line_codepage));
strcpy(cfg->line_codepage,
cp_name(decode_codepage(cfg->line_codepage)));
}
}
static void sshbug_handler(union control *ctrl, void *dlg,
void *data, int event)
{
if (event == EVENT_REFRESH) {
dlg_update_start(ctrl, dlg);
dlg_listbox_clear(ctrl, dlg);
dlg_listbox_addwithid(ctrl, dlg, "Auto", AUTO);
dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF);
dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON);
switch (*(int *)ATOFFSET(data, ctrl->listbox.context.i)) {
case AUTO: dlg_listbox_select(ctrl, dlg, 0); break;
case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break;
case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break;
}
dlg_update_done(ctrl, dlg);
} else if (event == EVENT_SELCHANGE) {
int i = dlg_listbox_index(ctrl, dlg);
if (i < 0)
i = AUTO;
else
i = dlg_listbox_getid(ctrl, dlg, i);
*(int *)ATOFFSET(data, ctrl->listbox.context.i) = i;
}
}
#define SAVEDSESSION_LEN 2048
struct sessionsaver_data {
union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
union control *okbutton, *cancelbutton;
struct sesslist sesslist;
int midsession;
};
/*
* Helper function to load the session selected in the list box, if
* any, as this is done in more than one place below. Returns 0 for
* failure.
*/
static int load_selected_session(struct sessionsaver_data *ssd,
char *savedsession,
void *dlg, Config *cfg, int *maybe_launch)
{
int i = dlg_listbox_index(ssd->listbox, dlg);
int isdef;
if (i < 0) {
dlg_beep(dlg);
return 0;
}
isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
load_settings(ssd->sesslist.sessions[i], cfg);
if (!isdef) {
strncpy(savedsession, ssd->sesslist.sessions[i],
SAVEDSESSION_LEN);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -