mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 09:58:01 +00:00
Merge demo screenshot features from 'pre-0.77'.
This commit is contained in:
commit
dec7d7fce7
@ -14,6 +14,7 @@
|
|||||||
#cmakedefine01 HAVE_GETNAMEDPIPECLIENTPROCESSID
|
#cmakedefine01 HAVE_GETNAMEDPIPECLIENTPROCESSID
|
||||||
#cmakedefine01 HAVE_SETDEFAULTDLLDIRECTORIES
|
#cmakedefine01 HAVE_SETDEFAULTDLLDIRECTORIES
|
||||||
#cmakedefine01 HAVE_STRTOUMAX
|
#cmakedefine01 HAVE_STRTOUMAX
|
||||||
|
#cmakedefine01 HAVE_DWMAPI_H
|
||||||
|
|
||||||
#cmakedefine NOT_X_WINDOWS
|
#cmakedefine NOT_X_WINDOWS
|
||||||
|
|
||||||
|
@ -51,6 +51,8 @@ check_symbol_exists(GetNamedPipeClientProcessId "windows.h"
|
|||||||
HAVE_GETNAMEDPIPECLIENTPROCESSID)
|
HAVE_GETNAMEDPIPECLIENTPROCESSID)
|
||||||
check_symbol_exists(CreatePseudoConsole "windows.h" HAVE_CONPTY)
|
check_symbol_exists(CreatePseudoConsole "windows.h" HAVE_CONPTY)
|
||||||
|
|
||||||
|
check_include_files("windows.h;dwmapi.h" HAVE_DWMAPI_H)
|
||||||
|
|
||||||
check_c_source_compiles("
|
check_c_source_compiles("
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
GCP_RESULTSW gcpw;
|
GCP_RESULTSW gcpw;
|
||||||
|
@ -32,11 +32,8 @@
|
|||||||
|
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
|
|
||||||
static char *null_init(const BackendVtable *, Seat *, Backend **, LogContext *,
|
|
||||||
Conf *, const char *, int, char **, bool, bool);
|
|
||||||
static char *loop_init(const BackendVtable *, Seat *, Backend **, LogContext *,
|
static char *loop_init(const BackendVtable *, Seat *, Backend **, LogContext *,
|
||||||
Conf *, const char *, int, char **, bool, bool);
|
Conf *, const char *, int, char **, bool, bool);
|
||||||
static void null_free(Backend *);
|
|
||||||
static void loop_free(Backend *);
|
static void loop_free(Backend *);
|
||||||
static void null_reconfig(Backend *, Conf *);
|
static void null_reconfig(Backend *, Conf *);
|
||||||
static void null_send(Backend *, const char *, size_t);
|
static void null_send(Backend *, const char *, size_t);
|
||||||
@ -55,8 +52,8 @@ static void null_unthrottle(Backend *, size_t);
|
|||||||
static int null_cfg_info(Backend *);
|
static int null_cfg_info(Backend *);
|
||||||
|
|
||||||
const BackendVtable null_backend = {
|
const BackendVtable null_backend = {
|
||||||
.init = null_init,
|
.init = loop_init,
|
||||||
.free = null_free,
|
.free = loop_free,
|
||||||
.reconfig = null_reconfig,
|
.reconfig = null_reconfig,
|
||||||
.send = null_send,
|
.send = null_send,
|
||||||
.sendbuffer = null_sendbuffer,
|
.sendbuffer = null_sendbuffer,
|
||||||
@ -106,17 +103,6 @@ struct loop_state {
|
|||||||
size_t sendbuffer;
|
size_t sendbuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *null_init(const BackendVtable *vt, Seat *seat,
|
|
||||||
Backend **backend_handle, LogContext *logctx,
|
|
||||||
Conf *conf, const char *host, int port,
|
|
||||||
char **realhost, bool nodelay, bool keepalive) {
|
|
||||||
/* No local authentication phase in this protocol */
|
|
||||||
seat_set_trust_status(seat, false);
|
|
||||||
|
|
||||||
*backend_handle = NULL;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *loop_init(const BackendVtable *vt, Seat *seat,
|
static char *loop_init(const BackendVtable *vt, Seat *seat,
|
||||||
Backend **backend_handle, LogContext *logctx,
|
Backend **backend_handle, LogContext *logctx,
|
||||||
Conf *conf, const char *host, int port,
|
Conf *conf, const char *host, int port,
|
||||||
@ -127,15 +113,14 @@ static char *loop_init(const BackendVtable *vt, Seat *seat,
|
|||||||
seat_set_trust_status(seat, false);
|
seat_set_trust_status(seat, false);
|
||||||
|
|
||||||
st->seat = seat;
|
st->seat = seat;
|
||||||
|
st->backend.vt = vt;
|
||||||
*backend_handle = &st->backend;
|
*backend_handle = &st->backend;
|
||||||
|
|
||||||
|
*realhost = dupstr(host);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void null_free(Backend *be)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loop_free(Backend *be)
|
static void loop_free(Backend *be)
|
||||||
{
|
{
|
||||||
struct loop_state *st = container_of(be, struct loop_state, backend);
|
struct loop_state *st = container_of(be, struct loop_state, backend);
|
||||||
|
18
settings.c
18
settings.c
@ -1307,6 +1307,8 @@ static int sessioncmp(const void *av, const void *bv)
|
|||||||
return strcmp(a, b); /* otherwise, compare normally */
|
return strcmp(a, b); /* otherwise, compare normally */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool sesslist_demo_mode = false;
|
||||||
|
|
||||||
void get_sesslist(struct sesslist *list, bool allocate)
|
void get_sesslist(struct sesslist *list, bool allocate)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -1316,12 +1318,18 @@ void get_sesslist(struct sesslist *list, bool allocate)
|
|||||||
if (allocate) {
|
if (allocate) {
|
||||||
strbuf *sb = strbuf_new();
|
strbuf *sb = strbuf_new();
|
||||||
|
|
||||||
if ((handle = enum_settings_start()) != NULL) {
|
if (sesslist_demo_mode) {
|
||||||
while (enum_settings_next(handle, sb))
|
put_asciz(sb, "demo-server");
|
||||||
put_byte(sb, '\0');
|
put_asciz(sb, "demo-server-2");
|
||||||
enum_settings_finish(handle);
|
} else {
|
||||||
|
if ((handle = enum_settings_start()) != NULL) {
|
||||||
|
while (enum_settings_next(handle, sb))
|
||||||
|
put_byte(sb, '\0');
|
||||||
|
enum_settings_finish(handle);
|
||||||
|
}
|
||||||
|
put_byte(sb, '\0');
|
||||||
}
|
}
|
||||||
put_byte(sb, '\0');
|
|
||||||
list->buffer = strbuf_to_str(sb);
|
list->buffer = strbuf_to_str(sb);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -28,6 +28,7 @@ add_sources_from_current_dir(utils
|
|||||||
utils/platform_get_x_display.c
|
utils/platform_get_x_display.c
|
||||||
utils/registry_get_string.c
|
utils/registry_get_string.c
|
||||||
utils/request_file.c
|
utils/request_file.c
|
||||||
|
utils/screenshot.c
|
||||||
utils/security.c
|
utils/security.c
|
||||||
utils/split_into_argv.c
|
utils/split_into_argv.c
|
||||||
utils/version.c
|
utils/version.c
|
||||||
|
@ -388,6 +388,8 @@ static void create_controls(HWND hwnd, char *path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *dialog_box_demo_screenshot_filename = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function is the configuration box.
|
* This function is the configuration box.
|
||||||
* (Being a dialog procedure, in general it returns 0 if the default
|
* (Being a dialog procedure, in general it returns 0 if the default
|
||||||
@ -396,6 +398,7 @@ static void create_controls(HWND hwnd, char *path)
|
|||||||
static INT_PTR CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg,
|
static INT_PTR CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg,
|
||||||
WPARAM wParam, LPARAM lParam)
|
WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
|
const int DEMO_SCREENSHOT_TIMER_ID = 1230;
|
||||||
HWND hw, treeview;
|
HWND hw, treeview;
|
||||||
struct treeview_faff tvfaff;
|
struct treeview_faff tvfaff;
|
||||||
int ret;
|
int ret;
|
||||||
@ -565,6 +568,21 @@ static INT_PTR CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg,
|
|||||||
* spurious firing during the above setup procedure.
|
* spurious firing during the above setup procedure.
|
||||||
*/
|
*/
|
||||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, 1);
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, 1);
|
||||||
|
|
||||||
|
if (dialog_box_demo_screenshot_filename)
|
||||||
|
SetTimer(hwnd, DEMO_SCREENSHOT_TIMER_ID, TICKSPERSEC, NULL);
|
||||||
|
return 0;
|
||||||
|
case WM_TIMER:
|
||||||
|
if (dialog_box_demo_screenshot_filename &&
|
||||||
|
(UINT_PTR)wParam == DEMO_SCREENSHOT_TIMER_ID) {
|
||||||
|
KillTimer(hwnd, DEMO_SCREENSHOT_TIMER_ID);
|
||||||
|
const char *err = save_screenshot(
|
||||||
|
hwnd, dialog_box_demo_screenshot_filename);
|
||||||
|
if (err)
|
||||||
|
MessageBox(hwnd, err, "Demo screenshot failure",
|
||||||
|
MB_OK | MB_ICONERROR);
|
||||||
|
SaneEndDialog(hwnd, 0);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
case WM_LBUTTONUP:
|
case WM_LBUTTONUP:
|
||||||
/*
|
/*
|
||||||
|
@ -759,4 +759,7 @@ bool aux_match_arg(AuxMatchOpt *amo, char **val);
|
|||||||
bool aux_match_opt(AuxMatchOpt *amo, char **val, const char *optname, ...);
|
bool aux_match_opt(AuxMatchOpt *amo, char **val, const char *optname, ...);
|
||||||
bool aux_match_done(AuxMatchOpt *amo);
|
bool aux_match_done(AuxMatchOpt *amo);
|
||||||
|
|
||||||
|
char *save_screenshot(HWND hwnd, const char *outfile);
|
||||||
|
void gui_terminal_ready(HWND hwnd, Seat *seat, Backend *backend);
|
||||||
|
|
||||||
#endif /* PUTTY_WINDOWS_PLATFORM_H */
|
#endif /* PUTTY_WINDOWS_PLATFORM_H */
|
||||||
|
@ -45,3 +45,7 @@ const wchar_t *get_app_user_model_id(void)
|
|||||||
{
|
{
|
||||||
return L"SimonTatham.Pterm";
|
return L"SimonTatham.Pterm";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gui_terminal_ready(HWND hwnd, Seat *seat, Backend *backend)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
|
|
||||||
|
extern bool sesslist_demo_mode;
|
||||||
|
extern const char *dialog_box_demo_screenshot_filename;
|
||||||
|
static strbuf *demo_terminal_data = NULL;
|
||||||
|
static const char *terminal_demo_screenshot_filename;
|
||||||
|
|
||||||
void gui_term_process_cmdline(Conf *conf, char *cmdline)
|
void gui_term_process_cmdline(Conf *conf, char *cmdline)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
bool special_launchable_argument = false;
|
bool special_launchable_argument = false;
|
||||||
|
bool demo_config_box = false;
|
||||||
|
|
||||||
settings_set_default_protocol(be_default_protocol);
|
settings_set_default_protocol(be_default_protocol);
|
||||||
/* Find the appropriate default port. */
|
/* Find the appropriate default port. */
|
||||||
@ -81,6 +87,29 @@ void gui_term_process_cmdline(Conf *conf, char *cmdline)
|
|||||||
} else if (!strcmp(p, "-pgpfp")) {
|
} else if (!strcmp(p, "-pgpfp")) {
|
||||||
pgp_fingerprints_msgbox(NULL);
|
pgp_fingerprints_msgbox(NULL);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
} else if (!strcmp(p, "-demo-config-box")) {
|
||||||
|
if (i+1 >= argc) {
|
||||||
|
cmdline_error("%s expects an output filename", p);
|
||||||
|
} else {
|
||||||
|
demo_config_box = true;
|
||||||
|
dialog_box_demo_screenshot_filename = argv[++i];
|
||||||
|
}
|
||||||
|
} else if (!strcmp(p, "-demo-terminal")) {
|
||||||
|
if (i+2 >= argc) {
|
||||||
|
cmdline_error("%s expects input and output filenames", p);
|
||||||
|
} else {
|
||||||
|
const char *infile = argv[++i];
|
||||||
|
terminal_demo_screenshot_filename = argv[++i];
|
||||||
|
FILE *fp = fopen(infile, "rb");
|
||||||
|
if (!fp)
|
||||||
|
cmdline_error("can't open input file '%s'", infile);
|
||||||
|
demo_terminal_data = strbuf_new();
|
||||||
|
char buf[4096];
|
||||||
|
int retd;
|
||||||
|
while ((retd = fread(buf, 1, sizeof(buf), fp)) > 0)
|
||||||
|
put_data(demo_terminal_data, buf, retd);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
} else if (*p != '-') {
|
} else if (*p != '-') {
|
||||||
cmdline_error("unexpected argument \"%s\"", p);
|
cmdline_error("unexpected argument \"%s\"", p);
|
||||||
} else {
|
} else {
|
||||||
@ -91,13 +120,26 @@ void gui_term_process_cmdline(Conf *conf, char *cmdline)
|
|||||||
|
|
||||||
cmdline_run_saved(conf);
|
cmdline_run_saved(conf);
|
||||||
|
|
||||||
/*
|
if (demo_config_box) {
|
||||||
* Bring up the config dialog if the command line hasn't
|
sesslist_demo_mode = true;
|
||||||
* (explicitly) specified a launchable configuration.
|
load_open_settings(NULL, conf);
|
||||||
*/
|
conf_set_str(conf, CONF_host, "demo-server.example.com");
|
||||||
if (!(special_launchable_argument || cmdline_host_ok(conf))) {
|
do_config(conf);
|
||||||
if (!do_config(conf))
|
cleanup_exit(0);
|
||||||
cleanup_exit(0);
|
} else if (demo_terminal_data) {
|
||||||
|
/* Ensure conf will cause an immediate session launch */
|
||||||
|
load_open_settings(NULL, conf);
|
||||||
|
conf_set_str(conf, CONF_host, "demo-server.example.com");
|
||||||
|
conf_set_int(conf, CONF_close_on_exit, FORCE_OFF);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Bring up the config dialog if the command line hasn't
|
||||||
|
* (explicitly) specified a launchable configuration.
|
||||||
|
*/
|
||||||
|
if (!(special_launchable_argument || cmdline_host_ok(conf))) {
|
||||||
|
if (!do_config(conf))
|
||||||
|
cleanup_exit(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare_session(conf);
|
prepare_session(conf);
|
||||||
@ -105,6 +147,10 @@ void gui_term_process_cmdline(Conf *conf, char *cmdline)
|
|||||||
|
|
||||||
const struct BackendVtable *backend_vt_from_conf(Conf *conf)
|
const struct BackendVtable *backend_vt_from_conf(Conf *conf)
|
||||||
{
|
{
|
||||||
|
if (demo_terminal_data) {
|
||||||
|
return &null_backend;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Select protocol. This is farmed out into a table in a
|
* Select protocol. This is farmed out into a table in a
|
||||||
* separate file to enable an ssh-free variant.
|
* separate file to enable an ssh-free variant.
|
||||||
@ -125,3 +171,19 @@ const wchar_t *get_app_user_model_id(void)
|
|||||||
{
|
{
|
||||||
return L"SimonTatham.PuTTY";
|
return L"SimonTatham.PuTTY";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void demo_terminal_screenshot(void *ctx, unsigned long now)
|
||||||
|
{
|
||||||
|
HWND hwnd = (HWND)ctx;
|
||||||
|
save_screenshot(hwnd, terminal_demo_screenshot_filename);
|
||||||
|
cleanup_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gui_terminal_ready(HWND hwnd, Seat *seat, Backend *backend)
|
||||||
|
{
|
||||||
|
if (demo_terminal_data) {
|
||||||
|
ptrlen data = ptrlen_from_strbuf(demo_terminal_data);
|
||||||
|
seat_stdout(seat, data.ptr, data.len);
|
||||||
|
schedule_timer(TICKSPERSEC, demo_terminal_screenshot, (void *)hwnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#define DEFAULT_EDCURVE_INDEX 0
|
#define DEFAULT_EDCURVE_INDEX 0
|
||||||
|
|
||||||
static char *cmdline_keyfile = NULL;
|
static char *cmdline_keyfile = NULL;
|
||||||
|
static ptrlen cmdline_demo_keystr;
|
||||||
|
static const char *demo_screenshot_filename = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print a modal (Really Bad) message box and perform a fatal exit.
|
* Print a modal (Really Bad) message box and perform a fatal exit.
|
||||||
@ -992,6 +994,65 @@ void ui_set_fptype(HWND hwnd, struct MainDlgState *state, int option)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void update_ui_after_load(HWND hwnd, struct MainDlgState *state,
|
||||||
|
const char *passphrase, int type,
|
||||||
|
RSAKey *newkey1, ssh2_userkey *newkey2)
|
||||||
|
{
|
||||||
|
SetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT, passphrase);
|
||||||
|
SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT, passphrase);
|
||||||
|
|
||||||
|
if (type == SSH_KEYTYPE_SSH1) {
|
||||||
|
char *fingerprint, *savecomment;
|
||||||
|
|
||||||
|
state->ssh2 = false;
|
||||||
|
state->commentptr = &state->key.comment;
|
||||||
|
state->key = *newkey1; /* structure copy */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the key fingerprint.
|
||||||
|
*/
|
||||||
|
savecomment = state->key.comment;
|
||||||
|
state->key.comment = NULL;
|
||||||
|
fingerprint = rsa_ssh1_fingerprint(&state->key);
|
||||||
|
state->key.comment = savecomment;
|
||||||
|
SetDlgItemText(hwnd, IDC_FINGERPRINT, fingerprint);
|
||||||
|
sfree(fingerprint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Construct a decimal representation of the key, for pasting
|
||||||
|
* into .ssh/authorized_keys on a Unix box.
|
||||||
|
*/
|
||||||
|
setupbigedit1(hwnd, IDC_KEYDISPLAY, IDC_PKSTATIC, &state->key);
|
||||||
|
} else {
|
||||||
|
char *fp;
|
||||||
|
char *savecomment;
|
||||||
|
|
||||||
|
state->ssh2 = true;
|
||||||
|
state->commentptr = &state->ssh2key.comment;
|
||||||
|
state->ssh2key = *newkey2; /* structure copy */
|
||||||
|
sfree(newkey2);
|
||||||
|
|
||||||
|
savecomment = state->ssh2key.comment;
|
||||||
|
state->ssh2key.comment = NULL;
|
||||||
|
fp = ssh2_fingerprint(state->ssh2key.key, state->fptype);
|
||||||
|
state->ssh2key.comment = savecomment;
|
||||||
|
|
||||||
|
SetDlgItemText(hwnd, IDC_FINGERPRINT, fp);
|
||||||
|
sfree(fp);
|
||||||
|
|
||||||
|
setupbigedit2(hwnd, IDC_KEYDISPLAY,
|
||||||
|
IDC_PKSTATIC, &state->ssh2key);
|
||||||
|
}
|
||||||
|
SetDlgItemText(hwnd, IDC_COMMENTEDIT,
|
||||||
|
*state->commentptr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finally, hide the progress bar and show the key data.
|
||||||
|
*/
|
||||||
|
ui_set_state(hwnd, state, 2);
|
||||||
|
state->key_exists = true;
|
||||||
|
}
|
||||||
|
|
||||||
void load_key_file(HWND hwnd, struct MainDlgState *state,
|
void load_key_file(HWND hwnd, struct MainDlgState *state,
|
||||||
Filename *filename, bool was_import_cmd)
|
Filename *filename, bool was_import_cmd)
|
||||||
{
|
{
|
||||||
@ -1081,65 +1142,7 @@ void load_key_file(HWND hwnd, struct MainDlgState *state,
|
|||||||
* Now update the key controls with all the
|
* Now update the key controls with all the
|
||||||
* key data.
|
* key data.
|
||||||
*/
|
*/
|
||||||
{
|
update_ui_after_load(hwnd, state, passphrase, type, &newkey1, newkey2);
|
||||||
SetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT,
|
|
||||||
passphrase);
|
|
||||||
SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT,
|
|
||||||
passphrase);
|
|
||||||
if (type == SSH_KEYTYPE_SSH1) {
|
|
||||||
char *fingerprint, *savecomment;
|
|
||||||
|
|
||||||
state->ssh2 = false;
|
|
||||||
state->commentptr = &state->key.comment;
|
|
||||||
state->key = newkey1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set the key fingerprint.
|
|
||||||
*/
|
|
||||||
savecomment = state->key.comment;
|
|
||||||
state->key.comment = NULL;
|
|
||||||
fingerprint = rsa_ssh1_fingerprint(&state->key);
|
|
||||||
state->key.comment = savecomment;
|
|
||||||
SetDlgItemText(hwnd, IDC_FINGERPRINT, fingerprint);
|
|
||||||
sfree(fingerprint);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Construct a decimal representation
|
|
||||||
* of the key, for pasting into
|
|
||||||
* .ssh/authorized_keys on a Unix box.
|
|
||||||
*/
|
|
||||||
setupbigedit1(hwnd, IDC_KEYDISPLAY,
|
|
||||||
IDC_PKSTATIC, &state->key);
|
|
||||||
} else {
|
|
||||||
char *fp;
|
|
||||||
char *savecomment;
|
|
||||||
|
|
||||||
state->ssh2 = true;
|
|
||||||
state->commentptr =
|
|
||||||
&state->ssh2key.comment;
|
|
||||||
state->ssh2key = *newkey2; /* structure copy */
|
|
||||||
sfree(newkey2);
|
|
||||||
|
|
||||||
savecomment = state->ssh2key.comment;
|
|
||||||
state->ssh2key.comment = NULL;
|
|
||||||
fp = ssh2_fingerprint(state->ssh2key.key, state->fptype);
|
|
||||||
state->ssh2key.comment = savecomment;
|
|
||||||
|
|
||||||
SetDlgItemText(hwnd, IDC_FINGERPRINT, fp);
|
|
||||||
sfree(fp);
|
|
||||||
|
|
||||||
setupbigedit2(hwnd, IDC_KEYDISPLAY,
|
|
||||||
IDC_PKSTATIC, &state->ssh2key);
|
|
||||||
}
|
|
||||||
SetDlgItemText(hwnd, IDC_COMMENTEDIT,
|
|
||||||
*state->commentptr);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Finally, hide the progress bar and show
|
|
||||||
* the key data.
|
|
||||||
*/
|
|
||||||
ui_set_state(hwnd, state, 2);
|
|
||||||
state->key_exists = true;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the user has imported a foreign key
|
* If the user has imported a foreign key
|
||||||
@ -1205,6 +1208,7 @@ static void start_generating_key(HWND hwnd, struct MainDlgState *state)
|
|||||||
static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
|
static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
|
||||||
WPARAM wParam, LPARAM lParam)
|
WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
|
const int DEMO_SCREENSHOT_TIMER_ID = 1230;
|
||||||
static const char entropy_msg[] =
|
static const char entropy_msg[] =
|
||||||
"Please generate some randomness by moving the mouse over the blank area.";
|
"Please generate some randomness by moving the mouse over the blank area.";
|
||||||
struct MainDlgState *state;
|
struct MainDlgState *state;
|
||||||
@ -1428,9 +1432,30 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
|
|||||||
Filename *fn = filename_from_str(cmdline_keyfile);
|
Filename *fn = filename_from_str(cmdline_keyfile);
|
||||||
load_key_file(hwnd, state, fn, false);
|
load_key_file(hwnd, state, fn, false);
|
||||||
filename_free(fn);
|
filename_free(fn);
|
||||||
|
} else if (cmdline_demo_keystr.ptr) {
|
||||||
|
BinarySource src[1];
|
||||||
|
BinarySource_BARE_INIT_PL(src, cmdline_demo_keystr);
|
||||||
|
const char *errmsg;
|
||||||
|
ssh2_userkey *k = ppk_load_s(src, NULL, &errmsg);
|
||||||
|
assert(!errmsg);
|
||||||
|
|
||||||
|
update_ui_after_load(hwnd, state, "demo passphrase",
|
||||||
|
SSH_KEYTYPE_SSH2, NULL, k);
|
||||||
|
|
||||||
|
SetTimer(hwnd, DEMO_SCREENSHOT_TIMER_ID, TICKSPERSEC, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
case WM_TIMER:
|
||||||
|
if ((UINT_PTR)wParam == DEMO_SCREENSHOT_TIMER_ID) {
|
||||||
|
KillTimer(hwnd, DEMO_SCREENSHOT_TIMER_ID);
|
||||||
|
const char *err = save_screenshot(hwnd, demo_screenshot_filename);
|
||||||
|
if (err)
|
||||||
|
MessageBox(hwnd, err, "Demo screenshot failure",
|
||||||
|
MB_OK | MB_ICONERROR);
|
||||||
|
EndDialog(hwnd, 0);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
case WM_MOUSEMOVE:
|
case WM_MOUSEMOVE:
|
||||||
state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||||
if (state->entropy && state->entropy_got < state->entropy_required) {
|
if (state->entropy && state->entropy_got < state->entropy_required) {
|
||||||
@ -2175,6 +2200,22 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
|||||||
opt_error("unrecognised PPK parameter '%s'\n", val);
|
opt_error("unrecognised PPK parameter '%s'\n", val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (match_optval("-demo-screenshot")) {
|
||||||
|
demo_screenshot_filename = val;
|
||||||
|
cmdline_demo_keystr = PTRLEN_LITERAL(
|
||||||
|
"PuTTY-User-Key-File-3: ssh-ed25519\n"
|
||||||
|
"Encryption: none\n"
|
||||||
|
"Comment: ed25519-key-20220402\n"
|
||||||
|
"Public-Lines: 2\n"
|
||||||
|
"AAAAC3NzaC1lZDI1NTE5AAAAILzuIFwZ"
|
||||||
|
"8ZhgOlilcSb+9zPuCf/DmKJiloVlmWGy\n"
|
||||||
|
"xa/F\n"
|
||||||
|
"Private-Lines: 1\n"
|
||||||
|
"AAAAIPca6vLwtB2NJhZUpABQISR0gcQH8jjQLta19VyzA3wc\n"
|
||||||
|
"Private-MAC: 1159e9628259b35933b397379bbe8a14"
|
||||||
|
"a1f1d97fe91e446e45a9581a3408b70e\n");
|
||||||
|
params->keybutton = IDC_KEYSSH2EDDSA;
|
||||||
|
argbits = 255;
|
||||||
} else {
|
} else {
|
||||||
opt_error("unrecognised option '%s'\n", amo.argv[amo.index]);
|
opt_error("unrecognised option '%s'\n", amo.argv[amo.index]);
|
||||||
}
|
}
|
||||||
|
126
windows/utils/screenshot.c
Normal file
126
windows/utils/screenshot.c
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
#include "putty.h"
|
||||||
|
|
||||||
|
#if HAVE_DWMAPI_H
|
||||||
|
|
||||||
|
#include <dwmapi.h>
|
||||||
|
|
||||||
|
char *save_screenshot(HWND hwnd, const char *outfile)
|
||||||
|
{
|
||||||
|
HDC dcWindow = NULL, dcSave = NULL;
|
||||||
|
HBITMAP bmSave = NULL;
|
||||||
|
uint8_t *buffer = NULL;
|
||||||
|
char *err = NULL;
|
||||||
|
|
||||||
|
static HMODULE dwmapi_module;
|
||||||
|
DECL_WINDOWS_FUNCTION(static, HRESULT, DwmGetWindowAttribute,
|
||||||
|
(HWND, DWORD, PVOID, DWORD));
|
||||||
|
|
||||||
|
if (!dwmapi_module) {
|
||||||
|
dwmapi_module = load_system32_dll("dwmapi.dll");
|
||||||
|
GET_WINDOWS_FUNCTION(dwmapi_module, DwmGetWindowAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
dcWindow = GetDC(NULL);
|
||||||
|
if (!dcWindow) {
|
||||||
|
err = dupprintf("GetDC(window): %s", win_strerror(GetLastError()));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x, y, w, h;
|
||||||
|
RECT wr;
|
||||||
|
|
||||||
|
/* Use DwmGetWindowAttribute in place of GetWindowRect to exclude
|
||||||
|
* drop shadow, otherwise we get a load of unwanted desktop
|
||||||
|
* background under the shadow */
|
||||||
|
if (p_DwmGetWindowAttribute &&
|
||||||
|
0 <= p_DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS,
|
||||||
|
&wr, sizeof(wr))) {
|
||||||
|
x = wr.left;
|
||||||
|
y = wr.top;
|
||||||
|
w = wr.right - wr.left;
|
||||||
|
h = wr.bottom - wr.top;
|
||||||
|
} else {
|
||||||
|
BITMAP bmhdr;
|
||||||
|
memset(&bmhdr, 0, sizeof(bmhdr));
|
||||||
|
GetObject(GetCurrentObject(dcWindow, OBJ_BITMAP),
|
||||||
|
sizeof(bmhdr), &bmhdr);
|
||||||
|
x = y = 0;
|
||||||
|
w = bmhdr.bmWidth;
|
||||||
|
h = bmhdr.bmHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
dcSave = CreateCompatibleDC(dcWindow);
|
||||||
|
if (!dcSave) {
|
||||||
|
err = dupprintf("CreateCompatibleDC(desktop window dc): %s",
|
||||||
|
win_strerror(GetLastError()));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bmSave = CreateCompatibleBitmap(dcWindow, w, h);
|
||||||
|
if (!bmSave) {
|
||||||
|
err = dupprintf("CreateCompatibleBitmap: %s",
|
||||||
|
win_strerror(GetLastError()));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SelectObject(dcSave, bmSave)) {
|
||||||
|
err = dupprintf("SelectObject: %s", win_strerror(GetLastError()));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!BitBlt(dcSave, 0, 0, w, h, dcWindow, x, y, SRCCOPY)) {
|
||||||
|
err = dupprintf("BitBlt: %s", win_strerror(GetLastError()));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
BITMAPINFO bmInfo;
|
||||||
|
memset(&bmInfo, 0, sizeof(bmInfo));
|
||||||
|
bmInfo.bmiHeader.biSize = sizeof(bmInfo.bmiHeader);
|
||||||
|
bmInfo.bmiHeader.biWidth = w;
|
||||||
|
bmInfo.bmiHeader.biHeight = h;
|
||||||
|
bmInfo.bmiHeader.biPlanes = 1;
|
||||||
|
bmInfo.bmiHeader.biBitCount = 32;
|
||||||
|
bmInfo.bmiHeader.biCompression = BI_RGB;
|
||||||
|
|
||||||
|
size_t bmPixels = (size_t)w*h, bmBytes = bmPixels * 4;
|
||||||
|
buffer = snewn(bmBytes, uint8_t);
|
||||||
|
|
||||||
|
if (!GetDIBits(dcWindow, bmSave, 0, h, buffer, &bmInfo, DIB_RGB_COLORS))
|
||||||
|
err = dupprintf("GetDIBits (get data): %s",
|
||||||
|
win_strerror(GetLastError()));
|
||||||
|
|
||||||
|
FILE *fp = fopen(outfile, "wb");
|
||||||
|
if (!fp) {
|
||||||
|
err = dupprintf("'%s': unable to open file", outfile);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
BITMAPFILEHEADER bmFileHdr;
|
||||||
|
bmFileHdr.bfType = 'B' | ('M' << 8);
|
||||||
|
bmFileHdr.bfSize = sizeof(bmFileHdr) + sizeof(bmInfo.bmiHeader) + bmBytes;
|
||||||
|
bmFileHdr.bfOffBits = sizeof(bmFileHdr) + sizeof(bmInfo.bmiHeader);
|
||||||
|
fwrite((void *)&bmFileHdr, 1, sizeof(bmFileHdr), fp);
|
||||||
|
fwrite((void *)&bmInfo.bmiHeader, 1, sizeof(bmInfo.bmiHeader), fp);
|
||||||
|
fwrite((void *)buffer, 1, bmBytes, fp);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (dcWindow)
|
||||||
|
ReleaseDC(NULL, dcWindow);
|
||||||
|
if (bmSave)
|
||||||
|
DeleteObject(bmSave);
|
||||||
|
if (dcSave)
|
||||||
|
DeleteObject(dcSave);
|
||||||
|
sfree(buffer);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* HAVE_DWMAPI_H */
|
||||||
|
|
||||||
|
/* Without <dwmapi.h> we can't get the right window rectangle */
|
||||||
|
char *save_screenshot(HWND hwnd, const char *outfile)
|
||||||
|
{
|
||||||
|
return dupstr("Demo screenshots not compiled in to this build");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_DWMAPI_H */
|
@ -810,6 +810,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
|||||||
term_set_focus(term, GetForegroundWindow() == wgs.term_hwnd);
|
term_set_focus(term, GetForegroundWindow() == wgs.term_hwnd);
|
||||||
UpdateWindow(wgs.term_hwnd);
|
UpdateWindow(wgs.term_hwnd);
|
||||||
|
|
||||||
|
gui_terminal_ready(wgs.term_hwnd, &wgs.seat, backend);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int n;
|
int n;
|
||||||
DWORD timeout;
|
DWORD timeout;
|
||||||
|
Loading…
Reference in New Issue
Block a user