📄 winstore.c
字号:
/*
* winstore.c: Windows-specific implementation of the interface
* defined in storage.h.
*/
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "putty.h"
#include "storage.h"
#include <shlobj.h>
#ifndef CSIDL_APPDATA
#define CSIDL_APPDATA 0x001a
#endif
#ifndef CSIDL_LOCAL_APPDATA
#define CSIDL_LOCAL_APPDATA 0x001c
#endif
static const char *const puttystr = PUTTY_REG_POS "\\Sessions";
static const char hex[16] = "0123456789ABCDEF";
static int tried_shgetfolderpath = FALSE;
static HMODULE shell32_module = NULL;
typedef HRESULT (WINAPI *p_SHGetFolderPath_t)
(HWND, int, HANDLE, DWORD, LPTSTR);
static p_SHGetFolderPath_t p_SHGetFolderPath = NULL;
static void mungestr(const char *in, char *out)
{
int candot = 0;
while (*in) {
if (*in == ' ' || *in == '\\' || *in == '*' || *in == '?' ||
*in == '%' || *in < ' ' || *in > '~' || (*in == '.'
&& !candot)) {
*out++ = '%';
*out++ = hex[((unsigned char) *in) >> 4];
*out++ = hex[((unsigned char) *in) & 15];
} else
*out++ = *in;
in++;
candot = 1;
}
*out = '\0';
return;
}
static void unmungestr(const char *in, char *out, int outlen)
{
while (*in) {
if (*in == '%' && in[1] && in[2]) {
int i, j;
i = in[1] - '0';
i -= (i > 9 ? 7 : 0);
j = in[2] - '0';
j -= (j > 9 ? 7 : 0);
*out++ = (i << 4) + j;
if (!--outlen)
return;
in += 3;
} else {
*out++ = *in++;
if (!--outlen)
return;
}
}
*out = '\0';
return;
}
void *open_settings_w(const char *sessionname, char **errmsg)
{
HKEY subkey1, sesskey;
int ret;
char *p;
*errmsg = NULL;
if (!sessionname || !*sessionname)
sessionname = "Default Settings";
p = snewn(3 * strlen(sessionname) + 1, char);
mungestr(sessionname, p);
ret = RegCreateKey(HKEY_CURRENT_USER, puttystr, &subkey1);
if (ret != ERROR_SUCCESS) {
sfree(p);
*errmsg = dupprintf("Unable to create registry key\n"
"HKEY_CURRENT_USER\\%s", puttystr);
return NULL;
}
ret = RegCreateKey(subkey1, p, &sesskey);
RegCloseKey(subkey1);
if (ret != ERROR_SUCCESS) {
*errmsg = dupprintf("Unable to create registry key\n"
"HKEY_CURRENT_USER\\%s\\%s", puttystr, p);
sfree(p);
return NULL;
}
sfree(p);
return (void *) sesskey;
}
void write_setting_s(void *handle, const char *key, const char *value)
{
if (handle)
RegSetValueEx((HKEY) handle, key, 0, REG_SZ, value,
1 + strlen(value));
}
void write_setting_i(void *handle, const char *key, int value)
{
if (handle)
RegSetValueEx((HKEY) handle, key, 0, REG_DWORD,
(CONST BYTE *) &value, sizeof(value));
}
void close_settings_w(void *handle)
{
RegCloseKey((HKEY) handle);
}
void *open_settings_r(const char *sessionname)
{
HKEY subkey1, sesskey;
char *p;
if (!sessionname || !*sessionname)
sessionname = "Default Settings";
p = snewn(3 * strlen(sessionname) + 1, char);
mungestr(sessionname, p);
if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS) {
sesskey = NULL;
} else {
if (RegOpenKey(subkey1, p, &sesskey) != ERROR_SUCCESS) {
sesskey = NULL;
}
RegCloseKey(subkey1);
}
sfree(p);
return (void *) sesskey;
}
char *read_setting_s(void *handle, const char *key, char *buffer, int buflen)
{
DWORD type, size;
size = buflen;
if (!handle ||
RegQueryValueEx((HKEY) handle, key, 0,
&type, buffer, &size) != ERROR_SUCCESS ||
type != REG_SZ) return NULL;
else
return buffer;
}
int read_setting_i(void *handle, const char *key, int defvalue)
{
DWORD type, val, size;
size = sizeof(val);
if (!handle ||
RegQueryValueEx((HKEY) handle, key, 0, &type,
(BYTE *) &val, &size) != ERROR_SUCCESS ||
size != sizeof(val) || type != REG_DWORD)
return defvalue;
else
return val;
}
int read_setting_fontspec(void *handle, const char *name, FontSpec *result)
{
char *settingname;
FontSpec ret;
if (!read_setting_s(handle, name, ret.name, sizeof(ret.name)))
return 0;
settingname = dupcat(name, "IsBold", NULL);
ret.isbold = read_setting_i(handle, settingname, -1);
sfree(settingname);
if (ret.isbold == -1) return 0;
settingname = dupcat(name, "CharSet", NULL);
ret.charset = read_setting_i(handle, settingname, -1);
sfree(settingname);
if (ret.charset == -1) return 0;
settingname = dupcat(name, "Height", NULL);
ret.height = read_setting_i(handle, settingname, INT_MIN);
sfree(settingname);
if (ret.height == INT_MIN) return 0;
*result = ret;
return 1;
}
void write_setting_fontspec(void *handle, const char *name, FontSpec font)
{
char *settingname;
write_setting_s(handle, name, font.name);
settingname = dupcat(name, "IsBold", NULL);
write_setting_i(handle, settingname, font.isbold);
sfree(settingname);
settingname = dupcat(name, "CharSet", NULL);
write_setting_i(handle, settingname, font.charset);
sfree(settingname);
settingname = dupcat(name, "Height", NULL);
write_setting_i(handle, settingname, font.height);
sfree(settingname);
}
int read_setting_filename(void *handle, const char *name, Filename *result)
{
return !!read_setting_s(handle, name, result->path, sizeof(result->path));
}
void write_setting_filename(void *handle, const char *name, Filename result)
{
write_setting_s(handle, name, result.path);
}
void close_settings_r(void *handle)
{
RegCloseKey((HKEY) handle);
}
void del_settings(const char *sessionname)
{
HKEY subkey1;
char *p;
if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS)
return;
p = snewn(3 * strlen(sessionname) + 1, char);
mungestr(sessionname, p);
RegDeleteKey(subkey1, p);
sfree(p);
RegCloseKey(subkey1);
}
struct enumsettings {
HKEY key;
int i;
};
void *enum_settings_start(void)
{
struct enumsettings *ret;
HKEY key;
if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &key) != ERROR_SUCCESS)
return NULL;
ret = snew(struct enumsettings);
if (ret) {
ret->key = key;
ret->i = 0;
}
return ret;
}
char *enum_settings_next(void *handle, char *buffer, int buflen)
{
struct enumsettings *e = (struct enumsettings *) handle;
char *otherbuf;
otherbuf = snewn(3 * buflen, char);
if (RegEnumKey(e->key, e->i++, otherbuf, 3 * buflen) == ERROR_SUCCESS) {
unmungestr(otherbuf, buffer, buflen);
sfree(otherbuf);
return buffer;
} else {
sfree(otherbuf);
return NULL;
}
}
void enum_settings_finish(void *handle)
{
struct enumsettings *e = (struct enumsettings *) handle;
RegCloseKey(e->key);
sfree(e);
}
static void hostkey_regname(char *buffer, const char *hostname,
int port, const char *keytype)
{
int len;
strcpy(buffer, keytype);
strcat(buffer, "@");
len = strlen(buffer);
len += sprintf(buffer + len, "%d:", port);
mungestr(hostname, buffer + strlen(buffer));
}
int verify_host_key(const char *hostname, int port,
const char *keytype, const char *key)
{
char *otherstr, *regname;
int len;
HKEY rkey;
DWORD readlen;
DWORD type;
int ret, compare;
len = 1 + strlen(key);
/*
* Now read a saved key in from the registry and see what it
* says.
*/
otherstr = snewn(len, char);
regname = snewn(3 * (strlen(hostname) + strlen(keytype)) + 15, char);
hostkey_regname(regname, hostname, port, keytype);
if (RegOpenKey(HKEY_CURRENT_USER, PUTTY_REG_POS "\\SshHostKeys",
&rkey) != ERROR_SUCCESS)
return 1; /* key does not exist in registry */
readlen = len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -