📄 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)"
static void protocolbuttons_handler(union control *ctrl, void *dlg,
void *data, int event)
{
int button, defport;
Config *cfg = (Config *)data;
/*
* 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.
*/
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((union control *)ctrl->radio.context.p, dlg);
}
}
}
}
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 },
{ "-- 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 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;
};
/*
* 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 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], !isdef, cfg);
if (!isdef) {
strncpy(savedsession, ssd->sesslist->sessions[i],
SAVEDSESSION_LEN);
savedsession[SAVEDSESSION_LEN-1] = '\0';
} else {
savedsession[0] = '\0';
}
dlg_refresh(NULL, dlg);
/* Restore the selection, which might have been clobbered by
* changing the value of the edit box. */
dlg_listbox_select(ssd->listbox, dlg, i);
return 1;
}
static void sessionsaver_handler(union control *ctrl, void *dlg,
void *data, int event)
{
Config *cfg = (Config *)data;
struct sessionsaver_data *ssd =
(struct sessionsaver_data *)ctrl->generic.context.p;
char *savedsession;
/*
* The first time we're called in a new dialog, we must
* allocate space to store the current contents of the saved
* session edit box (since it must persist even when we switch
* panels, but is not part of the Config).
*
* Of course, this doesn't need to be done mid-session.
*/
if (!ssd->editbox) {
savedsession = NULL;
} else if (!dlg_get_privdata(ssd->editbox, dlg)) {
savedsession = (char *)
dlg_alloc_privdata(ssd->editbox, dlg, SAVEDSESSION_LEN);
savedsession[0] = '\0';
} else {
savedsession = dlg_get_privdata(ssd->editbox, dlg);
}
if (event == EVENT_REFRESH) {
if (ctrl == ssd->editbox) {
dlg_editbox_set(ctrl, dlg, savedsession);
} else if (ctrl == ssd->listbox) {
int i;
dlg_update_start(ctrl, dlg);
dlg_listbox_clear(ctrl, dlg);
for (i = 0; i < ssd->sesslist->nsessions; i++)
dlg_listbox_add(ctrl, dlg, ssd->sesslist->sessions[i]);
dlg_update_done(ctrl, dlg);
}
} else if (event == EVENT_VALCHANGE) {
if (ctrl == ssd->editbox) {
dlg_editbox_get(ctrl, dlg, savedsession,
SAVEDSESSION_LEN);
}
} else if (event == EVENT_ACTION) {
if (ctrl == ssd->listbox || ctrl == ssd->loadbutton) {
/*
* The user has double-clicked a session, or hit Load.
* We must load the selected session, and then
* terminate the configuration dialog _if_ there was a
* 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])) {
dlg_end(dlg, 1); /* it's all over, and succeeded */
}
} else if (ctrl == ssd->savebutton) {
int isdef = !strcmp(savedsession, "Default Settings");
if (!savedsession[0]) {
int i = dlg_listbox_index(ssd->listbox, dlg);
if (i < 0) {
dlg_beep(dlg);
return;
}
isdef = !strcmp(ssd->sesslist->sessions[i], "Default Settings");
if (!isdef) {
strncpy(savedsession, ssd->sesslist->sessions[i],
SAVEDSESSION_LEN);
savedsession[SAVEDSESSION_LEN-1] = '\0';
} else {
savedsession[0] = '\0';
}
}
{
char *errmsg = save_settings(savedsession, !isdef, cfg);
if (errmsg) {
dlg_error_msg(dlg, errmsg);
sfree(errmsg);
}
}
get_sesslist(ssd->sesslist, FALSE);
get_sesslist(ssd->sesslist, TRUE);
dlg_refresh(ssd->editbox, dlg);
dlg_refresh(ssd->listbox, dlg);
} else if (ctrl == ssd->delbutton) {
int i = dlg_listbox_index(ssd->listbox, dlg);
if (i <= 0) {
dlg_beep(dlg);
} else {
del_settings(ssd->sesslist->sessions[i]);
get_sesslist(ssd->sesslist, FALSE);
get_sesslist(ssd->sesslist, TRUE);
dlg_refresh(ssd->listbox, dlg);
}
} else if (ctrl == ssd->okbutton) {
if (!savedsession) {
/* In a mid-session Change Settings, Apply is always OK. */
dlg_end(dlg, 1);
return;
}
/*
* Annoying special case. If the `Open' button is
* pressed while no host name is currently set, _and_
* the session list previously had the focus, _and_
* 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) {
Config cfg2;
if (!load_selected_session(ssd, savedsession, dlg, &cfg2)) {
dlg_beep(dlg);
return;
}
/* If at this point we have a valid session, go! */
if (*cfg2.host) {
*cfg = cfg2; /* structure copy */
cfg->remote_cmd_ptr = cfg->remote_cmd; /* nasty */
dlg_end(dlg, 1);
} else
dlg_beep(dlg);
}
/*
* Otherwise, do the normal thing: if we have a valid
* session, get going.
*/
if (*cfg->host) {
dlg_end(dlg, 1);
} else
dlg_beep(dlg);
} else if (ctrl == ssd->cancelbutton) {
dlg_end(dlg, 0);
}
}
}
struct charclass_data {
union control *listbox, *editbox, *button;
};
static void charclass_handler(union control *ctrl, void *dlg,
void *data, int event)
{
Config *cfg = (Config *)data;
struct charclass_data *ccd =
(struct charclass_data *)ctrl->generic.context.p;
if (event == EVENT_REFRESH) {
if (ctrl == ccd->listbox) {
int i;
dlg_update_start(ctrl, dlg);
dlg_listbox_clear(ctrl, dlg);
for (i = 0; i < 128; i++) {
char str[100];
sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
(i >= 0x21 && i != 0x7F) ? i : ' ', cfg->wordness[i]);
dlg_listbox_add(ctrl, dlg, str);
}
dlg_update_done(ctrl, dlg);
}
} else if (event == EVENT_ACTION) {
if (ctrl == ccd->button) {
char str[100];
int i, n;
dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str));
n = atoi(str);
for (i = 0; i < 128; i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -