1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-03-22 14:39:24 -05:00

Backport of the pre-0.77 demo features to 0.76.

This is a combined cherry-pick of three commits on the 0.77 branch:

896bcd506866d3f "Resurrect the test backends"
9294ee349617632 "Windows PuTTYgen: saw load_key_file in half"
bc7e06c49411a89 "Windows tools: assorted '-demo' options"

Of course, these commits aren't in 0.76 itself, and I don't see any
reason to publish a binary build of 0.76 containing them. This is just
a branch I can build from myself to get a version of PuTTY that will
look exactly like the real 0.76 but permit automated generation of
demo screenshots.
This commit is contained in:
Simon Tatham 2022-04-02 16:13:27 +01:00
parent 1fd7baa734
commit 11192e2e33
8 changed files with 331 additions and 93 deletions

3
Recipe
View File

@ -330,7 +330,9 @@ KEYGEN = sshrsag sshdssg sshecdsag
# X/GTK Unix app, [U] for command-line Unix app. # X/GTK Unix app, [U] for command-line Unix app.
putty : [G] GUITERM NONSSH WINSSH W_BE_ALL WINMISC winx11 putty.res LIBS putty : [G] GUITERM NONSSH WINSSH W_BE_ALL WINMISC winx11 putty.res LIBS
+ screenshot testback
puttytel : [G] GUITERM NONSSH W_BE_NOSSH WINMISC puttytel.res nogss LIBS puttytel : [G] GUITERM NONSSH W_BE_NOSSH WINMISC puttytel.res nogss LIBS
+ screenshot testback
plink : [C] winplink wincons console NONSSH WINSSH W_BE_ALL logging WINMISC plink : [C] winplink wincons console NONSSH WINSSH W_BE_ALL logging WINMISC
+ winx11 plink.res winnojmp sessprep noterm winnohlp winselcli + winx11 plink.res winnojmp sessprep noterm winnohlp winselcli
+ clicons wincliloop console LIBS + clicons wincliloop console LIBS
@ -353,6 +355,7 @@ puttygen : [G] winpgen KEYGEN SSHPRIME sshdes ARITH sshmd5 version
+ sshpubk sshaes sshsh256 sshsh512 IMPORT winutils puttygen.res + sshpubk sshaes sshsh256 sshsh512 IMPORT winutils puttygen.res
+ tree234 notiming winhelp winnojmp CONF LIBS wintime sshecc sshprng + tree234 notiming winhelp winnojmp CONF LIBS wintime sshecc sshprng
+ sshauxcrypt sshhmac winsecur winmiscs sshsha3 sshblake2 sshargon2 + sshauxcrypt sshhmac winsecur winmiscs sshsha3 sshblake2 sshargon2
+ screenshot
pterm : [X] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore pterm : [X] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore
+ uxsignal CHARSET cmdline uxpterm version time xpmpterm xpmptcfg + uxsignal CHARSET cmdline uxpterm version time xpmpterm xpmptcfg

View File

@ -1302,6 +1302,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;
@ -1311,12 +1313,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);
/* /*

View File

@ -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 size_t null_send(Backend *, const char *, size_t); static size_t null_send(Backend *, const char *, size_t);
@ -54,8 +51,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,
@ -102,17 +99,6 @@ struct loop_state {
Backend backend; Backend backend;
}; };
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,
@ -123,15 +109,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);

114
windows/screenshot.c Normal file
View File

@ -0,0 +1,114 @@
#include "putty.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;
}

View File

@ -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:
/* /*

View File

@ -231,6 +231,11 @@ static int compose_state = 0;
static UINT wm_mousewheel = WM_MOUSEWHEEL; static UINT wm_mousewheel = WM_MOUSEWHEEL;
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;
#define IS_HIGH_VARSEL(wch1, wch2) \ #define IS_HIGH_VARSEL(wch1, wch2) \
((wch1) == 0xDB40 && ((wch2) >= 0xDD00 && (wch2) <= 0xDDEF)) ((wch1) == 0xDB40 && ((wch2) >= 0xDD00 && (wch2) <= 0xDDEF))
#define IS_LOW_VARSEL(wch) \ #define IS_LOW_VARSEL(wch) \
@ -369,7 +374,10 @@ static void start_backend(void)
* 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.
*/ */
vt = backend_vt_from_proto(conf_get_int(conf, CONF_protocol)); if (demo_terminal_data)
vt = &null_backend;
else
vt = backend_vt_from_proto(conf_get_int(conf, CONF_protocol));
if (!vt) { if (!vt) {
char *str = dupprintf("%s Internal Error", appname); char *str = dupprintf("%s Internal Error", appname);
MessageBox(NULL, "Unsupported protocol number found", MessageBox(NULL, "Unsupported protocol number found",
@ -520,6 +528,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
{ {
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. */
@ -646,6 +655,30 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
} 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'", argv);
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 {
@ -656,13 +689,26 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
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);
@ -885,6 +931,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) {
HANDLE *handles; HANDLE *handles;
int nhandles, n; int nhandles, n;
@ -5858,3 +5906,19 @@ static bool win_seat_get_window_pixel_size(Seat *seat, int *x, int *y)
*y = r.bottom - r.top; *y = r.bottom - r.top;
return true; return true;
} }
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);
}
}

View File

@ -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.
@ -966,6 +968,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)
{ {
@ -1055,65 +1116,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
@ -1179,6 +1182,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;
@ -1402,9 +1406,33 @@ 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);
/* BODGE for the 0.66 backport */
ui_set_key_type(hwnd, state, IDC_KEYSSH2EDDSA);
SetDlgItemInt(hwnd, IDC_BITS, 255, false);
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->collecting_entropy && if (state->collecting_entropy &&
@ -2006,6 +2034,21 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
!strcmp(argv[i], "-restrict_acl") || !strcmp(argv[i], "-restrict_acl") ||
!strcmp(argv[i], "-restrictacl")) { !strcmp(argv[i], "-restrictacl")) {
restrict_process_acl(); restrict_process_acl();
} else if (!strcmp(argv[i], "-demo-screenshot")) {
demo_screenshot_filename = (i+1 < argc ? argv[++i] :
"puttygen.bmp");
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");
} else { } else {
/* /*
* Assume the first argument to be a private key file, and * Assume the first argument to be a private key file, and

View File

@ -701,4 +701,7 @@ void cli_main_loop(cliloop_pre_t pre, cliloop_post_t post, void *ctx);
bool cliloop_null_pre(void *vctx, const HANDLE **, size_t *); bool cliloop_null_pre(void *vctx, const HANDLE **, size_t *);
bool cliloop_null_post(void *vctx, size_t); bool cliloop_null_post(void *vctx, size_t);
char *save_screenshot(HWND hwnd, const char *outfile);
void gui_terminal_ready(HWND hwnd, Seat *seat, Backend *backend);
#endif #endif