Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitrij <kvarkas@gmail.com>2022-10-31 00:45:23 +0300
committerDimitrij <kvarkas@gmail.com>2022-10-31 00:45:23 +0300
commit302fb2e8ddea1c993552c9a30c02f41d01ca54a9 (patch)
treed6cf1b32664296ef2cecda33caeafbe39e6695c1 /WINDOWS
parent59105d9b26363e47f00676bd365b2ac8d4cb536a (diff)
parent4ff82ab29a22936b78510c68f544a99e677efed3 (diff)
Merge tag 'tags/0.78'HEADmaster
Diffstat (limited to 'WINDOWS')
-rw-r--r--WINDOWS/PAGEANT.RC8
-rw-r--r--WINDOWS/PUTTY.RC8
-rw-r--r--WINDOWS/PUTTYGEN.RC12
-rw-r--r--WINDOWS/PUTTYTEL.RC8
-rw-r--r--WINDOWS/RCSTUFF.H15
-rw-r--r--WINDOWS/WINCFG.C405
-rw-r--r--WINDOWS/WINCONS.C452
-rw-r--r--WINDOWS/WINCTRLS.C2600
-rw-r--r--WINDOWS/WINDEFS.C40
-rw-r--r--WINDOWS/WINDLG.C1156
-rw-r--r--WINDOWS/WINDOW.C404
-rw-r--r--WINDOWS/WINGSS.C703
-rw-r--r--WINDOWS/WINHANDL.C731
-rw-r--r--WINDOWS/WINHELP.C250
-rw-r--r--WINDOWS/WINHELP.H208
-rw-r--r--WINDOWS/WINJUMP.C748
-rw-r--r--WINDOWS/WINMISC.C467
-rw-r--r--WINDOWS/WINNET.C1825
-rw-r--r--WINDOWS/WINNOISE.C142
-rw-r--r--WINDOWS/WINNOJMP.C8
-rw-r--r--WINDOWS/WINPGEN.C2026
-rw-r--r--WINDOWS/WINPGNT.C1723
-rw-r--r--WINDOWS/WINPGNTC.C348
-rw-r--r--WINDOWS/WINPLINK.C535
-rw-r--r--WINDOWS/WINPRINT.C224
-rw-r--r--WINDOWS/WINPROXY.C107
-rw-r--r--WINDOWS/WINSER.C465
-rw-r--r--WINDOWS/WINSFTP.C650
-rw-r--r--WINDOWS/WINSTORE.C873
-rw-r--r--WINDOWS/WINSTUFF.H704
-rw-r--r--WINDOWS/WINTIME.C26
-rw-r--r--WINDOWS/WINUCS.C1213
-rw-r--r--WINDOWS/WINUTILS.C788
-rw-r--r--WINDOWS/WINX11.C19
-rw-r--r--WINDOWS/WIN_RES.H49
-rw-r--r--WINDOWS/WIN_RES.RC2137
-rw-r--r--WINDOWS/installer.wxs15
-rw-r--r--WINDOWS/wincapi.c93
-rw-r--r--WINDOWS/wincapi.h31
-rw-r--r--WINDOWS/wincliloop.c136
-rw-r--r--WINDOWS/winhelp.rc28
-rw-r--r--WINDOWS/winhsock.c343
-rw-r--r--WINDOWS/winmiscs.c285
-rw-r--r--WINDOWS/winnohlp.c15
-rw-r--r--WINDOWS/winnpc.c98
-rw-r--r--WINDOWS/winnps.c240
-rw-r--r--WINDOWS/winseat.h14
-rw-r--r--WINDOWS/winsecur.c334
-rw-r--r--WINDOWS/winsecur.h53
-rw-r--r--WINDOWS/winselcli.c78
-rw-r--r--WINDOWS/winselgui.c38
-rw-r--r--WINDOWS/winshare.c151
-rw-r--r--WINDOWS/winsocks.c24
53 files changed, 442 insertions, 21591 deletions
diff --git a/WINDOWS/PAGEANT.RC b/WINDOWS/PAGEANT.RC
index a4a15195..1bea78b4 100644
--- a/WINDOWS/PAGEANT.RC
+++ b/WINDOWS/PAGEANT.RC
@@ -9,7 +9,7 @@
#include "pageant-rc.h"
-#include "winhelp.rc2"
+#include "help.rc2"
IDI_MAINICON ICON "pageant.ico"
IDI_TRAYICON ICON "pageants.ico"
@@ -51,8 +51,8 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Pageant Key List"
FONT 8, "MS Shell Dlg"
BEGIN
- LISTBOX 100, 10, 10, 420, 155,
- LBS_EXTENDEDSEL | LBS_HASSTRINGS | LBS_USETABSTOPS | WS_VSCROLL | WS_TABSTOP
+ LISTBOX IDC_KEYLIST_LISTBOX, 10, 10, 420, 155,
+ LBS_EXTENDEDSEL | LBS_OWNERDRAWFIXED | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "&Add Key", IDC_KEYLIST_ADDKEY, 10, 187, 60, 14
PUSHBUTTON "Add Key (&encrypted)", IDC_KEYLIST_ADDKEY_ENC, 75, 187, 80, 14
PUSHBUTTON "Re-e&ncrypt", IDC_KEYLIST_REENCRYPT, 315, 187, 60, 14
@@ -60,7 +60,7 @@ BEGIN
PUSHBUTTON "&Help", IDC_KEYLIST_HELP, 10, 212, 50, 14
DEFPUSHBUTTON "&Close", IDOK, 390, 212, 50, 14
LTEXT "&Fingerprint type:", IDC_KEYLIST_FPTYPE_STATIC, 10, 172, 60, 8
- COMBOBOX IDC_KEYLIST_FPTYPE, 70, 170, 60, 12, CBS_DROPDOWNLIST
+ COMBOBOX IDC_KEYLIST_FPTYPE, 70, 170, 100, 12, CBS_DROPDOWNLIST
END
/* Accelerators used: cl */
diff --git a/WINDOWS/PUTTY.RC b/WINDOWS/PUTTY.RC
index 14f62f48..b8df49f2 100644
--- a/WINDOWS/PUTTY.RC
+++ b/WINDOWS/PUTTY.RC
@@ -1,10 +1,14 @@
#include "rcstuff.h"
+#include "putty-rc.h"
#define APPNAME "PuTTYNG"
#define APPDESC "SSH, Telnet, Rlogin, and SUPDUP client"
-#include "winhelp.rc2"
-#include "win_res.rc2"
+IDI_MAINICON ICON "putty.ico"
+IDI_CFGICON ICON "puttycfg.ico"
+
+#include "help.rc2"
+#include "putty-common.rc2"
#ifndef NO_MANIFESTS
1 RT_MANIFEST "putty.mft"
diff --git a/WINDOWS/PUTTYGEN.RC b/WINDOWS/PUTTYGEN.RC
index b910b6a3..fbe14fc3 100644
--- a/WINDOWS/PUTTYGEN.RC
+++ b/WINDOWS/PUTTYGEN.RC
@@ -7,7 +7,7 @@
#define APPNAME "PuTTYgen"
#define APPDESC "PuTTY SSH key generation utility"
-#include "winhelp.rc2"
+#include "help.rc2"
#include "puttygen-rc.h"
200 ICON "puttygen.ico"
@@ -82,6 +82,16 @@ BEGIN
PUSHBUTTON "&Cancel", IDCANCEL, 134, 80, 40, 14
END
+/* Accelerators used: clw */
+216 DIALOG DISCARDABLE 140, 40, 450, 300
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "PuTTYgen: certificate information"
+FONT 8, "MS Shell Dlg"
+CLASS "PuTTYgenCertInfo"
+BEGIN
+ DEFPUSHBUTTON "&Close", IDOK, 201, 130, 48, 14
+END
+
#include "version.rc2"
#ifndef NO_MANIFESTS
diff --git a/WINDOWS/PUTTYTEL.RC b/WINDOWS/PUTTYTEL.RC
index 259bc683..41767a10 100644
--- a/WINDOWS/PUTTYTEL.RC
+++ b/WINDOWS/PUTTYTEL.RC
@@ -1,10 +1,14 @@
#include "rcstuff.h"
+#include "putty-rc.h"
#define APPNAME "PuTTYtel"
#define APPDESC "Telnet and Rlogin client"
-#include "winhelp.rc2"
-#include "win_res.rc2"
+IDI_MAINICON ICON "putty.ico"
+IDI_CFGICON ICON "puttycfg.ico"
+
+#include "help.rc2"
+#include "putty-common.rc2"
#ifndef NO_MANIFESTS
1 RT_MANIFEST "puttytel.mft"
diff --git a/WINDOWS/RCSTUFF.H b/WINDOWS/RCSTUFF.H
index ee2c7696..dbace3f5 100644
--- a/WINDOWS/RCSTUFF.H
+++ b/WINDOWS/RCSTUFF.H
@@ -5,20 +5,15 @@
#ifndef PUTTY_RCSTUFF_H
#define PUTTY_RCSTUFF_H
-#ifdef __LCC__
-#include <win.h>
-#else
+#ifdef HAVE_CMAKE_H
+#include "cmake.h"
+#endif
-/* Some compilers don't have winresrc.h */
-#ifndef NO_WINRESRC_H
-#ifndef MSVC4
+#if HAVE_WINRESRC_H
#include <winresrc.h>
-#else
+#elif HAVE_WINRES_H
#include <winres.h>
#endif
-#endif
-
-#endif /* end #ifdef __LCC__ */
/* Some systems don't define this, so I do it myself if necessary */
#ifndef TCS_MULTILINE
diff --git a/WINDOWS/WINCFG.C b/WINDOWS/WINCFG.C
deleted file mode 100644
index fab3240f..00000000
--- a/WINDOWS/WINCFG.C
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * wincfg.c - the Windows-specific parts of the PuTTY configuration
- * box.
- */
-
-#include <assert.h>
-#include <stdlib.h>
-
-#include "putty.h"
-#include "dialog.h"
-#include "storage.h"
-
-static void about_handler(union control *ctrl, dlgparam *dlg,
- void *data, int event)
-{
- HWND *hwndp = (HWND *)ctrl->generic.context.p;
-
- if (event == EVENT_ACTION) {
- modal_about_box(*hwndp);
- }
-}
-
-static void help_handler(union control *ctrl, dlgparam *dlg,
- void *data, int event)
-{
- HWND *hwndp = (HWND *)ctrl->generic.context.p;
-
- if (event == EVENT_ACTION) {
- show_help(*hwndp);
- }
-}
-
-static void variable_pitch_handler(union control *ctrl, dlgparam *dlg,
- void *data, int event)
-{
- if (event == EVENT_REFRESH) {
- dlg_checkbox_set(ctrl, dlg, !dlg_get_fixed_pitch_flag(dlg));
- } else if (event == EVENT_VALCHANGE) {
- dlg_set_fixed_pitch_flag(dlg, !dlg_checkbox_get(ctrl, dlg));
- }
-}
-
-void win_setup_config_box(struct controlbox *b, HWND *hwndp, bool has_help,
- bool midsession, int protocol)
-{
- const struct BackendVtable *backvt;
- bool resize_forbidden = false;
- struct controlset *s;
- union control *c;
- char *str;
-
- if (!midsession) {
- /*
- * Add the About and Help buttons to the standard panel.
- */
- s = ctrl_getset(b, "", "", "");
- c = ctrl_pushbutton(s, "About", 'a', HELPCTX(no_help),
- about_handler, P(hwndp));
- c->generic.column = 0;
- if (has_help) {
- c = ctrl_pushbutton(s, "Help", 'h', HELPCTX(no_help),
- help_handler, P(hwndp));
- c->generic.column = 1;
- }
- }
-
- /*
- * Full-screen mode is a Windows peculiarity; hence
- * scrollbar_in_fullscreen is as well.
- */
- s = ctrl_getset(b, "Window", "scrollback",
- "Control the scrollback in the window");
- ctrl_checkbox(s, "Display scrollbar in full screen mode", 'i',
- HELPCTX(window_scrollback),
- conf_checkbox_handler,
- I(CONF_scrollbar_in_fullscreen));
- /*
- * Really this wants to go just after `Display scrollbar'. See
- * if we can find that control, and do some shuffling.
- */
- {
- int i;
- for (i = 0; i < s->ncontrols; i++) {
- c = s->ctrls[i];
- if (c->generic.type == CTRL_CHECKBOX &&
- c->generic.context.i == CONF_scrollbar) {
- /*
- * Control i is the scrollbar checkbox.
- * Control s->ncontrols-1 is the scrollbar-in-FS one.
- */
- if (i < s->ncontrols-2) {
- c = s->ctrls[s->ncontrols-1];
- memmove(s->ctrls+i+2, s->ctrls+i+1,
- (s->ncontrols-i-2)*sizeof(union control *));
- s->ctrls[i+1] = c;
- }
- break;
- }
- }
- }
-
- /*
- * Windows has the AltGr key, which has various Windows-
- * specific options.
- */
- s = ctrl_getset(b, "Terminal/Keyboard", "features",
- "Enable extra keyboard features:");
- ctrl_checkbox(s, "AltGr acts as Compose key", 't',
- HELPCTX(keyboard_compose),
- conf_checkbox_handler, I(CONF_compose_key));
- ctrl_checkbox(s, "Control-Alt is different from AltGr", 'd',
- HELPCTX(keyboard_ctrlalt),
- conf_checkbox_handler, I(CONF_ctrlaltkeys));
-
- /*
- * Windows allows an arbitrary .WAV to be played as a bell, and
- * also the use of the PC speaker. For this we must search the
- * existing controlset for the radio-button set controlling the
- * `beep' option, and add extra buttons to it.
- *
- * Note that although this _looks_ like a hideous hack, it's
- * actually all above board. The well-defined interface to the
- * per-platform dialog box code is the _data structures_ `union
- * control', `struct controlset' and so on; so code like this
- * that reaches into those data structures and changes bits of
- * them is perfectly legitimate and crosses no boundaries. All
- * the ctrl_* routines that create most of the controls are
- * convenient shortcuts provided on the cross-platform side of
- * the interface, and template creation code is under no actual
- * obligation to use them.
- */
- s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
- {
- int i;
- for (i = 0; i < s->ncontrols; i++) {
- c = s->ctrls[i];
- if (c->generic.type == CTRL_RADIO &&
- c->generic.context.i == CONF_beep) {
- assert(c->generic.handler == conf_radiobutton_handler);
- c->radio.nbuttons += 2;
- c->radio.buttons =
- sresize(c->radio.buttons, c->radio.nbuttons, char *);
- c->radio.buttons[c->radio.nbuttons-1] =
- dupstr("Play a custom sound file");
- c->radio.buttons[c->radio.nbuttons-2] =
- dupstr("Beep using the PC speaker");
- c->radio.buttondata =
- sresize(c->radio.buttondata, c->radio.nbuttons, intorptr);
- c->radio.buttondata[c->radio.nbuttons-1] = I(BELL_WAVEFILE);
- c->radio.buttondata[c->radio.nbuttons-2] = I(BELL_PCSPEAKER);
- if (c->radio.shortcuts) {
- c->radio.shortcuts =
- sresize(c->radio.shortcuts, c->radio.nbuttons, char);
- c->radio.shortcuts[c->radio.nbuttons-1] = NO_SHORTCUT;
- c->radio.shortcuts[c->radio.nbuttons-2] = NO_SHORTCUT;
- }
- break;
- }
- }
- }
- ctrl_filesel(s, "Custom sound file to play as a bell:", NO_SHORTCUT,
- FILTER_WAVE_FILES, false, "Select bell sound file",
- HELPCTX(bell_style),
- conf_filesel_handler, I(CONF_bell_wavefile));
-
- /*
- * While we've got this box open, taskbar flashing on a bell is
- * also Windows-specific.
- */
- ctrl_radiobuttons(s, "Taskbar/caption indication on bell:", 'i', 3,
- HELPCTX(bell_taskbar),
- conf_radiobutton_handler,
- I(CONF_beep_ind),
- "Disabled", I(B_IND_DISABLED),
- "Flashing", I(B_IND_FLASH),
- "Steady", I(B_IND_STEADY), NULL);
-
- /*
- * The sunken-edge border is a Windows GUI feature.
- */
- s = ctrl_getset(b, "Window/Appearance", "border",
- "Adjust the window border");
- ctrl_checkbox(s, "Sunken-edge border (slightly thicker)", 's',
- HELPCTX(appearance_border),
- conf_checkbox_handler, I(CONF_sunken_edge));
-
- /*
- * Configurable font quality settings for Windows.
- */
- s = ctrl_getset(b, "Window/Appearance", "font",
- "Font settings");
- ctrl_checkbox(s, "Allow selection of variable-pitch fonts", NO_SHORTCUT,
- HELPCTX(appearance_font), variable_pitch_handler, I(0));
- ctrl_radiobuttons(s, "Font quality:", 'q', 2,
- HELPCTX(appearance_font),
- conf_radiobutton_handler,
- I(CONF_font_quality),
- "Antialiased", I(FQ_ANTIALIASED),
- "Non-Antialiased", I(FQ_NONANTIALIASED),
- "ClearType", I(FQ_CLEARTYPE),
- "Default", I(FQ_DEFAULT), NULL);
-
- /*
- * Cyrillic Lock is a horrid misfeature even on Windows, and
- * the least we can do is ensure it never makes it to any other
- * platform (at least unless someone fixes it!).
- */
- s = ctrl_getset(b, "Window/Translation", "tweaks", NULL);
- ctrl_checkbox(s, "Caps Lock acts as Cyrillic switch", 's',
- HELPCTX(translation_cyrillic),
- conf_checkbox_handler,
- I(CONF_xlat_capslockcyr));
-
- /*
- * On Windows we can use but not enumerate translation tables
- * from the operating system. Briefly document this.
- */
- s = ctrl_getset(b, "Window/Translation", "trans",
- "Character set translation on received data");
- ctrl_text(s, "(Codepages supported by Windows but not listed here, "
- "such as CP866 on many systems, can be entered manually)",
- HELPCTX(translation_codepage));
-
- /*
- * Windows has the weird OEM font mode, which gives us some
- * additional options when working with line-drawing
- * characters.
- */
- str = dupprintf("Adjust how %s displays line drawing characters", appname);
- s = ctrl_getset(b, "Window/Translation", "linedraw", str);
- sfree(str);
- {
- int i;
- for (i = 0; i < s->ncontrols; i++) {
- c = s->ctrls[i];
- if (c->generic.type == CTRL_RADIO &&
- c->generic.context.i == CONF_vtmode) {
- assert(c->generic.handler == conf_radiobutton_handler);
- c->radio.nbuttons += 3;
- c->radio.buttons =
- sresize(c->radio.buttons, c->radio.nbuttons, char *);
- c->radio.buttons[c->radio.nbuttons-3] =
- dupstr("Font has XWindows encoding");
- c->radio.buttons[c->radio.nbuttons-2] =
- dupstr("Use font in both ANSI and OEM modes");
- c->radio.buttons[c->radio.nbuttons-1] =
- dupstr("Use font in OEM mode only");
- c->radio.buttondata =
- sresize(c->radio.buttondata, c->radio.nbuttons, intorptr);
- c->radio.buttondata[c->radio.nbuttons-3] = I(VT_XWINDOWS);
- c->radio.buttondata[c->radio.nbuttons-2] = I(VT_OEMANSI);
- c->radio.buttondata[c->radio.nbuttons-1] = I(VT_OEMONLY);
- if (!c->radio.shortcuts) {
- int j;
- c->radio.shortcuts = snewn(c->radio.nbuttons, char);
- for (j = 0; j < c->radio.nbuttons; j++)
- c->radio.shortcuts[j] = NO_SHORTCUT;
- } else {
- c->radio.shortcuts = sresize(c->radio.shortcuts,
- c->radio.nbuttons, char);
- }
- c->radio.shortcuts[c->radio.nbuttons-3] = 'x';
- c->radio.shortcuts[c->radio.nbuttons-2] = 'b';
- c->radio.shortcuts[c->radio.nbuttons-1] = 'e';
- break;
- }
- }
- }
-
- /*
- * RTF paste is Windows-specific.
- */
- s = ctrl_getset(b, "Window/Selection/Copy", "format",
- "Formatting of copied characters");
- ctrl_checkbox(s, "Copy to clipboard in RTF as well as plain text", 'f',
- HELPCTX(copy_rtf),
- conf_checkbox_handler, I(CONF_rtf_paste));
-
- /*
- * Windows often has no middle button, so we supply a selection
- * mode in which the more critical Paste action is available on
- * the right button instead.
- */
- s = ctrl_getset(b, "Window/Selection", "mouse",
- "Control use of mouse");
- ctrl_radiobuttons(s, "Action of mouse buttons:", 'm', 1,
- HELPCTX(selection_buttons),
- conf_radiobutton_handler,
- I(CONF_mouse_is_xterm),
- "Windows (Middle extends, Right brings up menu)", I(2),
- "Compromise (Middle extends, Right pastes)", I(0),
- "xterm (Right extends, Middle pastes)", I(1), NULL);
- /*
- * This really ought to go at the _top_ of its box, not the
- * bottom, so we'll just do some shuffling now we've set it
- * up...
- */
- c = s->ctrls[s->ncontrols-1]; /* this should be the new control */
- memmove(s->ctrls+1, s->ctrls, (s->ncontrols-1)*sizeof(union control *));
- s->ctrls[0] = c;
-
- /*
- * Logical palettes don't even make sense anywhere except Windows.
- */
- s = ctrl_getset(b, "Window/Colours", "general",
- "General options for colour usage");
- ctrl_checkbox(s, "Attempt to use logical palettes", 'l',
- HELPCTX(colours_logpal),
- conf_checkbox_handler, I(CONF_try_palette));
- ctrl_checkbox(s, "Use system colours", 's',
- HELPCTX(colours_system),
- conf_checkbox_handler, I(CONF_system_colour));
-
-
- /*
- * Resize-by-changing-font is a Windows insanity.
- */
-
- backvt = backend_vt_from_proto(protocol);
- if (backvt)
- resize_forbidden = (backvt->flags & BACKEND_RESIZE_FORBIDDEN);
- if (!midsession || !resize_forbidden) {
- s = ctrl_getset(b, "Window", "size", "Set the size of the window");
- ctrl_radiobuttons(s, "When window is resized:", 'z', 1,
- HELPCTX(window_resize),
- conf_radiobutton_handler,
- I(CONF_resize_action),
- "Change the number of rows and columns", I(RESIZE_TERM),
- "Change the size of the font", I(RESIZE_FONT),
- "Change font size only when maximised", I(RESIZE_EITHER),
- "Forbid resizing completely", I(RESIZE_DISABLED), NULL);
- }
-
- /*
- * Most of the Window/Behaviour stuff is there to mimic Windows
- * conventions which PuTTY can optionally disregard. Hence,
- * most of these options are Windows-specific.
- */
- s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
- ctrl_checkbox(s, "Window closes on ALT-F4", '4',
- HELPCTX(behaviour_altf4),
- conf_checkbox_handler, I(CONF_alt_f4));
- ctrl_checkbox(s, "System menu appears on ALT-Space", 'y',
- HELPCTX(behaviour_altspace),
- conf_checkbox_handler, I(CONF_alt_space));
- ctrl_checkbox(s, "System menu appears on ALT alone", 'l',
- HELPCTX(behaviour_altonly),
- conf_checkbox_handler, I(CONF_alt_only));
- ctrl_checkbox(s, "Ensure window is always on top", 'e',
- HELPCTX(behaviour_alwaysontop),
- conf_checkbox_handler, I(CONF_alwaysontop));
- ctrl_checkbox(s, "Full screen on Alt-Enter", 'f',
- HELPCTX(behaviour_altenter),
- conf_checkbox_handler,
- I(CONF_fullscreenonaltenter));
-
- /*
- * Windows supports a local-command proxy. This also means we
- * must adjust the text on the `Telnet command' control.
- */
- if (!midsession) {
- int i;
- s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
- for (i = 0; i < s->ncontrols; i++) {
- c = s->ctrls[i];
- if (c->generic.type == CTRL_RADIO &&
- c->generic.context.i == CONF_proxy_type) {
- assert(c->generic.handler == conf_radiobutton_handler);
- c->radio.nbuttons++;
- c->radio.buttons =
- sresize(c->radio.buttons, c->radio.nbuttons, char *);
- c->radio.buttons[c->radio.nbuttons-1] =
- dupstr("Local");
- c->radio.buttondata =
- sresize(c->radio.buttondata, c->radio.nbuttons, intorptr);
- c->radio.buttondata[c->radio.nbuttons-1] = I(PROXY_CMD);
- break;
- }
- }
-
- for (i = 0; i < s->ncontrols; i++) {
- c = s->ctrls[i];
- if (c->generic.type == CTRL_EDITBOX &&
- c->generic.context.i == CONF_proxy_telnet_command) {
- assert(c->generic.handler == conf_editbox_handler);
- sfree(c->generic.label);
- c->generic.label = dupstr("Telnet command, or local"
- " proxy command");
- break;
- }
- }
- }
-
- /*
- * $XAUTHORITY is not reliable on Windows, so we provide a
- * means to override it.
- */
- if (!midsession && backend_vt_from_proto(PROT_SSH)) {
- s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
- ctrl_filesel(s, "X authority file for local display", 't',
- NULL, false, "Select X authority file",
- HELPCTX(ssh_tunnels_xauthority),
- conf_filesel_handler, I(CONF_xauthfile));
- }
-}
diff --git a/WINDOWS/WINCONS.C b/WINDOWS/WINCONS.C
deleted file mode 100644
index 414167b4..00000000
--- a/WINDOWS/WINCONS.C
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * wincons.c - various interactive-prompt routines shared between
- * the Windows console PuTTY tools
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "putty.h"
-#include "storage.h"
-#include "ssh.h"
-#include "console.h"
-
-void cleanup_exit(int code)
-{
- /*
- * Clean up.
- */
- sk_cleanup();
-
- random_save_seed();
-
- exit(code);
-}
-
-void console_print_error_msg(const char *prefix, const char *msg)
-{
- fputs(prefix, stderr);
- fputs(": ", stderr);
- fputs(msg, stderr);
- fputc('\n', stderr);
- fflush(stderr);
-}
-
-int console_verify_ssh_host_key(
- Seat *seat, const char *host, int port, const char *keytype,
- char *keystr, const char *keydisp, char **fingerprints,
- void (*callback)(void *ctx, int result), void *ctx)
-{
- int ret;
- HANDLE hin;
- DWORD savemode, i;
- const char *common_fmt, *intro, *prompt;
-
- char line[32];
-
- /*
- * Verify the key against the registry.
- */
- ret = verify_host_key(host, port, keytype, keystr);
-
- if (ret == 0) /* success - key matched OK */
- return 1;
-
- if (ret == 2) { /* key was different */
- common_fmt = hk_wrongmsg_common_fmt;
- intro = hk_wrongmsg_interactive_intro;
- prompt = hk_wrongmsg_interactive_prompt;
- } else { /* key was absent */
- common_fmt = hk_absentmsg_common_fmt;
- intro = hk_absentmsg_interactive_intro;
- prompt = hk_absentmsg_interactive_prompt;
- }
-
- FingerprintType fptype_default =
- ssh2_pick_default_fingerprint(fingerprints);
-
- fprintf(stderr, common_fmt, keytype, fingerprints[fptype_default]);
- if (console_batch_mode) {
- fputs(console_abandoned_msg, stderr);
- return 0;
- }
-
- fputs(intro, stderr);
- fflush(stderr);
-
- while (true) {
- fputs(prompt, stderr);
- fflush(stderr);
-
- line[0] = '\0'; /* fail safe if ReadFile returns no data */
-
- hin = GetStdHandle(STD_INPUT_HANDLE);
- GetConsoleMode(hin, &savemode);
- SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
- ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
- ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
- SetConsoleMode(hin, savemode);
-
- if (line[0] == 'i' || line[0] == 'I') {
- fprintf(stderr, "Full public key:\n%s\n", keydisp);
- if (fingerprints[SSH_FPTYPE_SHA256])
- fprintf(stderr, "SHA256 key fingerprint:\n%s\n",
- fingerprints[SSH_FPTYPE_SHA256]);
- if (fingerprints[SSH_FPTYPE_MD5])
- fprintf(stderr, "MD5 key fingerprint:\n%s\n",
- fingerprints[SSH_FPTYPE_MD5]);
- } else {
- break;
- }
- }
-
- /* In case of misplaced reflexes from another program, also recognise 'q'
- * as 'abandon connection rather than trust this key' */
- if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n' &&
- line[0] != 'q' && line[0] != 'Q') {
- if (line[0] == 'y' || line[0] == 'Y')
- store_host_key(host, port, keytype, keystr);
- return 1;
- } else {
- fputs(console_abandoned_msg, stderr);
- return 0;
- }
-}
-
-int console_confirm_weak_crypto_primitive(
- Seat *seat, const char *algtype, const char *algname,
- void (*callback)(void *ctx, int result), void *ctx)
-{
- HANDLE hin;
- DWORD savemode, i;
-
- char line[32];
-
- fprintf(stderr, weakcrypto_msg_common_fmt, algtype, algname);
-
- if (console_batch_mode) {
- fputs(console_abandoned_msg, stderr);
- return 0;
- }
-
- fputs(console_continue_prompt, stderr);
- fflush(stderr);
-
- hin = GetStdHandle(STD_INPUT_HANDLE);
- GetConsoleMode(hin, &savemode);
- SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
- ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
- ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
- SetConsoleMode(hin, savemode);
-
- if (line[0] == 'y' || line[0] == 'Y') {
- return 1;
- } else {
- fputs(console_abandoned_msg, stderr);
- return 0;
- }
-}
-
-int console_confirm_weak_cached_hostkey(
- Seat *seat, const char *algname, const char *betteralgs,
- void (*callback)(void *ctx, int result), void *ctx)
-{
- HANDLE hin;
- DWORD savemode, i;
-
- char line[32];
-
- fprintf(stderr, weakhk_msg_common_fmt, algname, betteralgs);
-
- if (console_batch_mode) {
- fputs(console_abandoned_msg, stderr);
- return 0;
- }
-
- fputs(console_continue_prompt, stderr);
- fflush(stderr);
-
- hin = GetStdHandle(STD_INPUT_HANDLE);
- GetConsoleMode(hin, &savemode);
- SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
- ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
- ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
- SetConsoleMode(hin, savemode);
-
- if (line[0] == 'y' || line[0] == 'Y') {
- return 1;
- } else {
- fputs(console_abandoned_msg, stderr);
- return 0;
- }
-}
-
-bool is_interactive(void)
-{
- return is_console_handle(GetStdHandle(STD_INPUT_HANDLE));
-}
-
-bool console_antispoof_prompt = true;
-bool console_set_trust_status(Seat *seat, bool trusted)
-{
- if (console_batch_mode || !is_interactive() || !console_antispoof_prompt) {
- /*
- * In batch mode, we don't need to worry about the server
- * mimicking our interactive authentication, because the user
- * already knows not to expect any.
- *
- * If standard input isn't connected to a terminal, likewise,
- * because even if the server did send a spoof authentication
- * prompt, the user couldn't respond to it via the terminal
- * anyway.
- *
- * We also vacuously return success if the user has purposely
- * disabled the antispoof prompt.
- */
- return true;
- }
-
- return false;
-}
-
-/*
- * Ask whether to wipe a session log file before writing to it.
- * Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
- */
-int console_askappend(LogPolicy *lp, Filename *filename,
- void (*callback)(void *ctx, int result), void *ctx)
-{
- HANDLE hin;
- DWORD savemode, i;
-
- static const char msgtemplate[] =
- "The session log file \"%.*s\" already exists.\n"
- "You can overwrite it with a new session log,\n"
- "append your session log to the end of it,\n"
- "or disable session logging for this session.\n"
- "Enter \"y\" to wipe the file, \"n\" to append to it,\n"
- "or just press Return to disable logging.\n"
- "Wipe the log file? (y/n, Return cancels logging) ";
-
- static const char msgtemplate_batch[] =
- "The session log file \"%.*s\" already exists.\n"
- "Logging will not be enabled.\n";
-
- char line[32];
-
- if (console_batch_mode) {
- fprintf(stderr, msgtemplate_batch, FILENAME_MAX, filename->path);
- fflush(stderr);
- return 0;
- }
- fprintf(stderr, msgtemplate, FILENAME_MAX, filename->path);
- fflush(stderr);
-
- hin = GetStdHandle(STD_INPUT_HANDLE);
- GetConsoleMode(hin, &savemode);
- SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
- ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
- ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
- SetConsoleMode(hin, savemode);
-
- if (line[0] == 'y' || line[0] == 'Y')
- return 2;
- else if (line[0] == 'n' || line[0] == 'N')
- return 1;
- else
- return 0;
-}
-
-/*
- * Warn about the obsolescent key file format.
- *
- * Uniquely among these functions, this one does _not_ expect a
- * frontend handle. This means that if PuTTY is ported to a
- * platform which requires frontend handles, this function will be
- * an anomaly. Fortunately, the problem it addresses will not have
- * been present on that platform, so it can plausibly be
- * implemented as an empty function.
- */
-void old_keyfile_warning(void)
-{
- static const char message[] =
- "You are loading an SSH-2 private key which has an\n"
- "old version of the file format. This means your key\n"
- "file is not fully tamperproof. Future versions of\n"
- "PuTTY may stop supporting this private key format,\n"
- "so we recommend you convert your key to the new\n"
- "format.\n"
- "\n"
- "Once the key is loaded into PuTTYgen, you can perform\n"
- "this conversion simply by saving it again.\n";
-
- fputs(message, stderr);
-}
-
-/*
- * Display the fingerprints of the PGP Master Keys to the user.
- */
-void pgp_fingerprints(void)
-{
- fputs("These are the fingerprints of the PuTTY PGP Master Keys. They can\n"
- "be used to establish a trust path from this executable to another\n"
- "one. See the manual for more information.\n"
- "(Note: these fingerprints have nothing to do with SSH!)\n"
- "\n"
- "PuTTY Master Key as of " PGP_MASTER_KEY_YEAR
- " (" PGP_MASTER_KEY_DETAILS "):\n"
- " " PGP_MASTER_KEY_FP "\n\n"
- "Previous Master Key (" PGP_PREV_MASTER_KEY_YEAR
- ", " PGP_PREV_MASTER_KEY_DETAILS "):\n"
- " " PGP_PREV_MASTER_KEY_FP "\n", stdout);
-}
-
-void console_logging_error(LogPolicy *lp, const char *string)
-{
- /* Ordinary Event Log entries are displayed in the same way as
- * logging errors, but only in verbose mode */
- fprintf(stderr, "%s\n", string);
- fflush(stderr);
-}
-
-void console_eventlog(LogPolicy *lp, const char *string)
-{
- /* Ordinary Event Log entries are displayed in the same way as
- * logging errors, but only in verbose mode */
- if (lp_verbose(lp))
- console_logging_error(lp, string);
-}
-
-StripCtrlChars *console_stripctrl_new(
- Seat *seat, BinarySink *bs_out, SeatInteractionContext sic)
-{
- return stripctrl_new(bs_out, false, 0);
-}
-
-static void console_write(HANDLE hout, ptrlen data)
-{
- DWORD dummy;
- WriteFile(hout, data.ptr, data.len, &dummy, NULL);
-}
-
-int console_get_userpass_input(prompts_t *p)
-{
- HANDLE hin = INVALID_HANDLE_VALUE, hout = INVALID_HANDLE_VALUE;
- size_t curr_prompt;
-
- /*
- * Zero all the results, in case we abort half-way through.
- */
- {
- int i;
- for (i = 0; i < (int)p->n_prompts; i++)
- prompt_set_result(p->prompts[i], "");
- }
-
- /*
- * The prompts_t might contain a message to be displayed but no
- * actual prompt. More usually, though, it will contain
- * questions that the user needs to answer, in which case we
- * need to ensure that we're able to get the answers.
- */
- if (p->n_prompts) {
- if (console_batch_mode)
- return 0;
- hin = GetStdHandle(STD_INPUT_HANDLE);
- if (hin == INVALID_HANDLE_VALUE) {
- fprintf(stderr, "Cannot get standard input handle\n");
- cleanup_exit(1);
- }
- }
-
- /*
- * And if we have anything to print, we need standard output.
- */
- if ((p->name_reqd && p->name) || p->instruction || p->n_prompts) {
- hout = GetStdHandle(STD_OUTPUT_HANDLE);
- if (hout == INVALID_HANDLE_VALUE) {
- fprintf(stderr, "Cannot get standard output handle\n");
- cleanup_exit(1);
- }
- }
-
- /*
- * Preamble.
- */
- /* We only print the `name' caption if we have to... */
- if (p->name_reqd && p->name) {
- ptrlen plname = ptrlen_from_asciz(p->name);
- console_write(hout, plname);
- if (!ptrlen_endswith(plname, PTRLEN_LITERAL("\n"), NULL))
- console_write(hout, PTRLEN_LITERAL("\n"));
- }
- /* ...but we always print any `instruction'. */
- if (p->instruction) {
- ptrlen plinst = ptrlen_from_asciz(p->instruction);
- console_write(hout, plinst);
- if (!ptrlen_endswith(plinst, PTRLEN_LITERAL("\n"), NULL))
- console_write(hout, PTRLEN_LITERAL("\n"));
- }
-
- for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) {
-
- DWORD savemode, newmode;
- prompt_t *pr = p->prompts[curr_prompt];
-
- GetConsoleMode(hin, &savemode);
- newmode = savemode | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT;
- if (!pr->echo)
- newmode &= ~ENABLE_ECHO_INPUT;
- else
- newmode |= ENABLE_ECHO_INPUT;
- SetConsoleMode(hin, newmode);
-
- console_write(hout, ptrlen_from_asciz(pr->prompt));
-
- bool failed = false;
- while (1) {
- /*
- * Amount of data to try to read from the console in one
- * go. This isn't completely arbitrary: a user reported
- * that trying to read more than 31366 bytes at a time
- * would fail with ERROR_NOT_ENOUGH_MEMORY on Windows 7,
- * and Ruby's Win32 support module has evidence of a
- * similar workaround:
- *
- * https://github.com/ruby/ruby/blob/0aa5195262d4193d3accf3e6b9bad236238b816b/win32/win32.c#L6842
- *
- * To keep things simple, I stick with a nice round power
- * of 2 rather than trying to go to the very limit of that
- * bug. (We're typically reading user passphrases and the
- * like here, so even this much is overkill really.)
- */
- DWORD toread = 16384;
-
- size_t prev_result_len = pr->result->len;
- void *ptr = strbuf_append(pr->result, toread);
-
- DWORD ret = 0;
- if (!ReadFile(hin, ptr, toread, &ret, NULL) || ret == 0) {
- failed = true;
- break;
- }
-
- strbuf_shrink_to(pr->result, prev_result_len + ret);
- if (strbuf_chomp(pr->result, '\n')) {
- strbuf_chomp(pr->result, '\r');
- break;
- }
- }
-
- SetConsoleMode(hin, savemode);
-
- if (!pr->echo)
- console_write(hout, PTRLEN_LITERAL("\r\n"));
-
- if (failed) {
- return 0; /* failure due to read error */
- }
- }
-
- return 1; /* success */
-}
diff --git a/WINDOWS/WINCTRLS.C b/WINDOWS/WINCTRLS.C
deleted file mode 100644
index 59129eab..00000000
--- a/WINDOWS/WINCTRLS.C
+++ /dev/null
@@ -1,2600 +0,0 @@
-/*
- * winctrls.c: routines to self-manage the controls in a dialog
- * box.
- */
-
-/*
- * Possible TODO in new cross-platform config box stuff:
- *
- * - When lining up two controls alongside each other, I wonder if
- * we could conveniently arrange to centre them vertically?
- * Particularly ugly in the current setup is the `Add new
- * forwarded port:' static next to the rather taller `Remove'
- * button.
- */
-
-#include <assert.h>
-#include <ctype.h>
-
-#include "putty.h"
-#include "misc.h"
-#include "dialog.h"
-
-#include <commctrl.h>
-
-#define GAPBETWEEN 3
-#define GAPWITHIN 1
-#define GAPXBOX 7
-#define GAPYBOX 4
-#define DLGWIDTH 168
-#define STATICHEIGHT 8
-#define TITLEHEIGHT 12
-#define CHECKBOXHEIGHT 8
-#define RADIOHEIGHT 8
-#define EDITHEIGHT 12
-#define LISTHEIGHT 11
-#define LISTINCREMENT 8
-#define COMBOHEIGHT 12
-#define PUSHBTNHEIGHT 14
-#define PROGBARHEIGHT 14
-
-DECL_WINDOWS_FUNCTION(static, void, InitCommonControls, (void));
-DECL_WINDOWS_FUNCTION(static, BOOL, MakeDragList, (HWND));
-DECL_WINDOWS_FUNCTION(static, int, LBItemFromPt, (HWND, POINT, BOOL));
-DECL_WINDOWS_FUNCTION(static, void, DrawInsert, (HWND, HWND, int));
-
-void init_common_controls(void)
-{
- HMODULE comctl32_module = load_system32_dll("comctl32.dll");
- GET_WINDOWS_FUNCTION(comctl32_module, InitCommonControls);
- GET_WINDOWS_FUNCTION(comctl32_module, MakeDragList);
- GET_WINDOWS_FUNCTION(comctl32_module, LBItemFromPt);
- GET_WINDOWS_FUNCTION(comctl32_module, DrawInsert);
- p_InitCommonControls();
-}
-
-void ctlposinit(struct ctlpos *cp, HWND hwnd,
- int leftborder, int rightborder, int topborder)
-{
- RECT r, r2;
- cp->hwnd = hwnd;
- cp->font = SendMessage(hwnd, WM_GETFONT, 0, 0);
- cp->ypos = topborder;
- GetClientRect(hwnd, &r);
- r2.left = r2.top = 0;
- r2.right = 4;
- r2.bottom = 8;
- MapDialogRect(hwnd, &r2);
- cp->dlu4inpix = r2.right;
- cp->width = (r.right * 4) / (r2.right) - 2 * GAPBETWEEN;
- cp->xoff = leftborder;
- cp->width -= leftborder + rightborder;
-}
-
-HWND doctl(struct ctlpos *cp, RECT r,
- char *wclass, int wstyle, int exstyle, char *wtext, int wid)
-{
- HWND ctl;
- /*
- * Note nonstandard use of RECT. This is deliberate: by
- * transforming the width and height directly we arrange to
- * have all supposedly same-sized controls really same-sized.
- */
-
- r.left += cp->xoff;
- MapDialogRect(cp->hwnd, &r);
-
- /*
- * We can pass in cp->hwnd == NULL, to indicate a dry run
- * without creating any actual controls.
- */
- if (cp->hwnd) {
- ctl = CreateWindowEx(exstyle, wclass, wtext, wstyle,
- r.left, r.top, r.right, r.bottom,
- cp->hwnd, (HMENU)(ULONG_PTR)wid, hinst, NULL);
- SendMessage(ctl, WM_SETFONT, cp->font, MAKELPARAM(true, 0));
-
- if (!strcmp(wclass, "LISTBOX")) {
- /*
- * Bizarre Windows bug: the list box calculates its
- * number of lines based on the font it has at creation
- * time, but sending it WM_SETFONT doesn't cause it to
- * recalculate. So now, _after_ we've sent it
- * WM_SETFONT, we explicitly resize it (to the same
- * size it was already!) to force it to reconsider.
- */
- SetWindowPos(ctl, NULL, 0, 0, r.right, r.bottom,
- SWP_NOACTIVATE | SWP_NOCOPYBITS |
- SWP_NOMOVE | SWP_NOZORDER);
- }
- } else
- ctl = NULL;
- return ctl;
-}
-
-/*
- * A title bar across the top of a sub-dialog.
- */
-void bartitle(struct ctlpos *cp, char *name, int id)
-{
- RECT r;
-
- r.left = GAPBETWEEN;
- r.right = cp->width;
- r.top = cp->ypos;
- r.bottom = STATICHEIGHT;
- cp->ypos += r.bottom + GAPBETWEEN;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, name, id);
-}
-
-/*
- * Begin a grouping box, with or without a group title.
- */
-void beginbox(struct ctlpos *cp, char *name, int idbox)
-{
- cp->boxystart = cp->ypos;
- if (!name)
- cp->boxystart -= STATICHEIGHT / 2;
- if (name)
- cp->ypos += STATICHEIGHT;
- cp->ypos += GAPYBOX;
- cp->width -= 2 * GAPXBOX;
- cp->xoff += GAPXBOX;
- cp->boxid = idbox;
- cp->boxtext = name;
-}
-
-/*
- * End a grouping box.
- */
-void endbox(struct ctlpos *cp)
-{
- RECT r;
- cp->xoff -= GAPXBOX;
- cp->width += 2 * GAPXBOX;
- cp->ypos += GAPYBOX - GAPBETWEEN;
- r.left = GAPBETWEEN;
- r.right = cp->width;
- r.top = cp->boxystart;
- r.bottom = cp->ypos - cp->boxystart;
- doctl(cp, r, "BUTTON", BS_GROUPBOX | WS_CHILD | WS_VISIBLE, 0,
- cp->boxtext ? cp->boxtext : "", cp->boxid);
- cp->ypos += GAPYBOX;
-}
-
-/*
- * A static line, followed by a full-width edit box.
- */
-void editboxfw(struct ctlpos *cp, bool password, char *text,
- int staticid, int editid)
-{
- RECT r;
-
- r.left = GAPBETWEEN;
- r.right = cp->width;
-
- if (text) {
- r.top = cp->ypos;
- r.bottom = STATICHEIGHT;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, staticid);
- cp->ypos += STATICHEIGHT + GAPWITHIN;
- }
- r.top = cp->ypos;
- r.bottom = EDITHEIGHT;
- doctl(cp, r, "EDIT",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL |
- (password ? ES_PASSWORD : 0),
- WS_EX_CLIENTEDGE, "", editid);
- cp->ypos += EDITHEIGHT + GAPBETWEEN;
-}
-
-/*
- * A static line, followed by a full-width combo box.
- */
-void combobox(struct ctlpos *cp, char *text, int staticid, int listid)
-{
- RECT r;
-
- r.left = GAPBETWEEN;
- r.right = cp->width;
-
- if (text) {
- r.top = cp->ypos;
- r.bottom = STATICHEIGHT;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, staticid);
- cp->ypos += STATICHEIGHT + GAPWITHIN;
- }
- r.top = cp->ypos;
- r.bottom = COMBOHEIGHT * 10;
- doctl(cp, r, "COMBOBOX",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
- CBS_DROPDOWN | CBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", listid);
- cp->ypos += COMBOHEIGHT + GAPBETWEEN;
-}
-
-struct radio { char *text; int id; };
-
-static void radioline_common(struct ctlpos *cp, char *text, int id,
- int nacross, struct radio *buttons, int nbuttons)
-{
- RECT r;
- int group;
- int i;
- int j;
-
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- if (text) {
- r.right = cp->width;
- r.bottom = STATICHEIGHT;
- cp->ypos += r.bottom + GAPWITHIN;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
- } else {
- r.right = r.bottom = 0;
- }
-
- group = WS_GROUP;
- i = 0;
- for (j = 0; j < nbuttons; j++) {
- char *btext = buttons[j].text;
- int bid = buttons[j].id;
-
- if (i == nacross) {
- cp->ypos += r.bottom + (nacross > 1 ? GAPBETWEEN : GAPWITHIN);
- i = 0;
- }
- r.left = GAPBETWEEN + i * (cp->width + GAPBETWEEN) / nacross;
- if (j < nbuttons-1)
- r.right =
- (i + 1) * (cp->width + GAPBETWEEN) / nacross - r.left;
- else
- r.right = cp->width - r.left;
- r.top = cp->ypos;
- r.bottom = RADIOHEIGHT;
- doctl(cp, r, "BUTTON",
- BS_NOTIFY | BS_AUTORADIOBUTTON | WS_CHILD |
- WS_VISIBLE | WS_TABSTOP | group, 0, btext, bid);
- group = 0;
- i++;
- }
- cp->ypos += r.bottom + GAPBETWEEN;
-}
-
-/*
- * A set of radio buttons on the same line, with a static above
- * them. `nacross' dictates how many parts the line is divided into
- * (you might want this not to equal the number of buttons if you
- * needed to line up some 2s and some 3s to look good in the same
- * panel).
- *
- * There's a bit of a hack in here to ensure that if nacross
- * exceeds the actual number of buttons, the rightmost button
- * really does get all the space right to the edge of the line, so
- * you can do things like
- *
- * (*) Button1 (*) Button2 (*) ButtonWithReallyLongTitle
- */
-void radioline(struct ctlpos *cp, char *text, int id, int nacross, ...)
-{
- va_list ap;
- struct radio *buttons;
- int i, nbuttons;
-
- va_start(ap, nacross);
- nbuttons = 0;
- while (1) {
- char *btext = va_arg(ap, char *);
- if (!btext)
- break;
- (void) va_arg(ap, int); /* id */
- nbuttons++;
- }
- va_end(ap);
- buttons = snewn(nbuttons, struct radio);
- va_start(ap, nacross);
- for (i = 0; i < nbuttons; i++) {
- buttons[i].text = va_arg(ap, char *);
- buttons[i].id = va_arg(ap, int);
- }
- va_end(ap);
- radioline_common(cp, text, id, nacross, buttons, nbuttons);
- sfree(buttons);
-}
-
-/*
- * A set of radio buttons on the same line, without a static above
- * them. Otherwise just like radioline.
- */
-void bareradioline(struct ctlpos *cp, int nacross, ...)
-{
- va_list ap;
- struct radio *buttons;
- int i, nbuttons;
-
- va_start(ap, nacross);
- nbuttons = 0;
- while (1) {
- char *btext = va_arg(ap, char *);
- if (!btext)
- break;
- (void) va_arg(ap, int); /* id */
- nbuttons++;
- }
- va_end(ap);
- buttons = snewn(nbuttons, struct radio);
- va_start(ap, nacross);
- for (i = 0; i < nbuttons; i++) {
- buttons[i].text = va_arg(ap, char *);
- buttons[i].id = va_arg(ap, int);
- }
- va_end(ap);
- radioline_common(cp, NULL, 0, nacross, buttons, nbuttons);
- sfree(buttons);
-}
-
-/*
- * A set of radio buttons on multiple lines, with a static above
- * them.
- */
-void radiobig(struct ctlpos *cp, char *text, int id, ...)
-{
- va_list ap;
- struct radio *buttons;
- int i, nbuttons;
-
- va_start(ap, id);
- nbuttons = 0;
- while (1) {
- char *btext = va_arg(ap, char *);
- if (!btext)
- break;
- (void) va_arg(ap, int); /* id */
- nbuttons++;
- }
- va_end(ap);
- buttons = snewn(nbuttons, struct radio);
- va_start(ap, id);
- for (i = 0; i < nbuttons; i++) {
- buttons[i].text = va_arg(ap, char *);
- buttons[i].id = va_arg(ap, int);
- }
- va_end(ap);
- radioline_common(cp, text, id, 1, buttons, nbuttons);
- sfree(buttons);
-}
-
-/*
- * A single standalone checkbox.
- */
-void checkbox(struct ctlpos *cp, char *text, int id)
-{
- RECT r;
-
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = CHECKBOXHEIGHT;
- cp->ypos += r.bottom + GAPBETWEEN;
- doctl(cp, r, "BUTTON",
- BS_NOTIFY | BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0,
- text, id);
-}
-
-/*
- * Wrap a piece of text for a static text control. Returns the
- * wrapped text (a malloc'ed string containing \ns), and also
- * returns the number of lines required.
- */
-char *staticwrap(struct ctlpos *cp, HWND hwnd, char *text, int *lines)
-{
- HDC hdc = GetDC(hwnd);
- int width, nlines, j;
- INT *pwidths, nfit;
- SIZE size;
- char *ret, *p, *q;
- RECT r;
- HFONT oldfont, newfont;
-
- ret = snewn(1+strlen(text), char);
- p = text;
- q = ret;
- pwidths = snewn(1+strlen(text), INT);
-
- /*
- * Work out the width the text will need to fit in, by doing
- * the same adjustment that the `statictext' function itself
- * will perform.
- */
- SetMapMode(hdc, MM_TEXT); /* ensure logical units == pixels */
- r.left = r.top = r.bottom = 0;
- r.right = cp->width;
- MapDialogRect(hwnd, &r);
- width = r.right;
-
- nlines = 1;
-
- /*
- * We must select the correct font into the HDC before calling
- * GetTextExtent*, or silly things will happen.
- */
- newfont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0);
- oldfont = SelectObject(hdc, newfont);
-
- while (*p) {
- if (!GetTextExtentExPoint(hdc, p, strlen(p), width,
- &nfit, pwidths, &size) ||
- (size_t)nfit >= strlen(p)) {
- /*
- * Either GetTextExtentExPoint returned failure, or the
- * whole of the rest of the text fits on this line.
- * Either way, we stop wrapping, copy the remainder of
- * the input string unchanged to the output, and leave.
- */
- strcpy(q, p);
- break;
- }
-
- /*
- * Now we search backwards along the string from `nfit',
- * looking for a space at which to break the line. If we
- * don't find one at all, that's fine - we'll just break
- * the line at `nfit'.
- */
- for (j = nfit; j > 0; j--) {
- if (isspace((unsigned char)p[j])) {
- nfit = j;
- break;
- }
- }
-
- strncpy(q, p, nfit);
- q[nfit] = '\n';
- q += nfit+1;
-
- p += nfit;
- while (*p && isspace((unsigned char)*p))
- p++;
-
- nlines++;
- }
-
- SelectObject(hdc, oldfont);
- ReleaseDC(cp->hwnd, hdc);
-
- if (lines) *lines = nlines;
-
- sfree(pwidths);
-
- return ret;
-}
-
-/*
- * A single standalone static text control.
- */
-void statictext(struct ctlpos *cp, char *text, int lines, int id)
-{
- RECT r;
-
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = STATICHEIGHT * lines;
- cp->ypos += r.bottom + GAPBETWEEN;
- doctl(cp, r, "STATIC",
- WS_CHILD | WS_VISIBLE | SS_LEFTNOWORDWRAP,
- 0, text, id);
-}
-
-/*
- * An owner-drawn static text control for a panel title.
- */
-void paneltitle(struct ctlpos *cp, int id)
-{
- RECT r;
-
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = TITLEHEIGHT;
- cp->ypos += r.bottom + GAPBETWEEN;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_OWNERDRAW,
- 0, NULL, id);
-}
-
-/*
- * A button on the right hand side, with a static to its left.
- */
-void staticbtn(struct ctlpos *cp, char *stext, int sid,
- char *btext, int bid)
-{
- const int height = (PUSHBTNHEIGHT > STATICHEIGHT ?
- PUSHBTNHEIGHT : STATICHEIGHT);
- RECT r;
- int lwid, rwid, rpos;
-
- rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
- lwid = rpos - 2 * GAPBETWEEN;
- rwid = cp->width + GAPBETWEEN - rpos;
-
- r.left = GAPBETWEEN;
- r.top = cp->ypos + (height - STATICHEIGHT) / 2;
- r.right = lwid;
- r.bottom = STATICHEIGHT;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
-
- r.left = rpos;
- r.top = cp->ypos + (height - PUSHBTNHEIGHT) / 2;
- r.right = rwid;
- r.bottom = PUSHBTNHEIGHT;
- doctl(cp, r, "BUTTON",
- BS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
- 0, btext, bid);
-
- cp->ypos += height + GAPBETWEEN;
-}
-
-/*
- * A simple push button.
- */
-void button(struct ctlpos *cp, char *btext, int bid, bool defbtn)
-{
- RECT r;
-
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = PUSHBTNHEIGHT;
-
- /* Q67655: the _dialog box_ must know which button is default
- * as well as the button itself knowing */
- if (defbtn && cp->hwnd)
- SendMessage(cp->hwnd, DM_SETDEFID, bid, 0);
-
- doctl(cp, r, "BUTTON",
- BS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_TABSTOP |
- (defbtn ? BS_DEFPUSHBUTTON : 0) | BS_PUSHBUTTON,
- 0, btext, bid);
-
- cp->ypos += PUSHBTNHEIGHT + GAPBETWEEN;
-}
-
-/*
- * Like staticbtn, but two buttons.
- */
-void static2btn(struct ctlpos *cp, char *stext, int sid,
- char *btext1, int bid1, char *btext2, int bid2)
-{
- const int height = (PUSHBTNHEIGHT > STATICHEIGHT ?
- PUSHBTNHEIGHT : STATICHEIGHT);
- RECT r;
- int lwid, rwid1, rwid2, rpos1, rpos2;
-
- rpos1 = GAPBETWEEN + (cp->width + GAPBETWEEN) / 2;
- rpos2 = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
- lwid = rpos1 - 2 * GAPBETWEEN;
- rwid1 = rpos2 - rpos1 - GAPBETWEEN;
- rwid2 = cp->width + GAPBETWEEN - rpos2;
-
- r.left = GAPBETWEEN;
- r.top = cp->ypos + (height - STATICHEIGHT) / 2;
- r.right = lwid;
- r.bottom = STATICHEIGHT;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
-
- r.left = rpos1;
- r.top = cp->ypos + (height - PUSHBTNHEIGHT) / 2;
- r.right = rwid1;
- r.bottom = PUSHBTNHEIGHT;
- doctl(cp, r, "BUTTON",
- BS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
- 0, btext1, bid1);
-
- r.left = rpos2;
- r.top = cp->ypos + (height - PUSHBTNHEIGHT) / 2;
- r.right = rwid2;
- r.bottom = PUSHBTNHEIGHT;
- doctl(cp, r, "BUTTON",
- BS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
- 0, btext2, bid2);
-
- cp->ypos += height + GAPBETWEEN;
-}
-
-/*
- * An edit control on the right hand side, with a static to its left.
- */
-static void staticedit_internal(struct ctlpos *cp, char *stext,
- int sid, int eid, int percentedit,
- int style)
-{
- const int height = (EDITHEIGHT > STATICHEIGHT ?
- EDITHEIGHT : STATICHEIGHT);
- RECT r;
- int lwid, rwid, rpos;
-
- rpos =
- GAPBETWEEN + (100 - percentedit) * (cp->width + GAPBETWEEN) / 100;
- lwid = rpos - 2 * GAPBETWEEN;
- rwid = cp->width + GAPBETWEEN - rpos;
-
- r.left = GAPBETWEEN;
- r.top = cp->ypos + (height - STATICHEIGHT) / 2;
- r.right = lwid;
- r.bottom = STATICHEIGHT;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
-
- r.left = rpos;
- r.top = cp->ypos + (height - EDITHEIGHT) / 2;
- r.right = rwid;
- r.bottom = EDITHEIGHT;
- doctl(cp, r, "EDIT",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL | style,
- WS_EX_CLIENTEDGE, "", eid);
-
- cp->ypos += height + GAPBETWEEN;
-}
-
-void staticedit(struct ctlpos *cp, char *stext,
- int sid, int eid, int percentedit)
-{
- staticedit_internal(cp, stext, sid, eid, percentedit, 0);
-}
-
-void staticpassedit(struct ctlpos *cp, char *stext,
- int sid, int eid, int percentedit)
-{
- staticedit_internal(cp, stext, sid, eid, percentedit, ES_PASSWORD);
-}
-
-/*
- * A drop-down list box on the right hand side, with a static to
- * its left.
- */
-void staticddl(struct ctlpos *cp, char *stext,
- int sid, int lid, int percentlist)
-{
- const int height = (COMBOHEIGHT > STATICHEIGHT ?
- COMBOHEIGHT : STATICHEIGHT);
- RECT r;
- int lwid, rwid, rpos;
-
- rpos =
- GAPBETWEEN + (100 - percentlist) * (cp->width + GAPBETWEEN) / 100;
- lwid = rpos - 2 * GAPBETWEEN;
- rwid = cp->width + GAPBETWEEN - rpos;
-
- r.left = GAPBETWEEN;
- r.top = cp->ypos + (height - STATICHEIGHT) / 2;
- r.right = lwid;
- r.bottom = STATICHEIGHT;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
-
- r.left = rpos;
- r.top = cp->ypos + (height - EDITHEIGHT) / 2;
- r.right = rwid;
- r.bottom = COMBOHEIGHT*4;
- doctl(cp, r, "COMBOBOX",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
- CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", lid);
-
- cp->ypos += height + GAPBETWEEN;
-}
-
-/*
- * A combo box on the right hand side, with a static to its left.
- */
-void staticcombo(struct ctlpos *cp, char *stext,
- int sid, int lid, int percentlist)
-{
- const int height = (COMBOHEIGHT > STATICHEIGHT ?
- COMBOHEIGHT : STATICHEIGHT);
- RECT r;
- int lwid, rwid, rpos;
-
- rpos =
- GAPBETWEEN + (100 - percentlist) * (cp->width + GAPBETWEEN) / 100;
- lwid = rpos - 2 * GAPBETWEEN;
- rwid = cp->width + GAPBETWEEN - rpos;
-
- r.left = GAPBETWEEN;
- r.top = cp->ypos + (height - STATICHEIGHT) / 2;
- r.right = lwid;
- r.bottom = STATICHEIGHT;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
-
- r.left = rpos;
- r.top = cp->ypos + (height - EDITHEIGHT) / 2;
- r.right = rwid;
- r.bottom = COMBOHEIGHT*10;
- doctl(cp, r, "COMBOBOX",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
- CBS_DROPDOWN | CBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", lid);
-
- cp->ypos += height + GAPBETWEEN;
-}
-
-/*
- * A static, with a full-width drop-down list box below it.
- */
-void staticddlbig(struct ctlpos *cp, char *stext,
- int sid, int lid)
-{
- RECT r;
-
- if (stext) {
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = STATICHEIGHT;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
- cp->ypos += STATICHEIGHT;
- }
-
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = COMBOHEIGHT*4;
- doctl(cp, r, "COMBOBOX",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
- CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", lid);
- cp->ypos += COMBOHEIGHT + GAPBETWEEN;
-}
-
-/*
- * A big multiline edit control with a static labelling it.
- */
-void bigeditctrl(struct ctlpos *cp, char *stext,
- int sid, int eid, int lines)
-{
- RECT r;
-
- if (stext) {
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = STATICHEIGHT;
- cp->ypos += r.bottom + GAPWITHIN;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
- }
-
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = EDITHEIGHT + (lines - 1) * STATICHEIGHT;
- cp->ypos += r.bottom + GAPBETWEEN;
- doctl(cp, r, "EDIT",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | ES_MULTILINE,
- WS_EX_CLIENTEDGE, "", eid);
-}
-
-/*
- * A list box with a static labelling it.
- */
-void listbox(struct ctlpos *cp, char *stext,
- int sid, int lid, int lines, bool multi)
-{
- RECT r;
-
- if (stext != NULL) {
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = STATICHEIGHT;
- cp->ypos += r.bottom + GAPWITHIN;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
- }
-
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = LISTHEIGHT + (lines - 1) * LISTINCREMENT;
- cp->ypos += r.bottom + GAPBETWEEN;
- doctl(cp, r, "LISTBOX",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
- LBS_NOTIFY | LBS_HASSTRINGS | LBS_USETABSTOPS |
- (multi ? LBS_MULTIPLESEL : 0),
- WS_EX_CLIENTEDGE, "", lid);
-}
-
-/*
- * A tab-control substitute when a real tab control is unavailable.
- */
-void ersatztab(struct ctlpos *cp, char *stext, int sid, int lid, int s2id)
-{
- const int height = (COMBOHEIGHT > STATICHEIGHT ?
- COMBOHEIGHT : STATICHEIGHT);
- RECT r;
- int bigwid, lwid, rwid, rpos;
- static const int BIGGAP = 15;
- static const int MEDGAP = 3;
-
- bigwid = cp->width + 2 * GAPBETWEEN - 2 * BIGGAP;
- cp->ypos += MEDGAP;
- rpos = BIGGAP + (bigwid + BIGGAP) / 2;
- lwid = rpos - 2 * BIGGAP;
- rwid = bigwid + BIGGAP - rpos;
-
- r.left = BIGGAP;
- r.top = cp->ypos + (height - STATICHEIGHT) / 2;
- r.right = lwid;
- r.bottom = STATICHEIGHT;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
-
- r.left = rpos;
- r.top = cp->ypos + (height - COMBOHEIGHT) / 2;
- r.right = rwid;
- r.bottom = COMBOHEIGHT * 10;
- doctl(cp, r, "COMBOBOX",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP |
- CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", lid);
-
- cp->ypos += height + MEDGAP + GAPBETWEEN;
-
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = 2;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ,
- 0, "", s2id);
-}
-
-/*
- * A static line, followed by an edit control on the left hand side
- * and a button on the right.
- */
-void editbutton(struct ctlpos *cp, char *stext, int sid,
- int eid, char *btext, int bid)
-{
- const int height = (EDITHEIGHT > PUSHBTNHEIGHT ?
- EDITHEIGHT : PUSHBTNHEIGHT);
- RECT r;
- int lwid, rwid, rpos;
-
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = STATICHEIGHT;
- cp->ypos += r.bottom + GAPWITHIN;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
-
- rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
- lwid = rpos - 2 * GAPBETWEEN;
- rwid = cp->width + GAPBETWEEN - rpos;
-
- r.left = GAPBETWEEN;
- r.top = cp->ypos + (height - EDITHEIGHT) / 2;
- r.right = lwid;
- r.bottom = EDITHEIGHT;
- doctl(cp, r, "EDIT",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
- WS_EX_CLIENTEDGE, "", eid);
-
- r.left = rpos;
- r.top = cp->ypos + (height - PUSHBTNHEIGHT) / 2;
- r.right = rwid;
- r.bottom = PUSHBTNHEIGHT;
- doctl(cp, r, "BUTTON",
- BS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
- 0, btext, bid);
-
- cp->ypos += height + GAPBETWEEN;
-}
-
-/*
- * A special control for manipulating an ordered preference list
- * (eg. for cipher selection).
- * XXX: this is a rough hack and could be improved.
- */
-void prefslist(struct prefslist *hdl, struct ctlpos *cp, int lines,
- char *stext, int sid, int listid, int upbid, int dnbid)
-{
- const static int percents[] = { 5, 75, 20 };
- RECT r;
- int xpos, percent = 0, i;
- int listheight = LISTHEIGHT + (lines - 1) * LISTINCREMENT;
- const int BTNSHEIGHT = 2*PUSHBTNHEIGHT + GAPBETWEEN;
- int totalheight, buttonpos;
-
- /* Squirrel away IDs. */
- hdl->listid = listid;
- hdl->upbid = upbid;
- hdl->dnbid = dnbid;
-
- /* The static label. */
- if (stext != NULL) {
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = STATICHEIGHT;
- cp->ypos += r.bottom + GAPWITHIN;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
- }
-
- if (listheight > BTNSHEIGHT) {
- totalheight = listheight;
- buttonpos = (listheight - BTNSHEIGHT) / 2;
- } else {
- totalheight = BTNSHEIGHT;
- buttonpos = 0;
- }
-
- for (i=0; i<3; i++) {
- int left, wid;
- xpos = (cp->width + GAPBETWEEN) * percent / 100;
- left = xpos + GAPBETWEEN;
- percent += percents[i];
- xpos = (cp->width + GAPBETWEEN) * percent / 100;
- wid = xpos - left;
-
- switch (i) {
- case 1: {
- /* The drag list box. */
- r.left = left; r.right = wid;
- r.top = cp->ypos; r.bottom = listheight;
- HWND ctl = doctl(cp, r, "LISTBOX",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP |
- WS_VSCROLL | LBS_HASSTRINGS | LBS_USETABSTOPS,
- WS_EX_CLIENTEDGE,
- "", listid);
- p_MakeDragList(ctl);
- break;
- }
-
- case 2:
- /* The "Up" and "Down" buttons. */
- /* XXX worry about accelerators if we have more than one
- * prefslist on a panel */
- r.left = left; r.right = wid;
- r.top = cp->ypos + buttonpos; r.bottom = PUSHBTNHEIGHT;
- doctl(cp, r, "BUTTON",
- BS_NOTIFY | WS_CHILD | WS_VISIBLE |
- WS_TABSTOP | BS_PUSHBUTTON,
- 0, "&Up", upbid);
-
- r.left = left; r.right = wid;
- r.top = cp->ypos + buttonpos + PUSHBTNHEIGHT + GAPBETWEEN;
- r.bottom = PUSHBTNHEIGHT;
- doctl(cp, r, "BUTTON",
- BS_NOTIFY | WS_CHILD | WS_VISIBLE |
- WS_TABSTOP | BS_PUSHBUTTON,
- 0, "&Down", dnbid);
-
- break;
-
- }
- }
-
- cp->ypos += totalheight + GAPBETWEEN;
-
-}
-
-/*
- * Helper function for prefslist: move item in list box.
- */
-static void pl_moveitem(HWND hwnd, int listid, int src, int dst)
-{
- int tlen, val;
- char *txt;
- /* Get the item's data. */
- tlen = SendDlgItemMessage (hwnd, listid, LB_GETTEXTLEN, src, 0);
- txt = snewn(tlen+1, char);
- SendDlgItemMessage (hwnd, listid, LB_GETTEXT, src, (LPARAM) txt);
- val = SendDlgItemMessage (hwnd, listid, LB_GETITEMDATA, src, 0);
- /* Deselect old location. */
- SendDlgItemMessage (hwnd, listid, LB_SETSEL, false, src);
- /* Delete it at the old location. */
- SendDlgItemMessage (hwnd, listid, LB_DELETESTRING, src, 0);
- /* Insert it at new location. */
- SendDlgItemMessage (hwnd, listid, LB_INSERTSTRING, dst,
- (LPARAM) txt);
- SendDlgItemMessage (hwnd, listid, LB_SETITEMDATA, dst,
- (LPARAM) val);
- /* Set selection. */
- SendDlgItemMessage (hwnd, listid, LB_SETCURSEL, dst, 0);
- sfree (txt);
-}
-
-int pl_itemfrompt(HWND hwnd, POINT cursor, bool scroll)
-{
- int ret;
- POINT uppoint, downpoint;
- int updist, downdist, upitem, downitem, i;
-
- /*
- * Ghastly hackery to try to figure out not which
- * _item_, but which _gap between items_, the user
- * is pointing at. We do this by first working out
- * which list item is under the cursor, and then
- * working out how far the cursor would have to
- * move up or down before the answer was different.
- * Then we put the insertion point _above_ the
- * current item if the upper edge is closer than
- * the lower edge, or _below_ it if vice versa.
- */
- ret = p_LBItemFromPt(hwnd, cursor, scroll);
- if (ret == -1)
- return ret;
- ret = p_LBItemFromPt(hwnd, cursor, false);
- updist = downdist = 0;
- for (i = 1; i < 4096 && (!updist || !downdist); i++) {
- uppoint = downpoint = cursor;
- uppoint.y -= i;
- downpoint.y += i;
- upitem = p_LBItemFromPt(hwnd, uppoint, false);
- downitem = p_LBItemFromPt(hwnd, downpoint, false);
- if (!updist && upitem != ret)
- updist = i;
- if (!downdist && downitem != ret)
- downdist = i;
- }
- if (downdist < updist)
- ret++;
- return ret;
-}
-
-/*
- * Handler for prefslist above.
- *
- * Return value has bit 0 set if the dialog box procedure needs to
- * return true from handling this message; it has bit 1 set if a
- * change may have been made in the contents of the list.
- */
-int handle_prefslist(struct prefslist *hdl,
- int *array, int maxmemb,
- bool is_dlmsg, HWND hwnd,
- WPARAM wParam, LPARAM lParam)
-{
- int i;
- int ret = 0;
-
- if (is_dlmsg) {
-
- if ((int)wParam == hdl->listid) {
- DRAGLISTINFO *dlm = (DRAGLISTINFO *)lParam;
- int dest = 0; /* initialise to placate gcc */
- switch (dlm->uNotification) {
- case DL_BEGINDRAG:
- /* Add a dummy item to make pl_itemfrompt() work
- * better.
- * FIXME: this causes scrollbar glitches if the count of
- * listbox contains >= its height. */
- hdl->dummyitem =
- SendDlgItemMessage(hwnd, hdl->listid,
- LB_ADDSTRING, 0, (LPARAM) "");
-
- hdl->srcitem = p_LBItemFromPt(dlm->hWnd, dlm->ptCursor, true);
- hdl->dragging = false;
- /* XXX hack Q183115 */
- SetWindowLongPtr(hwnd, DWLP_MSGRESULT, true);
- ret |= 1; break;
- case DL_CANCELDRAG:
- p_DrawInsert(hwnd, dlm->hWnd, -1); /* Clear arrow */
- SendDlgItemMessage(hwnd, hdl->listid,
- LB_DELETESTRING, hdl->dummyitem, 0);
- hdl->dragging = false;
- ret |= 1; break;
- case DL_DRAGGING:
- hdl->dragging = true;
- dest = pl_itemfrompt(dlm->hWnd, dlm->ptCursor, true);
- if (dest > hdl->dummyitem) dest = hdl->dummyitem;
- p_DrawInsert (hwnd, dlm->hWnd, dest);
- if (dest >= 0)
- SetWindowLongPtr(hwnd, DWLP_MSGRESULT, DL_MOVECURSOR);
- else
- SetWindowLongPtr(hwnd, DWLP_MSGRESULT, DL_STOPCURSOR);
- ret |= 1; break;
- case DL_DROPPED:
- if (hdl->dragging) {
- dest = pl_itemfrompt(dlm->hWnd, dlm->ptCursor, true);
- if (dest > hdl->dummyitem) dest = hdl->dummyitem;
- p_DrawInsert (hwnd, dlm->hWnd, -1);
- }
- SendDlgItemMessage(hwnd, hdl->listid,
- LB_DELETESTRING, hdl->dummyitem, 0);
- if (hdl->dragging) {
- hdl->dragging = false;
- if (dest >= 0) {
- /* Correct for "missing" item. */
- if (dest > hdl->srcitem) dest--;
- pl_moveitem(hwnd, hdl->listid, hdl->srcitem, dest);
- }
- ret |= 2;
- }
- ret |= 1; break;
- }
- }
-
- } else {
-
- if (((LOWORD(wParam) == hdl->upbid) ||
- (LOWORD(wParam) == hdl->dnbid)) &&
- ((HIWORD(wParam) == BN_CLICKED) ||
- (HIWORD(wParam) == BN_DOUBLECLICKED))) {
- /* Move an item up or down the list. */
- /* Get the current selection, if any. */
- int selection = SendDlgItemMessage (hwnd, hdl->listid, LB_GETCURSEL, 0, 0);
- if (selection == LB_ERR) {
- MessageBeep(0);
- } else {
- int nitems;
- /* Get the total number of items. */
- nitems = SendDlgItemMessage (hwnd, hdl->listid, LB_GETCOUNT, 0, 0);
- /* Should we do anything? */
- if (LOWORD(wParam) == hdl->upbid && (selection > 0))
- pl_moveitem(hwnd, hdl->listid, selection, selection - 1);
- else if (LOWORD(wParam) == hdl->dnbid && (selection < nitems - 1))
- pl_moveitem(hwnd, hdl->listid, selection, selection + 1);
- ret |= 2;
- }
-
- }
-
- }
-
- if (array) {
- /* Update array to match the list box. */
- for (i=0; i < maxmemb; i++)
- array[i] = SendDlgItemMessage (hwnd, hdl->listid, LB_GETITEMDATA,
- i, 0);
- }
-
- return ret;
-}
-
-/*
- * A progress bar (from Common Controls). We like our progress bars
- * to be smooth and unbroken, without those ugly divisions; some
- * older compilers may not support that, but that's life.
- */
-void progressbar(struct ctlpos *cp, int id)
-{
- RECT r;
-
- r.left = GAPBETWEEN;
- r.top = cp->ypos;
- r.right = cp->width;
- r.bottom = PROGBARHEIGHT;
- cp->ypos += r.bottom + GAPBETWEEN;
-
- doctl(cp, r, PROGRESS_CLASS, WS_CHILD | WS_VISIBLE
-#ifdef PBS_SMOOTH
- | PBS_SMOOTH
-#endif
- , WS_EX_CLIENTEDGE, "", id);
-}
-
-/* ----------------------------------------------------------------------
- * Platform-specific side of portable dialog-box mechanism.
- */
-
-/*
- * This function takes a string, escapes all the ampersands, and
- * places a single (unescaped) ampersand in front of the first
- * occurrence of the given shortcut character (which may be
- * NO_SHORTCUT).
- *
- * Return value is a malloc'ed copy of the processed version of the
- * string.
- */
-static char *shortcut_escape(const char *text, char shortcut)
-{
- char *ret;
- char const *p;
- char *q;
-
- if (!text)
- return NULL; /* sfree won't choke on this */
-
- ret = snewn(2*strlen(text)+1, char); /* size potentially doubles! */
- shortcut = tolower((unsigned char)shortcut);
-
- p = text;
- q = ret;
- while (*p) {
- if (shortcut != NO_SHORTCUT &&
- tolower((unsigned char)*p) == shortcut) {
- *q++ = '&';
- shortcut = NO_SHORTCUT; /* stop it happening twice */
- } else if (*p == '&') {
- *q++ = '&';
- }
- *q++ = *p++;
- }
- *q = '\0';
- return ret;
-}
-
-void winctrl_add_shortcuts(struct dlgparam *dp, struct winctrl *c)
-{
- int i;
- for (i = 0; i < lenof(c->shortcuts); i++)
- if (c->shortcuts[i] != NO_SHORTCUT) {
- unsigned char s = tolower((unsigned char)c->shortcuts[i]);
- assert(!dp->shortcuts[s]);
- dp->shortcuts[s] = true;
- }
-}
-
-void winctrl_rem_shortcuts(struct dlgparam *dp, struct winctrl *c)
-{
- int i;
- for (i = 0; i < lenof(c->shortcuts); i++)
- if (c->shortcuts[i] != NO_SHORTCUT) {
- unsigned char s = tolower((unsigned char)c->shortcuts[i]);
- assert(dp->shortcuts[s]);
- dp->shortcuts[s] = false;
- }
-}
-
-static int winctrl_cmp_byctrl(void *av, void *bv)
-{
- struct winctrl *a = (struct winctrl *)av;
- struct winctrl *b = (struct winctrl *)bv;
- if (a->ctrl < b->ctrl)
- return -1;
- else if (a->ctrl > b->ctrl)
- return +1;
- else
- return 0;
-}
-static int winctrl_cmp_byid(void *av, void *bv)
-{
- struct winctrl *a = (struct winctrl *)av;
- struct winctrl *b = (struct winctrl *)bv;
- if (a->base_id < b->base_id)
- return -1;
- else if (a->base_id > b->base_id)
- return +1;
- else
- return 0;
-}
-static int winctrl_cmp_byctrl_find(void *av, void *bv)
-{
- union control *a = (union control *)av;
- struct winctrl *b = (struct winctrl *)bv;
- if (a < b->ctrl)
- return -1;
- else if (a > b->ctrl)
- return +1;
- else
- return 0;
-}
-static int winctrl_cmp_byid_find(void *av, void *bv)
-{
- int *a = (int *)av;
- struct winctrl *b = (struct winctrl *)bv;
- if (*a < b->base_id)
- return -1;
- else if (*a >= b->base_id + b->num_ids)
- return +1;
- else
- return 0;
-}
-
-void winctrl_init(struct winctrls *wc)
-{
- wc->byctrl = newtree234(winctrl_cmp_byctrl);
- wc->byid = newtree234(winctrl_cmp_byid);
-}
-void winctrl_cleanup(struct winctrls *wc)
-{
- struct winctrl *c;
-
- while ((c = index234(wc->byid, 0)) != NULL) {
- winctrl_remove(wc, c);
- sfree(c->data);
- sfree(c);
- }
-
- freetree234(wc->byctrl);
- freetree234(wc->byid);
- wc->byctrl = wc->byid = NULL;
-}
-
-void winctrl_add(struct winctrls *wc, struct winctrl *c)
-{
- struct winctrl *ret;
- if (c->ctrl) {
- ret = add234(wc->byctrl, c);
- assert(ret == c);
- }
- ret = add234(wc->byid, c);
- assert(ret == c);
-}
-
-void winctrl_remove(struct winctrls *wc, struct winctrl *c)
-{
- struct winctrl *ret;
- ret = del234(wc->byctrl, c);
- ret = del234(wc->byid, c);
- assert(ret == c);
-}
-
-struct winctrl *winctrl_findbyctrl(struct winctrls *wc, union control *ctrl)
-{
- return find234(wc->byctrl, ctrl, winctrl_cmp_byctrl_find);
-}
-
-struct winctrl *winctrl_findbyid(struct winctrls *wc, int id)
-{
- return find234(wc->byid, &id, winctrl_cmp_byid_find);
-}
-
-struct winctrl *winctrl_findbyindex(struct winctrls *wc, int index)
-{
- return index234(wc->byid, index);
-}
-
-static void move_windows(HWND hwnd, int base_id, int num_ids, LONG dy)
-{
- if (!dy)
- return;
- for (int i = 0; i < num_ids; i++) {
- HWND win = GetDlgItem(hwnd, base_id + i);
-
- RECT rect;
- if (!GetWindowRect(win, &rect))
- continue;
-
- POINT p;
- p.x = rect.left;
- p.y = rect.top + dy;
- if (!ScreenToClient(hwnd, &p))
- continue;
-
- SetWindowPos(win, NULL, p.x, p.y, 0, 0,
- SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
- }
-}
-
-void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
- struct ctlpos *cp, struct controlset *s, int *id)
-{
- struct ctlpos columns[16];
- int ncols, colstart, colspan;
-
- struct ctlpos tabdelays[16];
- union control *tabdelayed[16];
- int ntabdelays;
-
- struct ctlpos pos;
-
- char shortcuts[MAX_SHORTCUTS_PER_CTRL];
- int nshortcuts;
- char *escaped;
- int i, actual_base_id, base_id, num_ids, align_id_relative;
- void *data;
-
- base_id = *id;
-
- /* Start a containing box, if we have a boxname. */
- if (s->boxname && *s->boxname) {
- struct winctrl *c = snew(struct winctrl);
- c->ctrl = NULL;
- c->base_id = c->align_id = base_id;
- c->num_ids = 1;
- c->data = NULL;
- memset(c->shortcuts, NO_SHORTCUT, lenof(c->shortcuts));
- winctrl_add(wc, c);
- beginbox(cp, s->boxtitle, base_id);
- base_id++;
- }
-
- /* Draw a title, if we have one. */
- if (!s->boxname && s->boxtitle) {
- struct winctrl *c = snew(struct winctrl);
- c->ctrl = NULL;
- c->base_id = c->align_id = base_id;
- c->num_ids = 1;
- c->data = dupstr(s->boxtitle);
- memset(c->shortcuts, NO_SHORTCUT, lenof(c->shortcuts));
- winctrl_add(wc, c);
- paneltitle(cp, base_id);
- base_id++;
- }
-
- /* Initially we have just one column. */
- ncols = 1;
- columns[0] = *cp; /* structure copy */
-
- /* And initially, there are no pending tab-delayed controls. */
- ntabdelays = 0;
-
- /* Loop over each control in the controlset. */
- for (i = 0; i < s->ncontrols; i++) {
- union control *ctrl = s->ctrls[i];
-
- /*
- * Generic processing that pertains to all control types.
- * At the end of this if statement, we'll have produced
- * `ctrl' (a pointer to the control we have to create, or
- * think about creating, in this iteration of the loop),
- * `pos' (a suitable ctlpos with which to position it), and
- * `c' (a winctrl structure to receive details of the
- * dialog IDs). Or we'll have done a `continue', if it was
- * CTRL_COLUMNS and doesn't require any control creation at
- * all.
- */
- if (ctrl->generic.type == CTRL_COLUMNS) {
- assert((ctrl->columns.ncols == 1) ^ (ncols == 1));
-
- if (ncols == 1) {
- /*
- * We're splitting into multiple columns.
- */
- int lpercent, rpercent, lx, rx, i;
-
- ncols = ctrl->columns.ncols;
- assert(ncols <= lenof(columns));
- for (i = 1; i < ncols; i++)
- columns[i] = columns[0]; /* structure copy */
-
- lpercent = 0;
- for (i = 0; i < ncols; i++) {
- rpercent = lpercent + ctrl->columns.percentages[i];
- lx = columns[i].xoff + lpercent *
- (columns[i].width + GAPBETWEEN) / 100;
- rx = columns[i].xoff + rpercent *
- (columns[i].width + GAPBETWEEN) / 100;
- columns[i].xoff = lx;
- columns[i].width = rx - lx - GAPBETWEEN;
- lpercent = rpercent;
- }
- } else {
- /*
- * We're recombining the various columns into one.
- */
- int maxy = columns[0].ypos;
- int i;
- for (i = 1; i < ncols; i++)
- if (maxy < columns[i].ypos)
- maxy = columns[i].ypos;
- ncols = 1;
- columns[0] = *cp; /* structure copy */
- columns[0].ypos = maxy;
- }
-
- continue;
- } else if (ctrl->generic.type == CTRL_TABDELAY) {
- int i;
-
- assert(!ctrl->generic.tabdelay);
- ctrl = ctrl->tabdelay.ctrl;
-
- for (i = 0; i < ntabdelays; i++)
- if (tabdelayed[i] == ctrl)
- break;
- assert(i < ntabdelays); /* we have to have found it */
-
- pos = tabdelays[i]; /* structure copy */
-
- colstart = colspan = -1; /* indicate this was tab-delayed */
-
- } else {
- /*
- * If it wasn't one of those, it's a genuine control;
- * so we'll have to compute a position for it now, by
- * checking its column span.
- */
- int col;
-
- colstart = COLUMN_START(ctrl->generic.column);
- colspan = COLUMN_SPAN(ctrl->generic.column);
-
- pos = columns[colstart]; /* structure copy */
- pos.width = columns[colstart+colspan-1].width +
- (columns[colstart+colspan-1].xoff - columns[colstart].xoff);
-
- for (col = colstart; col < colstart+colspan; col++)
- if (pos.ypos < columns[col].ypos)
- pos.ypos = columns[col].ypos;
-
- /*
- * If this control is to be tabdelayed, add it to the
- * tabdelay list, and unset pos.hwnd to inhibit actual
- * control creation.
- */
- if (ctrl->generic.tabdelay) {
- assert(ntabdelays < lenof(tabdelays));
- tabdelays[ntabdelays] = pos; /* structure copy */
- tabdelayed[ntabdelays] = ctrl;
- ntabdelays++;
- pos.hwnd = NULL;
- }
- }
-
- /* Most controls don't need anything in c->data. */
- data = NULL;
-
- /* And they all start off with no shortcuts registered. */
- memset(shortcuts, NO_SHORTCUT, lenof(shortcuts));
- nshortcuts = 0;
-
- /* Almost all controls start at base_id. */
- actual_base_id = base_id;
-
- /* For vertical alignment purposes, the most relevant control
- * in a group is usually the last one. But that can be
- * overridden occasionally. */
- align_id_relative = -1;
-
- /*
- * Now we're ready to actually create the control, by
- * switching on its type.
- */
- switch (ctrl->generic.type) {
- case CTRL_TEXT: {
- char *wrapped, *escaped;
- int lines;
- num_ids = 1;
- wrapped = staticwrap(&pos, cp->hwnd,
- ctrl->generic.label, &lines);
- escaped = shortcut_escape(wrapped, NO_SHORTCUT);
- statictext(&pos, escaped, lines, base_id);
- sfree(escaped);
- sfree(wrapped);
- break;
- }
- case CTRL_EDITBOX:
- num_ids = 2; /* static, edit */
- escaped = shortcut_escape(ctrl->editbox.label,
- ctrl->editbox.shortcut);
- shortcuts[nshortcuts++] = ctrl->editbox.shortcut;
- if (ctrl->editbox.percentwidth == 100) {
- if (ctrl->editbox.has_list)
- combobox(&pos, escaped,
- base_id, base_id+1);
- else
- editboxfw(&pos, ctrl->editbox.password, escaped,
- base_id, base_id+1);
- } else {
- if (ctrl->editbox.has_list) {
- staticcombo(&pos, escaped, base_id, base_id+1,
- ctrl->editbox.percentwidth);
- } else {
- (ctrl->editbox.password ? staticpassedit : staticedit)
- (&pos, escaped, base_id, base_id+1,
- ctrl->editbox.percentwidth);
- }
- }
- sfree(escaped);
- break;
- case CTRL_RADIO: {
- num_ids = ctrl->radio.nbuttons + 1; /* label as well */
- struct radio *buttons;
- int i;
-
- escaped = shortcut_escape(ctrl->radio.label,
- ctrl->radio.shortcut);
- shortcuts[nshortcuts++] = ctrl->radio.shortcut;
-
- buttons = snewn(ctrl->radio.nbuttons, struct radio);
-
- for (i = 0; i < ctrl->radio.nbuttons; i++) {
- buttons[i].text =
- shortcut_escape(ctrl->radio.buttons[i],
- (char)(ctrl->radio.shortcuts ?
- ctrl->radio.shortcuts[i] :
- NO_SHORTCUT));
- buttons[i].id = base_id + 1 + i;
- if (ctrl->radio.shortcuts) {
- assert(nshortcuts < MAX_SHORTCUTS_PER_CTRL);
- shortcuts[nshortcuts++] = ctrl->radio.shortcuts[i];
- }
- }
-
- radioline_common(&pos, escaped, base_id,
- ctrl->radio.ncolumns,
- buttons, ctrl->radio.nbuttons);
-
- for (i = 0; i < ctrl->radio.nbuttons; i++) {
- sfree(buttons[i].text);
- }
- sfree(buttons);
- sfree(escaped);
- break;
- }
- case CTRL_CHECKBOX:
- num_ids = 1;
- escaped = shortcut_escape(ctrl->checkbox.label,
- ctrl->checkbox.shortcut);
- shortcuts[nshortcuts++] = ctrl->checkbox.shortcut;
- checkbox(&pos, escaped, base_id);
- sfree(escaped);
- break;
- case CTRL_BUTTON:
- escaped = shortcut_escape(ctrl->button.label,
- ctrl->button.shortcut);
- shortcuts[nshortcuts++] = ctrl->button.shortcut;
- if (ctrl->button.iscancel)
- actual_base_id = IDCANCEL;
- num_ids = 1;
- button(&pos, escaped, actual_base_id, ctrl->button.isdefault);
- sfree(escaped);
- break;
- case CTRL_LISTBOX:
- num_ids = 2;
- escaped = shortcut_escape(ctrl->listbox.label,
- ctrl->listbox.shortcut);
- shortcuts[nshortcuts++] = ctrl->listbox.shortcut;
- if (ctrl->listbox.draglist) {
- data = snew(struct prefslist);
- num_ids = 4;
- prefslist(data, &pos, ctrl->listbox.height, escaped,
- base_id, base_id+1, base_id+2, base_id+3);
- shortcuts[nshortcuts++] = 'u'; /* Up */
- shortcuts[nshortcuts++] = 'd'; /* Down */
- } else if (ctrl->listbox.height == 0) {
- /* Drop-down list. */
- if (ctrl->listbox.percentwidth == 100) {
- staticddlbig(&pos, escaped,
- base_id, base_id+1);
- } else {
- staticddl(&pos, escaped, base_id,
- base_id+1, ctrl->listbox.percentwidth);
- }
- } else {
- /* Ordinary list. */
- listbox(&pos, escaped, base_id, base_id+1,
- ctrl->listbox.height, ctrl->listbox.multisel);
- }
- if (ctrl->listbox.ncols) {
- /*
- * This method of getting the box width is a bit of
- * a hack; we'd do better to try to retrieve the
- * actual width in dialog units from doctl() just
- * before MapDialogRect. But that's going to be no
- * fun, and this should be good enough accuracy.
- */
- int width = cp->width * ctrl->listbox.percentwidth;
- int *tabarray;
- int i, percent;
-
- tabarray = snewn(ctrl->listbox.ncols-1, int);
- percent = 0;
- for (i = 0; i < ctrl->listbox.ncols-1; i++) {
- percent += ctrl->listbox.percentages[i];
- tabarray[i] = width * percent / 10000;
- }
- SendDlgItemMessage(cp->hwnd, base_id+1, LB_SETTABSTOPS,
- ctrl->listbox.ncols-1, (LPARAM)tabarray);
- sfree(tabarray);
- }
- sfree(escaped);
- break;
- case CTRL_FILESELECT:
- num_ids = 3;
- escaped = shortcut_escape(ctrl->fileselect.label,
- ctrl->fileselect.shortcut);
- shortcuts[nshortcuts++] = ctrl->fileselect.shortcut;
- editbutton(&pos, escaped, base_id, base_id+1,
- "Bro&wse...", base_id+2);
- shortcuts[nshortcuts++] = 'w';
- sfree(escaped);
- break;
- case CTRL_FONTSELECT:
- num_ids = 3;
- escaped = shortcut_escape(ctrl->fontselect.label,
- ctrl->fontselect.shortcut);
- shortcuts[nshortcuts++] = ctrl->fontselect.shortcut;
- statictext(&pos, escaped, 1, base_id);
- staticbtn(&pos, "", base_id+1, "Change...", base_id+2);
- data = fontspec_new("", false, 0, 0);
- sfree(escaped);
- break;
- default:
- unreachable("bad control type in winctrl_layout");
- }
-
- /* Translate the original align_id_relative of -1 into n-1 */
- if (align_id_relative < 0)
- align_id_relative += num_ids;
-
- /*
- * Create a `struct winctrl' for this control, and advance
- * the dialog ID counter, if it's actually been created
- * (and isn't tabdelayed).
- */
- if (pos.hwnd) {
- struct winctrl *c = snew(struct winctrl);
-
- c->ctrl = ctrl;
- c->base_id = actual_base_id;
- c->align_id = c->base_id + align_id_relative;
- c->num_ids = num_ids;
- c->data = data;
- memcpy(c->shortcuts, shortcuts, sizeof(shortcuts));
- winctrl_add(wc, c);
- winctrl_add_shortcuts(dp, c);
- if (actual_base_id == base_id)
- base_id += num_ids;
-
- if (ctrl->generic.align_next_to) {
- /*
- * Implement align_next_to by looking at the y extents
- * of the two controls now that both are created, and
- * moving one or the other downwards so that they're
- * centred on a common horizontal line.
- */
- struct winctrl *c2 = winctrl_findbyctrl(
- wc, ctrl->generic.align_next_to);
- HWND win1 = GetDlgItem(pos.hwnd, c->align_id);
- HWND win2 = GetDlgItem(pos.hwnd, c2->align_id);
- RECT rect1, rect2;
- if (win1 && win2 &&
- GetWindowRect(win1, &rect1) &&
- GetWindowRect(win2, &rect2)) {
- LONG top = (rect1.top < rect2.top ? rect1.top : rect2.top);
- LONG bottom = (rect1.bottom > rect2.bottom ?
- rect1.bottom : rect2.bottom);
- move_windows(pos.hwnd, c->base_id, c->num_ids,
- (top + bottom - rect1.top - rect1.bottom)/2);
- move_windows(pos.hwnd, c2->base_id, c2->num_ids,
- (top + bottom - rect2.top - rect2.bottom)/2);
- }
- }
- } else {
- sfree(data);
- }
-
- if (colstart >= 0) {
- /*
- * Update the ypos in all columns crossed by this
- * control.
- */
- int i;
- for (i = colstart; i < colstart+colspan; i++)
- columns[i].ypos = pos.ypos;
- }
- }
-
- /*
- * We've now finished laying out the controls; so now update
- * the ctlpos and control ID that were passed in, terminate
- * any containing box, and return.
- */
- for (i = 0; i < ncols; i++)
- if (cp->ypos < columns[i].ypos)
- cp->ypos = columns[i].ypos;
- *id = base_id;
-
- if (s->boxname && *s->boxname)
- endbox(cp);
-}
-
-static void winctrl_set_focus(union control *ctrl, struct dlgparam *dp,
- bool has_focus)
-{
- if (has_focus) {
- if (dp->focused)
- dp->lastfocused = dp->focused;
- dp->focused = ctrl;
- } else if (!has_focus && dp->focused == ctrl) {
- dp->lastfocused = dp->focused;
- dp->focused = NULL;
- }
-}
-
-union control *dlg_last_focused(union control *ctrl, dlgparam *dp)
-{
- return dp->focused == ctrl ? dp->lastfocused : dp->focused;
-}
-
-/*
- * The dialog-box procedure calls this function to handle Windows
- * messages on a control we manage.
- */
-bool winctrl_handle_command(struct dlgparam *dp, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- struct winctrl *c;
- union control *ctrl;
- int i, id;
- bool ret;
- static UINT draglistmsg = WM_NULL;
-
- /*
- * Filter out pointless window messages. Our interest is in
- * WM_COMMAND and the drag list message, and nothing else.
- */
- if (draglistmsg == WM_NULL)
- draglistmsg = RegisterWindowMessage (DRAGLISTMSGSTRING);
-
- if (msg != draglistmsg && msg != WM_COMMAND && msg != WM_DRAWITEM)
- return false;
-
- /*
- * Look up the control ID in our data.
- */
- c = NULL;
- for (i = 0; i < dp->nctrltrees; i++) {
- c = winctrl_findbyid(dp->controltrees[i], LOWORD(wParam));
- if (c)
- break;
- }
- if (!c)
- return false; /* we have nothing to do */
-
- if (msg == WM_DRAWITEM) {
- /*
- * Owner-draw request for a panel title.
- */
- LPDRAWITEMSTRUCT di = (LPDRAWITEMSTRUCT) lParam;
- HDC hdc = di->hDC;
- RECT r = di->rcItem;
- SIZE s;
-
- SetMapMode(hdc, MM_TEXT); /* ensure logical units == pixels */
-
- GetTextExtentPoint32(hdc, (char *)c->data,
- strlen((char *)c->data), &s);
- DrawEdge(hdc, &r, EDGE_ETCHED, BF_ADJUST | BF_RECT);
- TextOut(hdc,
- r.left + (r.right-r.left-s.cx)/2,
- r.top + (r.bottom-r.top-s.cy)/2,
- (char *)c->data, strlen((char *)c->data));
-
- return true;
- }
-
- ctrl = c->ctrl;
- id = LOWORD(wParam) - c->base_id;
-
- if (!ctrl || !ctrl->generic.handler)
- return false; /* nothing we can do here */
-
- /*
- * From here on we do not issue `return' statements until the
- * very end of the dialog box: any event handler is entitled to
- * ask for a colour selector, so we _must_ always allow control
- * to reach the end of this switch statement so that the
- * subsequent code can test dp->coloursel_wanted().
- */
- ret = false;
- dp->coloursel_wanted = false;
-
- /*
- * Now switch on the control type and the message.
- */
- switch (ctrl->generic.type) {
- case CTRL_EDITBOX:
- if (msg == WM_COMMAND && !ctrl->editbox.has_list &&
- (HIWORD(wParam) == EN_SETFOCUS || HIWORD(wParam) == EN_KILLFOCUS))
- winctrl_set_focus(ctrl, dp, HIWORD(wParam) == EN_SETFOCUS);
- if (msg == WM_COMMAND && ctrl->editbox.has_list &&
- (HIWORD(wParam)==CBN_SETFOCUS || HIWORD(wParam)==CBN_KILLFOCUS))
- winctrl_set_focus(ctrl, dp, HIWORD(wParam) == CBN_SETFOCUS);
-
- if (msg == WM_COMMAND && !ctrl->editbox.has_list &&
- HIWORD(wParam) == EN_CHANGE)
- ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
- if (msg == WM_COMMAND &&
- ctrl->editbox.has_list) {
- if (HIWORD(wParam) == CBN_SELCHANGE) {
- int index, len;
- char *text;
-
- index = SendDlgItemMessage(dp->hwnd, c->base_id+1,
- CB_GETCURSEL, 0, 0);
- len = SendDlgItemMessage(dp->hwnd, c->base_id+1,
- CB_GETLBTEXTLEN, index, 0);
- text = snewn(len+1, char);
- SendDlgItemMessage(dp->hwnd, c->base_id+1, CB_GETLBTEXT,
- index, (LPARAM)text);
- SetDlgItemText(dp->hwnd, c->base_id+1, text);
- sfree(text);
- ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
- } else if (HIWORD(wParam) == CBN_EDITCHANGE) {
- ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
- } else if (HIWORD(wParam) == CBN_KILLFOCUS) {
- ctrl->generic.handler(ctrl, dp, dp->data, EVENT_REFRESH);
- }
-
- }
- break;
- case CTRL_RADIO:
- if (msg == WM_COMMAND &&
- (HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
- winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
- /*
- * We sometimes get spurious BN_CLICKED messages for the
- * radio button that is just about to _lose_ selection, if
- * we're switching using the arrow keys. Therefore we
- * double-check that the button in wParam is actually
- * checked before generating an event.
- */
- if (msg == WM_COMMAND &&
- (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) &&
- IsDlgButtonChecked(dp->hwnd, LOWORD(wParam))) {
- ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
- }
- break;
- case CTRL_CHECKBOX:
- if (msg == WM_COMMAND &&
- (HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
- winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
- if (msg == WM_COMMAND &&
- (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)) {
- ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
- }
- break;
- case CTRL_BUTTON:
- if (msg == WM_COMMAND &&
- (HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
- winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
- if (msg == WM_COMMAND &&
- (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)) {
- ctrl->generic.handler(ctrl, dp, dp->data, EVENT_ACTION);
- }
- break;
- case CTRL_LISTBOX:
- if (msg == WM_COMMAND && ctrl->listbox.height != 0 &&
- (HIWORD(wParam)==LBN_SETFOCUS || HIWORD(wParam)==LBN_KILLFOCUS))
- winctrl_set_focus(ctrl, dp, HIWORD(wParam) == LBN_SETFOCUS);
- if (msg == WM_COMMAND && ctrl->listbox.height == 0 &&
- (HIWORD(wParam)==CBN_SETFOCUS || HIWORD(wParam)==CBN_KILLFOCUS))
- winctrl_set_focus(ctrl, dp, HIWORD(wParam) == CBN_SETFOCUS);
- if (msg == WM_COMMAND && id >= 2 &&
- (HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
- winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
- if (ctrl->listbox.draglist) {
- int pret;
- pret = handle_prefslist(c->data, NULL, 0, (msg != WM_COMMAND),
- dp->hwnd, wParam, lParam);
- if (pret & 2)
- ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
- ret = pret & 1;
- } else {
- if (msg == WM_COMMAND && HIWORD(wParam) == LBN_DBLCLK) {
- SetCapture(dp->hwnd);
- ctrl->generic.handler(ctrl, dp, dp->data, EVENT_ACTION);
- } else if (msg == WM_COMMAND && HIWORD(wParam) == LBN_SELCHANGE) {
- ctrl->generic.handler(ctrl, dp, dp->data, EVENT_SELCHANGE);
- }
- }
- break;
- case CTRL_FILESELECT:
- if (msg == WM_COMMAND && id == 1 &&
- (HIWORD(wParam) == EN_SETFOCUS || HIWORD(wParam) == EN_KILLFOCUS))
- winctrl_set_focus(ctrl, dp, HIWORD(wParam) == EN_SETFOCUS);
- if (msg == WM_COMMAND && id == 2 &&
- (HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
- winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
- if (msg == WM_COMMAND && id == 1 && HIWORD(wParam) == EN_CHANGE)
- ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
- if (id == 2 &&
- (msg == WM_COMMAND &&
- (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED))) {
- OPENFILENAME of;
- char filename[FILENAME_MAX];
-
- memset(&of, 0, sizeof(of));
- of.hwndOwner = dp->hwnd;
- if (ctrl->fileselect.filter)
- of.lpstrFilter = ctrl->fileselect.filter;
- else
- of.lpstrFilter = "All Files (*.*)\0*\0\0\0";
- of.lpstrCustomFilter = NULL;
- of.nFilterIndex = 1;
- of.lpstrFile = filename;
- GetDlgItemText(dp->hwnd, c->base_id+1, filename, lenof(filename));
- filename[lenof(filename)-1] = '\0';
- of.nMaxFile = lenof(filename);
- of.lpstrFileTitle = NULL;
- of.lpstrTitle = ctrl->fileselect.title;
- of.Flags = 0;
- if (request_file(NULL, &of, false, ctrl->fileselect.for_writing)) {
- SetDlgItemText(dp->hwnd, c->base_id + 1, filename);
- ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
- }
- }
- break;
- case CTRL_FONTSELECT:
- if (msg == WM_COMMAND && id == 2 &&
- (HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS))
- winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS);
- if (id == 2 &&
- (msg == WM_COMMAND &&
- (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED))) {
- CHOOSEFONT cf;
- LOGFONT lf;
- HDC hdc;
- FontSpec *fs = (FontSpec *)c->data;
-
- hdc = GetDC(0);
- lf.lfHeight = -MulDiv(fs->height,
- GetDeviceCaps(hdc, LOGPIXELSY), 72);
- ReleaseDC(0, hdc);
- lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
- lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
- lf.lfWeight = (fs->isbold ? FW_BOLD : 0);
- lf.lfCharSet = fs->charset;
- lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
- lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
- lf.lfQuality = DEFAULT_QUALITY;
- lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
- strncpy(lf.lfFaceName, fs->name,
- sizeof(lf.lfFaceName) - 1);
- lf.lfFaceName[sizeof(lf.lfFaceName) - 1] = '\0';
-
- cf.lStructSize = sizeof(cf);
- cf.hwndOwner = dp->hwnd;
- cf.lpLogFont = &lf;
- cf.Flags = (dp->fixed_pitch_fonts ? CF_FIXEDPITCHONLY : 0) |
- CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
-
- if (ChooseFont(&cf)) {
- fs = fontspec_new(lf.lfFaceName, (lf.lfWeight == FW_BOLD),
- cf.iPointSize / 10, lf.lfCharSet);
- dlg_fontsel_set(ctrl, dp, fs);
- fontspec_free(fs);
-
- ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
- }
- }
- break;
- }
-
- /*
- * If the above event handler has asked for a colour selector,
- * now is the time to generate one.
- */
- if (dp->coloursel_wanted) {
- static CHOOSECOLOR cc;
- static DWORD custom[16] = { 0 }; /* zero initialisers */
- cc.lStructSize = sizeof(cc);
- cc.hwndOwner = dp->hwnd;
- cc.hInstance = (HWND) hinst;
- cc.lpCustColors = custom;
- cc.rgbResult = RGB(dp->coloursel_result.r,
- dp->coloursel_result.g,
- dp->coloursel_result.b);
- cc.Flags = CC_FULLOPEN | CC_RGBINIT;
- if (ChooseColor(&cc)) {
- dp->coloursel_result.r =
- (unsigned char) (cc.rgbResult & 0xFF);
- dp->coloursel_result.g =
- (unsigned char) (cc.rgbResult >> 8) & 0xFF;
- dp->coloursel_result.b =
- (unsigned char) (cc.rgbResult >> 16) & 0xFF;
- dp->coloursel_result.ok = true;
- } else
- dp->coloursel_result.ok = false;
- ctrl->generic.handler(ctrl, dp, dp->data, EVENT_CALLBACK);
- }
-
- return ret;
-}
-
-/*
- * This function can be called to produce context help on a
- * control. Returns true if it has actually launched some help.
- */
-bool winctrl_context_help(struct dlgparam *dp, HWND hwnd, int id)
-{
- int i;
- struct winctrl *c;
-
- /*
- * Look up the control ID in our data.
- */
- c = NULL;
- for (i = 0; i < dp->nctrltrees; i++) {
- c = winctrl_findbyid(dp->controltrees[i], id);
- if (c)
- break;
- }
- if (!c)
- return false; /* we have nothing to do */
-
- /*
- * This is the Windows front end, so we're allowed to assume
- * `helpctx.p' is a context string.
- */
- if (!c->ctrl || !c->ctrl->generic.helpctx.p)
- return false; /* no help available for this ctrl */
-
- launch_help(hwnd, c->ctrl->generic.helpctx.p);
- return true;
-}
-
-/*
- * Now the various functions that the platform-independent
- * mechanism can call to access the dialog box entries.
- */
-
-static struct winctrl *dlg_findbyctrl(struct dlgparam *dp, union control *ctrl)
-{
- int i;
-
- for (i = 0; i < dp->nctrltrees; i++) {
- struct winctrl *c = winctrl_findbyctrl(dp->controltrees[i], ctrl);
- if (c)
- return c;
- }
- return NULL;
-}
-
-bool dlg_is_visible(union control *ctrl, dlgparam *dp)
-{
- /*
- * In this implementation of the dialog box, we physically
- * uncreate controls that aren't in a visible panel of the config
- * box. So we can tell if a control is visible just by checking if
- * it _exists_.
- */
- return dlg_findbyctrl(dp, ctrl) != NULL;
-}
-
-void dlg_radiobutton_set(union control *ctrl, dlgparam *dp, int whichbutton)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- assert(c && c->ctrl->generic.type == CTRL_RADIO);
- CheckRadioButton(dp->hwnd,
- c->base_id + 1,
- c->base_id + c->ctrl->radio.nbuttons,
- c->base_id + 1 + whichbutton);
-}
-
-int dlg_radiobutton_get(union control *ctrl, dlgparam *dp)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- int i;
- assert(c && c->ctrl->generic.type == CTRL_RADIO);
- for (i = 0; i < c->ctrl->radio.nbuttons; i++)
- if (IsDlgButtonChecked(dp->hwnd, c->base_id + 1 + i))
- return i;
- unreachable("no radio button was checked");
-}
-
-void dlg_checkbox_set(union control *ctrl, dlgparam *dp, bool checked)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- assert(c && c->ctrl->generic.type == CTRL_CHECKBOX);
- CheckDlgButton(dp->hwnd, c->base_id, checked);
-}
-
-bool dlg_checkbox_get(union control *ctrl, dlgparam *dp)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- assert(c && c->ctrl->generic.type == CTRL_CHECKBOX);
- return 0 != IsDlgButtonChecked(dp->hwnd, c->base_id);
-}
-
-void dlg_editbox_set(union control *ctrl, dlgparam *dp, char const *text)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- assert(c && c->ctrl->generic.type == CTRL_EDITBOX);
- SetDlgItemText(dp->hwnd, c->base_id+1, text);
-}
-
-char *dlg_editbox_get(union control *ctrl, dlgparam *dp)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- assert(c && c->ctrl->generic.type == CTRL_EDITBOX);
- return GetDlgItemText_alloc(dp->hwnd, c->base_id+1);
-}
-
-/* The `listbox' functions can also apply to combo boxes. */
-void dlg_listbox_clear(union control *ctrl, dlgparam *dp)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- int msg;
- assert(c &&
- (c->ctrl->generic.type == CTRL_LISTBOX ||
- (c->ctrl->generic.type == CTRL_EDITBOX &&
- c->ctrl->editbox.has_list)));
- msg = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ?
- LB_RESETCONTENT : CB_RESETCONTENT);
- SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, 0, 0);
-}
-
-void dlg_listbox_del(union control *ctrl, dlgparam *dp, int index)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- int msg;
- assert(c &&
- (c->ctrl->generic.type == CTRL_LISTBOX ||
- (c->ctrl->generic.type == CTRL_EDITBOX &&
- c->ctrl->editbox.has_list)));
- msg = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ?
- LB_DELETESTRING : CB_DELETESTRING);
- SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, index, 0);
-}
-
-void dlg_listbox_add(union control *ctrl, dlgparam *dp, char const *text)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- int msg;
- assert(c &&
- (c->ctrl->generic.type == CTRL_LISTBOX ||
- (c->ctrl->generic.type == CTRL_EDITBOX &&
- c->ctrl->editbox.has_list)));
- msg = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ?
- LB_ADDSTRING : CB_ADDSTRING);
- SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, 0, (LPARAM)text);
-}
-
-/*
- * Each listbox entry may have a numeric id associated with it.
- * Note that some front ends only permit a string to be stored at
- * each position, which means that _if_ you put two identical
- * strings in any listbox then you MUST not assign them different
- * IDs and expect to get meaningful results back.
- */
-void dlg_listbox_addwithid(union control *ctrl, dlgparam *dp,
- char const *text, int id)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- int msg, msg2, index;
- assert(c &&
- (c->ctrl->generic.type == CTRL_LISTBOX ||
- (c->ctrl->generic.type == CTRL_EDITBOX &&
- c->ctrl->editbox.has_list)));
- msg = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ?
- LB_ADDSTRING : CB_ADDSTRING);
- msg2 = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ?
- LB_SETITEMDATA : CB_SETITEMDATA);
- index = SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, 0, (LPARAM)text);
- SendDlgItemMessage(dp->hwnd, c->base_id+1, msg2, index, (LPARAM)id);
-}
-
-int dlg_listbox_getid(union control *ctrl, dlgparam *dp, int index)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- int msg;
- assert(c && c->ctrl->generic.type == CTRL_LISTBOX);
- msg = (c->ctrl->listbox.height != 0 ? LB_GETITEMDATA : CB_GETITEMDATA);
- return
- SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, index, 0);
-}
-
-/* dlg_listbox_index returns <0 if no single element is selected. */
-int dlg_listbox_index(union control *ctrl, dlgparam *dp)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- int msg, ret;
- assert(c && c->ctrl->generic.type == CTRL_LISTBOX);
- if (c->ctrl->listbox.multisel) {
- assert(c->ctrl->listbox.height != 0); /* not combo box */
- ret = SendDlgItemMessage(dp->hwnd, c->base_id+1, LB_GETSELCOUNT, 0, 0);
- if (ret == LB_ERR || ret > 1)
- return -1;
- }
- msg = (c->ctrl->listbox.height != 0 ? LB_GETCURSEL : CB_GETCURSEL);
- ret = SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, 0, 0);
- if (ret == LB_ERR)
- return -1;
- else
- return ret;
-}
-
-bool dlg_listbox_issel(union control *ctrl, dlgparam *dp, int index)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- assert(c && c->ctrl->generic.type == CTRL_LISTBOX &&
- c->ctrl->listbox.multisel &&
- c->ctrl->listbox.height != 0);
- return
- SendDlgItemMessage(dp->hwnd, c->base_id+1, LB_GETSEL, index, 0);
-}
-
-void dlg_listbox_select(union control *ctrl, dlgparam *dp, int index)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- int msg;
- assert(c && c->ctrl->generic.type == CTRL_LISTBOX &&
- !c->ctrl->listbox.multisel);
- msg = (c->ctrl->listbox.height != 0 ? LB_SETCURSEL : CB_SETCURSEL);
- SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, index, 0);
-}
-
-void dlg_text_set(union control *ctrl, dlgparam *dp, char const *text)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- assert(c && c->ctrl->generic.type == CTRL_TEXT);
- SetDlgItemText(dp->hwnd, c->base_id, text);
-}
-
-void dlg_label_change(union control *ctrl, dlgparam *dp, char const *text)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- char *escaped = NULL;
- int id = -1;
-
- assert(c);
- switch (c->ctrl->generic.type) {
- case CTRL_EDITBOX:
- escaped = shortcut_escape(text, c->ctrl->editbox.shortcut);
- id = c->base_id;
- break;
- case CTRL_RADIO:
- escaped = shortcut_escape(text, c->ctrl->radio.shortcut);
- id = c->base_id;
- break;
- case CTRL_CHECKBOX:
- escaped = shortcut_escape(text, ctrl->checkbox.shortcut);
- id = c->base_id;
- break;
- case CTRL_BUTTON:
- escaped = shortcut_escape(text, ctrl->button.shortcut);
- id = c->base_id;
- break;
- case CTRL_LISTBOX:
- escaped = shortcut_escape(text, ctrl->listbox.shortcut);
- id = c->base_id;
- break;
- case CTRL_FILESELECT:
- escaped = shortcut_escape(text, ctrl->fileselect.shortcut);
- id = c->base_id;
- break;
- case CTRL_FONTSELECT:
- escaped = shortcut_escape(text, ctrl->fontselect.shortcut);
- id = c->base_id;
- break;
- default:
- unreachable("bad control type in label_change");
- }
- if (escaped) {
- SetDlgItemText(dp->hwnd, id, escaped);
- sfree(escaped);
- }
-}
-
-void dlg_filesel_set(union control *ctrl, dlgparam *dp, Filename *fn)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- assert(c && c->ctrl->generic.type == CTRL_FILESELECT);
- SetDlgItemText(dp->hwnd, c->base_id+1, fn->path);
-}
-
-Filename *dlg_filesel_get(union control *ctrl, dlgparam *dp)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- char *tmp;
- Filename *ret;
- assert(c && c->ctrl->generic.type == CTRL_FILESELECT);
- tmp = GetDlgItemText_alloc(dp->hwnd, c->base_id+1);
- ret = filename_from_str(tmp);
- sfree(tmp);
- return ret;
-}
-
-void dlg_fontsel_set(union control *ctrl, dlgparam *dp, FontSpec *fs)
-{
- char *buf, *boldstr;
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- assert(c && c->ctrl->generic.type == CTRL_FONTSELECT);
-
- fontspec_free((FontSpec *)c->data);
- c->data = fontspec_copy(fs);
-
- boldstr = (fs->isbold ? "bold, " : "");
- if (fs->height == 0)
- buf = dupprintf("Font: %s, %sdefault height", fs->name, boldstr);
- else
- buf = dupprintf("Font: %s, %s%d-%s", fs->name, boldstr,
- (fs->height < 0 ? -fs->height : fs->height),
- (fs->height < 0 ? "pixel" : "point"));
- SetDlgItemText(dp->hwnd, c->base_id+1, buf);
- sfree(buf);
-
- dlg_auto_set_fixed_pitch_flag(dp);
-}
-
-FontSpec *dlg_fontsel_get(union control *ctrl, dlgparam *dp)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- assert(c && c->ctrl->generic.type == CTRL_FONTSELECT);
- return fontspec_copy((FontSpec *)c->data);
-}
-
-/*
- * Bracketing a large set of updates in these two functions will
- * cause the front end (if possible) to delay updating the screen
- * until it's all complete, thus avoiding flicker.
- */
-void dlg_update_start(union control *ctrl, dlgparam *dp)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- if (c && c->ctrl->generic.type == CTRL_LISTBOX) {
- SendDlgItemMessage(dp->hwnd, c->base_id+1, WM_SETREDRAW, false, 0);
- }
-}
-
-void dlg_update_done(union control *ctrl, dlgparam *dp)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- if (c && c->ctrl->generic.type == CTRL_LISTBOX) {
- HWND hw = GetDlgItem(dp->hwnd, c->base_id+1);
- SendMessage(hw, WM_SETREDRAW, true, 0);
- InvalidateRect(hw, NULL, true);
- }
-}
-
-void dlg_set_focus(union control *ctrl, dlgparam *dp)
-{
- struct winctrl *c = dlg_findbyctrl(dp, ctrl);
- int id;
- HWND ctl;
- if (!c)
- return;
- switch (ctrl->generic.type) {
- case CTRL_EDITBOX: id = c->base_id + 1; break;
- case CTRL_RADIO:
- for (id = c->base_id + ctrl->radio.nbuttons; id > 1; id--)
- if (IsDlgButtonChecked(dp->hwnd, id))
- break;
- /*
- * In the theoretically-unlikely case that no button was
- * selected, id should come out of this as 1, which is a
- * reasonable enough choice.
- */
- break;
- case CTRL_CHECKBOX: id = c->base_id; break;
- case CTRL_BUTTON: id = c->base_id; break;
- case CTRL_LISTBOX: id = c->base_id + 1; break;
- case CTRL_FILESELECT: id = c->base_id + 1; break;
- case CTRL_FONTSELECT: id = c->base_id + 2; break;
- default: id = c->base_id; break;
- }
- ctl = GetDlgItem(dp->hwnd, id);
- SetFocus(ctl);
-}
-
-/*
- * During event processing, you might well want to give an error
- * indication to the user. dlg_beep() is a quick and easy generic
- * error; dlg_error() puts up a message-box or equivalent.
- */
-void dlg_beep(dlgparam *dp)
-{
- MessageBeep(0);
-}
-
-void dlg_error_msg(dlgparam *dp, const char *msg)
-{
- MessageBox(dp->hwnd, msg,
- dp->errtitle ? dp->errtitle : NULL,
- MB_OK | MB_ICONERROR);
-}
-
-/*
- * This function signals to the front end that the dialog's
- * processing is completed, and passes an integer value (typically
- * a success status).
- */
-void dlg_end(dlgparam *dp, int value)
-{
- dp->ended = true;
- dp->endresult = value;
-}
-
-void dlg_refresh(union control *ctrl, dlgparam *dp)
-{
- int i, j;
- struct winctrl *c;
-
- if (!ctrl) {
- /*
- * Send EVENT_REFRESH to absolutely everything.
- */
- for (j = 0; j < dp->nctrltrees; j++) {
- for (i = 0;
- (c = winctrl_findbyindex(dp->controltrees[j], i)) != NULL;
- i++) {
- if (c->ctrl && c->ctrl->generic.handler != NULL)
- c->ctrl->generic.handler(c->ctrl, dp,
- dp->data, EVENT_REFRESH);
- }
- }
- } else {
- /*
- * Send EVENT_REFRESH to a specific control.
- */
- if (ctrl->generic.handler != NULL)
- ctrl->generic.handler(ctrl, dp, dp->data, EVENT_REFRESH);
- }
-}
-
-void dlg_coloursel_start(union control *ctrl, dlgparam *dp, int r, int g, int b)
-{
- dp->coloursel_wanted = true;
- dp->coloursel_result.r = r;
- dp->coloursel_result.g = g;
- dp->coloursel_result.b = b;
-}
-
-bool dlg_coloursel_results(union control *ctrl, dlgparam *dp,
- int *r, int *g, int *b)
-{
- if (dp->coloursel_result.ok) {
- *r = dp->coloursel_result.r;
- *g = dp->coloursel_result.g;
- *b = dp->coloursel_result.b;
- return true;
- } else
- return false;
-}
-
-void dlg_auto_set_fixed_pitch_flag(dlgparam *dp)
-{
- Conf *conf = (Conf *)dp->data;
- FontSpec *fs;
- int quality;
- HFONT hfont;
- HDC hdc;
- TEXTMETRIC tm;
- bool is_var;
-
- /*
- * Attempt to load the current font, and see if it's
- * variable-pitch. If so, start off the fixed-pitch flag for the
- * dialog box as false.
- *
- * We assume here that any client of the dlg_* mechanism which is
- * using font selectors at all is also using a normal 'Conf *'
- * as dp->data.
- */
-
- quality = conf_get_int(conf, CONF_font_quality);
- fs = conf_get_fontspec(conf, CONF_font);
-
- hfont = CreateFont(0, 0, 0, 0, FW_DONTCARE, false, false, false,
- DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
- CLIP_DEFAULT_PRECIS, FONT_QUALITY(quality),
- FIXED_PITCH | FF_DONTCARE, fs->name);
- hdc = GetDC(NULL);
- if (hdc && SelectObject(hdc, hfont) && GetTextMetrics(hdc, &tm)) {
- /* Note that the TMPF_FIXED_PITCH bit is defined upside down :-( */
- is_var = (tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
- } else {
- is_var = false; /* assume it's basically normal */
- }
- if (hdc)
- ReleaseDC(NULL, hdc);
- if (hfont)
- DeleteObject(hfont);
-
- if (is_var)
- dp->fixed_pitch_fonts = false;
-}
-
-bool dlg_get_fixed_pitch_flag(dlgparam *dp)
-{
- return dp->fixed_pitch_fonts;
-}
-
-void dlg_set_fixed_pitch_flag(dlgparam *dp, bool flag)
-{
- dp->fixed_pitch_fonts = flag;
-}
-
-void dp_init(struct dlgparam *dp)
-{
- dp->nctrltrees = 0;
- dp->data = NULL;
- dp->ended = false;
- dp->focused = dp->lastfocused = NULL;
- memset(dp->shortcuts, 0, sizeof(dp->shortcuts));
- dp->hwnd = NULL;
- dp->wintitle = dp->errtitle = NULL;
- dp->fixed_pitch_fonts = true;
-}
-
-void dp_add_tree(struct dlgparam *dp, struct winctrls *wc)
-{
- assert(dp->nctrltrees < lenof(dp->controltrees));
- dp->controltrees[dp->nctrltrees++] = wc;
-}
-
-void dp_cleanup(struct dlgparam *dp)
-{
- sfree(dp->wintitle);
- sfree(dp->errtitle);
-}
diff --git a/WINDOWS/WINDEFS.C b/WINDOWS/WINDEFS.C
deleted file mode 100644
index 006e8dc5..00000000
--- a/WINDOWS/WINDEFS.C
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * windefs.c: default settings that are specific to Windows.
- */
-
-#include "putty.h"
-
-#include <commctrl.h>
-
-FontSpec *platform_default_fontspec(const char *name)
-{
- if (!strcmp(name, "Font"))
- return fontspec_new("Courier New", false, 10, ANSI_CHARSET);
- else
- return fontspec_new("", false, 0, 0);
-}
-
-Filename *platform_default_filename(const char *name)
-{
- if (!strcmp(name, "LogFileName"))
- return filename_from_str("putty.log");
- else
- return filename_from_str("");
-}
-
-char *platform_default_s(const char *name)
-{
- if (!strcmp(name, "SerialLine"))
- return dupstr("COM1");
- return NULL;
-}
-
-bool platform_default_b(const char *name, bool def)
-{
- return def;
-}
-
-int platform_default_i(const char *name, int def)
-{
- return def;
-}
diff --git a/WINDOWS/WINDLG.C b/WINDOWS/WINDLG.C
deleted file mode 100644
index 9c5fdb76..00000000
--- a/WINDOWS/WINDLG.C
+++ /dev/null
@@ -1,1156 +0,0 @@
-/*
- * windlg.c - dialogs for PuTTY(tel), including the configuration dialog.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <assert.h>
-#include <ctype.h>
-#include <time.h>
-
-#include "putty.h"
-#include "ssh.h"
-#include "win_res.h"
-#include "winseat.h"
-#include "storage.h"
-#include "dialog.h"
-#include "licence.h"
-
-#include <commctrl.h>
-#include <commdlg.h>
-#include <shellapi.h>
-
-#ifdef MSVC4
-#define TVINSERTSTRUCT TV_INSERTSTRUCT
-#define TVITEM TV_ITEM
-#define ICON_BIG 1
-#endif
-
-/*
- * These are the various bits of data required to handle the
- * portable-dialog stuff in the config box. Having them at file
- * scope in here isn't too bad a place to put them; if we were ever
- * to need more than one config box per process we could always
- * shift them to a per-config-box structure stored in GWL_USERDATA.
- */
-static struct controlbox *ctrlbox;
-/*
- * ctrls_base holds the OK and Cancel buttons: the controls which
- * are present in all dialog panels. ctrls_panel holds the ones
- * which change from panel to panel.
- */
-static struct winctrls ctrls_base, ctrls_panel;
-static struct dlgparam dp;
-
-#define LOGEVENT_INITIAL_MAX 128
-#define LOGEVENT_CIRCULAR_MAX 128
-
-static char *events_initial[LOGEVENT_INITIAL_MAX];
-static char *events_circular[LOGEVENT_CIRCULAR_MAX];
-static int ninitial = 0, ncircular = 0, circular_first = 0;
-
-#define PRINTER_DISABLED_STRING "None (printing disabled)"
-
-void force_normal(HWND hwnd)
-{
- static bool recurse = false;
-
- WINDOWPLACEMENT wp;
-
- if (recurse)
- return;
- recurse = true;
-
- wp.length = sizeof(wp);
- if (GetWindowPlacement(hwnd, &wp) && wp.showCmd == SW_SHOWMAXIMIZED) {
- wp.showCmd = SW_SHOWNORMAL;
- SetWindowPlacement(hwnd, &wp);
- }
- recurse = false;
-}
-
-static char *getevent(int i)
-{
- if (i < ninitial)
- return events_initial[i];
- if ((i -= ninitial) < ncircular)
- return events_circular[(circular_first + i) % LOGEVENT_CIRCULAR_MAX];
- return NULL;
-}
-
-static HWND logbox;
-HWND event_log_window(void) { return logbox; }
-
-static INT_PTR CALLBACK LogProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- int i;
-
- switch (msg) {
- case WM_INITDIALOG: {
- char *str = dupprintf("%s Event Log", appname);
- SetWindowText(hwnd, str);
- sfree(str);
-
- static int tabs[4] = { 78, 108 };
- SendDlgItemMessage(hwnd, IDN_LIST, LB_SETTABSTOPS, 2,
- (LPARAM) tabs);
-
- for (i = 0; i < ninitial; i++)
- SendDlgItemMessage(hwnd, IDN_LIST, LB_ADDSTRING,
- 0, (LPARAM) events_initial[i]);
- for (i = 0; i < ncircular; i++)
- SendDlgItemMessage(hwnd, IDN_LIST, LB_ADDSTRING,
- 0, (LPARAM) events_circular[(circular_first + i) % LOGEVENT_CIRCULAR_MAX]);
- return 1;
- }
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- case IDCANCEL:
- logbox = NULL;
- SetActiveWindow(GetParent(hwnd));
- DestroyWindow(hwnd);
- return 0;
- case IDN_COPY:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- int selcount;
- int *selitems;
- selcount = SendDlgItemMessage(hwnd, IDN_LIST,
- LB_GETSELCOUNT, 0, 0);
- if (selcount == 0) { /* don't even try to copy zero items */
- MessageBeep(0);
- break;
- }
-
- selitems = snewn(selcount, int);
- if (selitems) {
- int count = SendDlgItemMessage(hwnd, IDN_LIST,
- LB_GETSELITEMS,
- selcount,
- (LPARAM) selitems);
- int i;
- int size;
- char *clipdata;
- static unsigned char sel_nl[] = SEL_NL;
-
- if (count == 0) { /* can't copy zero stuff */
- MessageBeep(0);
- break;
- }
-
- size = 0;
- for (i = 0; i < count; i++)
- size +=
- strlen(getevent(selitems[i])) + sizeof(sel_nl);
-
- clipdata = snewn(size, char);
- if (clipdata) {
- char *p = clipdata;
- for (i = 0; i < count; i++) {
- char *q = getevent(selitems[i]);
- int qlen = strlen(q);
- memcpy(p, q, qlen);
- p += qlen;
- memcpy(p, sel_nl, sizeof(sel_nl));
- p += sizeof(sel_nl);
- }
- write_aclip(CLIP_SYSTEM, clipdata, size, true);
- sfree(clipdata);
- }
- sfree(selitems);
-
- for (i = 0; i < (ninitial + ncircular); i++)
- SendDlgItemMessage(hwnd, IDN_LIST, LB_SETSEL,
- false, i);
- }
- }
- return 0;
- }
- return 0;
- case WM_CLOSE:
- logbox = NULL;
- SetActiveWindow(GetParent(hwnd));
- DestroyWindow(hwnd);
- return 0;
- }
- return 0;
-}
-
-static INT_PTR CALLBACK LicenceProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- switch (msg) {
- case WM_INITDIALOG: {
- char *str = dupprintf("%s Licence", appname);
- SetWindowText(hwnd, str);
- sfree(str);
- SetDlgItemText(hwnd, IDA_TEXT, LICENCE_TEXT("\r\n\r\n"));
- return 1;
- }
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- case IDCANCEL:
- EndDialog(hwnd, 1);
- return 0;
- }
- return 0;
- case WM_CLOSE:
- EndDialog(hwnd, 1);
- return 0;
- }
- return 0;
-}
-
-static INT_PTR CALLBACK AboutProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- char *str;
-
- switch (msg) {
- case WM_INITDIALOG: {
- str = dupprintf("About %s", appname);
- SetWindowText(hwnd, str);
- sfree(str);
- char *buildinfo_text = buildinfo("\r\n");
- char *text = dupprintf
- ("%s\r\n\r\n%s\r\n\r\n%s\r\n\r\n%s",
- appname, ver, buildinfo_text,
- "\251 " SHORT_COPYRIGHT_DETAILS ". All rights reserved.");
- sfree(buildinfo_text);
- SetDlgItemText(hwnd, IDA_TEXT, text);
- MakeDlgItemBorderless(hwnd, IDA_TEXT);
- sfree(text);
- return 1;
- }
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- case IDCANCEL:
- EndDialog(hwnd, true);
- return 0;
- case IDA_LICENCE:
- EnableWindow(hwnd, 0);
- DialogBox(hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
- hwnd, LicenceProc);
- EnableWindow(hwnd, 1);
- SetActiveWindow(hwnd);
- return 0;
-
- case IDA_WEB:
- /* Load web browser */
- ShellExecute(hwnd, "open",
- "https://www.chiark.greenend.org.uk/~sgtatham/putty/",
- 0, 0, SW_SHOWDEFAULT);
- return 0;
- }
- return 0;
- case WM_CLOSE:
- EndDialog(hwnd, true);
- return 0;
- }
- return 0;
-}
-
-static int SaneDialogBox(HINSTANCE hinst,
- LPCTSTR tmpl,
- HWND hwndparent,
- DLGPROC lpDialogFunc)
-{
- WNDCLASS wc;
- HWND hwnd;
- MSG msg;
- int flags;
- int ret;
- int gm;
-
- wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;
- wc.lpfnWndProc = DefDlgProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = DLGWINDOWEXTRA + 2*sizeof(LONG_PTR);
- wc.hInstance = hinst;
- wc.hIcon = NULL;
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND +1);
- wc.lpszMenuName = NULL;
- wc.lpszClassName = "PuTTYConfigBox";
- RegisterClass(&wc);
-
- hwnd = CreateDialog(hinst, tmpl, hwndparent, lpDialogFunc);
-
- SetWindowLongPtr(hwnd, BOXFLAGS, 0); /* flags */
- SetWindowLongPtr(hwnd, BOXRESULT, 0); /* result from SaneEndDialog */
-
- while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) {
- flags=GetWindowLongPtr(hwnd, BOXFLAGS);
- if (!(flags & DF_END) && !IsDialogMessage(hwnd, &msg))
- DispatchMessage(&msg);
- if (flags & DF_END)
- break;
- }
-
- if (gm == 0)
- PostQuitMessage(msg.wParam); /* We got a WM_QUIT, pass it on */
-
- ret=GetWindowLongPtr(hwnd, BOXRESULT);
- DestroyWindow(hwnd);
- return ret;
-}
-
-static void SaneEndDialog(HWND hwnd, int ret)
-{
- SetWindowLongPtr(hwnd, BOXRESULT, ret);
- SetWindowLongPtr(hwnd, BOXFLAGS, DF_END);
-}
-
-/*
- * Null dialog procedure.
- */
-static INT_PTR CALLBACK NullDlgProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- return 0;
-}
-
-enum {
- IDCX_ABOUT = IDC_ABOUT,
- IDCX_TVSTATIC,
- IDCX_TREEVIEW,
- IDCX_STDBASE,
- IDCX_PANELBASE = IDCX_STDBASE + 32
-};
-
-struct treeview_faff {
- HWND treeview;
- HTREEITEM lastat[4];
-};
-
-static HTREEITEM treeview_insert(struct treeview_faff *faff,
- int level, char *text, char *path)
-{
- TVINSERTSTRUCT ins;
- int i;
- HTREEITEM newitem;
- ins.hParent = (level > 0 ? faff->lastat[level - 1] : TVI_ROOT);
- ins.hInsertAfter = faff->lastat[level];
-#if _WIN32_IE >= 0x0400 && defined NONAMELESSUNION
-#define INSITEM DUMMYUNIONNAME.item
-#else
-#define INSITEM item
-#endif
- ins.INSITEM.mask = TVIF_TEXT | TVIF_PARAM;
- ins.INSITEM.pszText = text;
- ins.INSITEM.cchTextMax = strlen(text)+1;
- ins.INSITEM.lParam = (LPARAM)path;
- newitem = TreeView_InsertItem(faff->treeview, &ins);
- if (level > 0)
- TreeView_Expand(faff->treeview, faff->lastat[level - 1],
- (level > 1 ? TVE_COLLAPSE : TVE_EXPAND));
- faff->lastat[level] = newitem;
- for (i = level + 1; i < 4; i++)
- faff->lastat[i] = NULL;
- return newitem;
-}
-
-/*
- * Create the panelfuls of controls in the configuration box.
- */
-static void create_controls(HWND hwnd, char *path)
-{
- struct ctlpos cp;
- int index;
- int base_id;
- struct winctrls *wc;
-
- if (!path[0]) {
- /*
- * Here we must create the basic standard controls.
- */
- ctlposinit(&cp, hwnd, 3, 3, 235);
- wc = &ctrls_base;
- base_id = IDCX_STDBASE;
- } else {
- /*
- * Otherwise, we're creating the controls for a particular
- * panel.
- */
- ctlposinit(&cp, hwnd, 100, 3, 13);
- wc = &ctrls_panel;
- base_id = IDCX_PANELBASE;
- }
-
- for (index=-1; (index = ctrl_find_path(ctrlbox, path, index)) >= 0 ;) {
- struct controlset *s = ctrlbox->ctrlsets[index];
- winctrl_layout(&dp, wc, &cp, s, &base_id);
- }
-}
-
-/*
- * This function is the configuration box.
- * (Being a dialog procedure, in general it returns 0 if the default
- * dialog processing should be performed, and 1 if it should not.)
- */
-static INT_PTR CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- HWND hw, treeview;
- struct treeview_faff tvfaff;
- int ret;
-
- switch (msg) {
- case WM_INITDIALOG:
- dp.hwnd = hwnd;
- create_controls(hwnd, ""); /* Open and Cancel buttons etc */
- SetWindowText(hwnd, dp.wintitle);
- SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
- if (has_help())
- SetWindowLongPtr(hwnd, GWL_EXSTYLE,
- GetWindowLongPtr(hwnd, GWL_EXSTYLE) |
- WS_EX_CONTEXTHELP);
- else {
- HWND item = GetDlgItem(hwnd, IDC_HELPBTN);
- if (item)
- DestroyWindow(item);
- }
- SendMessage(hwnd, WM_SETICON, (WPARAM) ICON_BIG,
- (LPARAM) LoadIcon(hinst, MAKEINTRESOURCE(IDI_CFGICON)));
- /*
- * Centre the window.
- */
- { /* centre the window */
- RECT rs, rd;
-
- hw = GetDesktopWindow();
- if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
- MoveWindow(hwnd,
- (rs.right + rs.left + rd.left - rd.right) / 2,
- (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
- rd.right - rd.left, rd.bottom - rd.top, true);
- }
-
- /*
- * Create the tree view.
- */
- {
- RECT r;
- WPARAM font;
- HWND tvstatic;
-
- r.left = 3;
- r.right = r.left + 95;
- r.top = 3;
- r.bottom = r.top + 10;
- MapDialogRect(hwnd, &r);
- tvstatic = CreateWindowEx(0, "STATIC", "Cate&gory:",
- WS_CHILD | WS_VISIBLE,
- r.left, r.top,
- r.right - r.left, r.bottom - r.top,
- hwnd, (HMENU) IDCX_TVSTATIC, hinst,
- NULL);
- font = SendMessage(hwnd, WM_GETFONT, 0, 0);
- SendMessage(tvstatic, WM_SETFONT, font, MAKELPARAM(true, 0));
-
- r.left = 3;
- r.right = r.left + 95;
- r.top = 13;
- r.bottom = r.top + 219;
- MapDialogRect(hwnd, &r);
- treeview = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TREEVIEW, "",
- WS_CHILD | WS_VISIBLE |
- WS_TABSTOP | TVS_HASLINES |
- TVS_DISABLEDRAGDROP | TVS_HASBUTTONS
- | TVS_LINESATROOT |
- TVS_SHOWSELALWAYS, r.left, r.top,
- r.right - r.left, r.bottom - r.top,
- hwnd, (HMENU) IDCX_TREEVIEW, hinst,
- NULL);
- font = SendMessage(hwnd, WM_GETFONT, 0, 0);
- SendMessage(treeview, WM_SETFONT, font, MAKELPARAM(true, 0));
- tvfaff.treeview = treeview;
- memset(tvfaff.lastat, 0, sizeof(tvfaff.lastat));
- }
-
- /*
- * Set up the tree view contents.
- */
- {
- HTREEITEM hfirst = NULL;
- int i;
- char *path = NULL;
- char *firstpath = NULL;
-
- for (i = 0; i < ctrlbox->nctrlsets; i++) {
- struct controlset *s = ctrlbox->ctrlsets[i];
- HTREEITEM item;
- int j;
- char *c;
-
- if (!s->pathname[0])
- continue;
- j = path ? ctrl_path_compare(s->pathname, path) : 0;
- if (j == INT_MAX)
- continue; /* same path, nothing to add to tree */
-
- /*
- * We expect never to find an implicit path
- * component. For example, we expect never to see
- * A/B/C followed by A/D/E, because that would
- * _implicitly_ create A/D. All our path prefixes
- * are expected to contain actual controls and be
- * selectable in the treeview; so we would expect
- * to see A/D _explicitly_ before encountering
- * A/D/E.
- */
- assert(j == ctrl_path_elements(s->pathname) - 1);
-
- c = strrchr(s->pathname, '/');
- if (!c)
- c = s->pathname;
- else
- c++;
-
- item = treeview_insert(&tvfaff, j, c, s->pathname);
- if (!hfirst) {
- hfirst = item;
- firstpath = s->pathname;
- }
-
- path = s->pathname;
- }
-
- /*
- * Put the treeview selection on to the first panel in the
- * ctrlbox.
- */
- TreeView_SelectItem(treeview, hfirst);
-
- /*
- * And create the actual control set for that panel, to
- * match the initial treeview selection.
- */
- assert(firstpath); /* config.c must have given us _something_ */
- create_controls(hwnd, firstpath);
- dlg_refresh(NULL, &dp); /* and set up control values */
- }
-
- /*
- * Set focus into the first available control.
- */
- {
- int i;
- struct winctrl *c;
-
- for (i = 0; (c = winctrl_findbyindex(&ctrls_panel, i)) != NULL;
- i++) {
- if (c->ctrl) {
- dlg_set_focus(c->ctrl, &dp);
- break;
- }
- }
- }
-
- /*
- * Now we've finished creating our initial set of controls,
- * it's safe to actually show the window without risking setup
- * flicker.
- */
- ShowWindow(hwnd, SW_SHOWNORMAL);
-
- /*
- * Set the flag that activates a couple of the other message
- * handlers below, which were disabled until now to avoid
- * spurious firing during the above setup procedure.
- */
- SetWindowLongPtr(hwnd, GWLP_USERDATA, 1);
- return 0;
- case WM_LBUTTONUP:
- /*
- * Button release should trigger WM_OK if there was a
- * previous double click on the session list.
- */
- ReleaseCapture();
- if (dp.ended)
- SaneEndDialog(hwnd, dp.endresult ? 1 : 0);
- break;
- case WM_NOTIFY:
- if (LOWORD(wParam) == IDCX_TREEVIEW &&
- ((LPNMHDR) lParam)->code == TVN_SELCHANGED) {
- /*
- * Selection-change events on the treeview cause us to do
- * a flurry of control deletion and creation - but only
- * after WM_INITDIALOG has finished. The initial
- * selection-change event(s) during treeview setup are
- * ignored.
- */
- HTREEITEM i;
- TVITEM item;
- char buffer[64];
-
- if (GetWindowLongPtr(hwnd, GWLP_USERDATA) != 1)
- return 0;
-
- i = TreeView_GetSelection(((LPNMHDR) lParam)->hwndFrom);
-
- SendMessage (hwnd, WM_SETREDRAW, false, 0);
-
- item.hItem = i;
- item.pszText = buffer;
- item.cchTextMax = sizeof(buffer);
- item.mask = TVIF_TEXT | TVIF_PARAM;
- TreeView_GetItem(((LPNMHDR) lParam)->hwndFrom, &item);
- {
- /* Destroy all controls in the currently visible panel. */
- int k;
- HWND item;
- struct winctrl *c;
-
- while ((c = winctrl_findbyindex(&ctrls_panel, 0)) != NULL) {
- for (k = 0; k < c->num_ids; k++) {
- item = GetDlgItem(hwnd, c->base_id + k);
- if (item)
- DestroyWindow(item);
- }
- winctrl_rem_shortcuts(&dp, c);
- winctrl_remove(&ctrls_panel, c);
- sfree(c->data);
- sfree(c);
- }
- }
- create_controls(hwnd, (char *)item.lParam);
-
- dlg_refresh(NULL, &dp); /* set up control values */
-
- SendMessage (hwnd, WM_SETREDRAW, true, 0);
- InvalidateRect (hwnd, NULL, true);
-
- SetFocus(((LPNMHDR) lParam)->hwndFrom); /* ensure focus stays */
- return 0;
- }
- break;
- case WM_COMMAND:
- case WM_DRAWITEM:
- default: /* also handle drag list msg here */
- /*
- * Only process WM_COMMAND once the dialog is fully formed.
- */
- if (GetWindowLongPtr(hwnd, GWLP_USERDATA) == 1) {
- ret = winctrl_handle_command(&dp, msg, wParam, lParam);
- if (dp.ended && GetCapture() != hwnd)
- SaneEndDialog(hwnd, dp.endresult ? 1 : 0);
- } else
- ret = 0;
- return ret;
- case WM_HELP:
- if (!winctrl_context_help(&dp, hwnd,
- ((LPHELPINFO)lParam)->iCtrlId))
- MessageBeep(0);
- break;
- case WM_CLOSE:
- quit_help(hwnd);
- SaneEndDialog(hwnd, 0);
- return 0;
-
- /* Grrr Explorer will maximize Dialogs! */
- case WM_SIZE:
- if (wParam == SIZE_MAXIMIZED)
- force_normal(hwnd);
- return 0;
-
- }
- return 0;
-}
-
-void modal_about_box(HWND hwnd)
-{
- EnableWindow(hwnd, 0);
- DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, AboutProc);
- EnableWindow(hwnd, 1);
- SetActiveWindow(hwnd);
-}
-
-void show_help(HWND hwnd)
-{
- launch_help(hwnd, NULL);
-}
-
-void defuse_showwindow(void)
-{
- /*
- * Work around the fact that the app's first call to ShowWindow
- * will ignore the default in favour of the shell-provided
- * setting.
- */
- {
- HWND hwnd;
- hwnd = CreateDialog(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
- NULL, NullDlgProc);
- ShowWindow(hwnd, SW_HIDE);
- SetActiveWindow(hwnd);
- DestroyWindow(hwnd);
- }
-}
-
-bool do_config(Conf *conf)
-{
- bool ret;
-
- ctrlbox = ctrl_new_box();
- setup_config_box(ctrlbox, false, 0, 0);
- win_setup_config_box(ctrlbox, &dp.hwnd, has_help(), false, 0);
- dp_init(&dp);
- winctrl_init(&ctrls_base);
- winctrl_init(&ctrls_panel);
- dp_add_tree(&dp, &ctrls_base);
- dp_add_tree(&dp, &ctrls_panel);
- dp.wintitle = dupprintf("%s Configuration", appname);
- dp.errtitle = dupprintf("%s Error", appname);
- dp.data = conf;
- dlg_auto_set_fixed_pitch_flag(&dp);
- dp.shortcuts['g'] = true; /* the treeview: `Cate&gory' */
-
- ret =
- SaneDialogBox(hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL,
- GenericMainDlgProc);
-
- ctrl_free_box(ctrlbox);
- winctrl_cleanup(&ctrls_panel);
- winctrl_cleanup(&ctrls_base);
- dp_cleanup(&dp);
-
- return ret;
-}
-
-bool do_reconfig(HWND hwnd, Conf *conf, int protcfginfo)
-{
- Conf *backup_conf;
- bool ret;
- int protocol;
-
- backup_conf = conf_copy(conf);
-
- ctrlbox = ctrl_new_box();
- protocol = conf_get_int(conf, CONF_protocol);
- setup_config_box(ctrlbox, true, protocol, protcfginfo);
- win_setup_config_box(ctrlbox, &dp.hwnd, has_help(), true, protocol);
- dp_init(&dp);
- winctrl_init(&ctrls_base);
- winctrl_init(&ctrls_panel);
- dp_add_tree(&dp, &ctrls_base);
- dp_add_tree(&dp, &ctrls_panel);
- dp.wintitle = dupprintf("%s Reconfiguration", appname);
- dp.errtitle = dupprintf("%s Error", appname);
- dp.data = conf;
- dlg_auto_set_fixed_pitch_flag(&dp);
- dp.shortcuts['g'] = true; /* the treeview: `Cate&gory' */
-
- ret = SaneDialogBox(hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL,
- GenericMainDlgProc);
-
- ctrl_free_box(ctrlbox);
- winctrl_cleanup(&ctrls_base);
- winctrl_cleanup(&ctrls_panel);
- dp_cleanup(&dp);
-
- if (!ret)
- conf_copy_into(conf, backup_conf);
-
- conf_free(backup_conf);
-
- return ret;
-}
-
-static void win_gui_eventlog(LogPolicy *lp, const char *string)
-{
- char timebuf[40];
- char **location;
- struct tm tm;
-
- tm=ltime();
- strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S\t", &tm);
-
- if (ninitial < LOGEVENT_INITIAL_MAX)
- location = &events_initial[ninitial];
- else
- location = &events_circular[(circular_first + ncircular) % LOGEVENT_CIRCULAR_MAX];
-
- if (*location)
- sfree(*location);
- *location = dupcat(timebuf, string);
- if (logbox) {
- int count;
- SendDlgItemMessage(logbox, IDN_LIST, LB_ADDSTRING,
- 0, (LPARAM) *location);
- count = SendDlgItemMessage(logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
- SendDlgItemMessage(logbox, IDN_LIST, LB_SETTOPINDEX, count - 1, 0);
- }
- if (ninitial < LOGEVENT_INITIAL_MAX) {
- ninitial++;
- } else if (ncircular < LOGEVENT_CIRCULAR_MAX) {
- ncircular++;
- } else if (ncircular == LOGEVENT_CIRCULAR_MAX) {
- circular_first = (circular_first + 1) % LOGEVENT_CIRCULAR_MAX;
- sfree(events_circular[circular_first]);
- events_circular[circular_first] = dupstr("..");
- }
-}
-
-static void win_gui_logging_error(LogPolicy *lp, const char *event)
-{
- WinGuiSeat *wgs = container_of(lp, WinGuiSeat, logpolicy);
-
- /* Send 'can't open log file' errors to the terminal window.
- * (Marked as stderr, although terminal.c won't care.) */
- seat_stderr_pl(&wgs->seat, ptrlen_from_asciz(event));
- seat_stderr_pl(&wgs->seat, PTRLEN_LITERAL("\r\n"));
-}
-
-void showeventlog(HWND hwnd)
-{
- if (!logbox) {
- logbox = CreateDialog(hinst, MAKEINTRESOURCE(IDD_LOGBOX),
- hwnd, LogProc);
- ShowWindow(logbox, SW_SHOWNORMAL);
- }
- SetActiveWindow(logbox);
-}
-
-void showabout(HWND hwnd)
-{
- DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, AboutProc);
-}
-
-struct hostkey_dialog_ctx {
- const char *const *keywords;
- const char *const *values;
- FingerprintType fptype_default;
- char **fingerprints;
- const char *keydisp;
- LPCTSTR iconid;
- const char *helpctx;
-};
-
-static INT_PTR CALLBACK HostKeyMoreInfoProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- switch (msg) {
- case WM_INITDIALOG: {
- const struct hostkey_dialog_ctx *ctx =
- (const struct hostkey_dialog_ctx *)lParam;
- SetWindowLongPtr(hwnd, GWLP_USERDATA, (INT_PTR)ctx);
-
- if (ctx->fingerprints[SSH_FPTYPE_SHA256])
- SetDlgItemText(hwnd, IDC_HKI_SHA256,
- ctx->fingerprints[SSH_FPTYPE_SHA256]);
- if (ctx->fingerprints[SSH_FPTYPE_MD5])
- SetDlgItemText(hwnd, IDC_HKI_MD5,
- ctx->fingerprints[SSH_FPTYPE_MD5]);
-
- SetDlgItemText(hwnd, IDA_TEXT, ctx->keydisp);
-
- return 1;
- }
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- EndDialog(hwnd, 0);
- return 0;
- }
- return 0;
- case WM_CLOSE:
- EndDialog(hwnd, 0);
- return 0;
- }
- return 0;
-}
-
-static INT_PTR CALLBACK HostKeyDialogProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- switch (msg) {
- case WM_INITDIALOG: {
- strbuf *sb = strbuf_new();
- const struct hostkey_dialog_ctx *ctx =
- (const struct hostkey_dialog_ctx *)lParam;
- SetWindowLongPtr(hwnd, GWLP_USERDATA, (INT_PTR)ctx);
- for (int id = 100;; id++) {
- char buf[256];
-
- if (!GetDlgItemText(hwnd, id, buf, (int)lenof(buf)))
- break;
-
- strbuf_clear(sb);
- for (const char *p = buf; *p ;) {
- if (*p == '{') {
- for (size_t i = 0; ctx->keywords[i]; i++) {
- if (strstartswith(p, ctx->keywords[i])) {
- p += strlen(ctx->keywords[i]);
- put_datapl(sb, ptrlen_from_asciz(ctx->values[i]));
- goto matched;
- }
- }
- } else {
- put_byte(sb, *p++);
- }
- matched:;
- }
-
- SetDlgItemText(hwnd, id, sb->s);
- }
- strbuf_free(sb);
-
- SetDlgItemText(hwnd, IDC_HK_FINGERPRINT,
- ctx->fingerprints[ctx->fptype_default]);
- MakeDlgItemBorderless(hwnd, IDC_HK_FINGERPRINT);
-
- HANDLE icon = LoadImage(
- NULL, ctx->iconid, IMAGE_ICON,
- GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
- LR_SHARED);
- SendDlgItemMessage(hwnd, IDC_HK_ICON, STM_SETICON, (WPARAM)icon, 0);
-
- if (!has_help()) {
- HWND item = GetDlgItem(hwnd, IDHELP);
- if (item)
- DestroyWindow(item);
- }
-
- return 1;
- }
- case WM_CTLCOLORSTATIC: {
- HDC hdc = (HDC)wParam;
- HWND control = (HWND)lParam;
-
- if (GetWindowLongPtr(control, GWLP_ID) == IDC_HK_TITLE) {
- SetBkMode(hdc, TRANSPARENT);
- HFONT prev_font = (HFONT)SelectObject(
- hdc, (HFONT)GetStockObject(SYSTEM_FONT));
- LOGFONT lf;
- if (GetObject(prev_font, sizeof(lf), &lf)) {
- lf.lfWeight = FW_BOLD;
- lf.lfHeight = lf.lfHeight * 3 / 2;
- HFONT bold_font = CreateFontIndirect(&lf);
- if (bold_font)
- SelectObject(hdc, bold_font);
- }
- return (INT_PTR)GetSysColorBrush(COLOR_BTNFACE);
- }
- return 0;
- }
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDC_HK_ACCEPT:
- case IDC_HK_ONCE:
- case IDCANCEL:
- EndDialog(hwnd, LOWORD(wParam));
- return 0;
- case IDHELP: {
- const struct hostkey_dialog_ctx *ctx =
- (const struct hostkey_dialog_ctx *)
- GetWindowLongPtr(hwnd, GWLP_USERDATA);
- launch_help(hwnd, ctx->helpctx);
- return 0;
- }
- case IDC_HK_MOREINFO: {
- const struct hostkey_dialog_ctx *ctx =
- (const struct hostkey_dialog_ctx *)
- GetWindowLongPtr(hwnd, GWLP_USERDATA);
- DialogBoxParam(hinst, MAKEINTRESOURCE(IDD_HK_MOREINFO),
- hwnd, HostKeyMoreInfoProc, (LPARAM)ctx);
- }
- }
- return 0;
- case WM_CLOSE:
- EndDialog(hwnd, IDCANCEL);
- return 0;
- }
- return 0;
-}
-
-int win_seat_verify_ssh_host_key(
- Seat *seat, const char *host, int port, const char *keytype,
- char *keystr, const char *keydisp, char **fingerprints,
- void (*callback)(void *ctx, int result), void *ctx)
-{
- int ret;
-
- WinGuiSeat *wgs = container_of(seat, WinGuiSeat, seat);
-
- /*
- * Verify the key against the registry.
- */
- ret = verify_host_key(host, port, keytype, keystr);
-
- if (ret == 0) /* success - key matched OK */
- return 1;
- else {
- static const char *const keywords[] =
- { "{KEYTYPE}", "{APPNAME}", NULL };
-
- const char *values[2];
- values[0] = keytype;
- values[1] = appname;
-
- struct hostkey_dialog_ctx ctx[1];
- ctx->keywords = keywords;
- ctx->values = values;
- ctx->fingerprints = fingerprints;
- ctx->fptype_default = ssh2_pick_default_fingerprint(fingerprints);
- ctx->keydisp = keydisp;
- ctx->iconid = (ret == 2 ? IDI_WARNING : IDI_QUESTION);
- ctx->helpctx = (ret == 2 ? WINHELP_CTX_errors_hostkey_changed :
- WINHELP_CTX_errors_hostkey_absent);
- int dlgid = (ret == 2 ? IDD_HK_WRONG : IDD_HK_ABSENT);
- int mbret = DialogBoxParam(
- hinst, MAKEINTRESOURCE(dlgid), wgs->term_hwnd,
- HostKeyDialogProc, (LPARAM)ctx);
- assert(mbret==IDC_HK_ACCEPT || mbret==IDC_HK_ONCE || mbret==IDCANCEL);
- if (mbret == IDC_HK_ACCEPT) {
- store_host_key(host, port, keytype, keystr);
- return 1;
- } else if (mbret == IDC_HK_ONCE)
- return 1;
- }
- return 0; /* abandon the connection */
-}
-
-/*
- * Ask whether the selected algorithm is acceptable (since it was
- * below the configured 'warn' threshold).
- */
-int win_seat_confirm_weak_crypto_primitive(
- Seat *seat, const char *algtype, const char *algname,
- void (*callback)(void *ctx, int result), void *ctx)
-{
- static const char mbtitle[] = "%s Security Alert";
- static const char msg[] =
- "The first %s supported by the server\n"
- "is %s, which is below the configured\n"
- "warning threshold.\n"
- "Do you want to continue with this connection?\n";
- char *message, *title;
- int mbret;
-
- message = dupprintf(msg, algtype, algname);
- title = dupprintf(mbtitle, appname);
- mbret = MessageBox(NULL, message, title,
- MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2);
- socket_reselect_all();
- sfree(message);
- sfree(title);
- if (mbret == IDYES)
- return 1;
- else
- return 0;
-}
-
-int win_seat_confirm_weak_cached_hostkey(
- Seat *seat, const char *algname, const char *betteralgs,
- void (*callback)(void *ctx, int result), void *ctx)
-{
- static const char mbtitle[] = "%s Security Alert";
- static const char msg[] =
- "The first host key type we have stored for this server\n"
- "is %s, which is below the configured warning threshold.\n"
- "The server also provides the following types of host key\n"
- "above the threshold, which we do not have stored:\n"
- "%s\n"
- "Do you want to continue with this connection?\n";
- char *message, *title;
- int mbret;
-
- message = dupprintf(msg, algname, betteralgs);
- title = dupprintf(mbtitle, appname);
- mbret = MessageBox(NULL, message, title,
- MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2);
- socket_reselect_all();
- sfree(message);
- sfree(title);
- if (mbret == IDYES)
- return 1;
- else
- return 0;
-}
-
-/*
- * Ask whether to wipe a session log file before writing to it.
- * Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
- */
-static int win_gui_askappend(LogPolicy *lp, Filename *filename,
- void (*callback)(void *ctx, int result),
- void *ctx)
-{
- static const char msgtemplate[] =
- "The session log file \"%.*s\" already exists.\n"
- "You can overwrite it with a new session log,\n"
- "append your session log to the end of it,\n"
- "or disable session logging for this session.\n"
- "Hit Yes to wipe the file, No to append to it,\n"
- "or Cancel to disable logging.";
- char *message;
- char *mbtitle;
- int mbret;
-
- message = dupprintf(msgtemplate, FILENAME_MAX, filename->path);
- mbtitle = dupprintf("%s Log to File", appname);
-
- mbret = MessageBox(NULL, message, mbtitle,
- MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON3);
-
- socket_reselect_all();
-
- sfree(message);
- sfree(mbtitle);
-
- if (mbret == IDYES)
- return 2;
- else if (mbret == IDNO)
- return 1;
- else
- return 0;
-}
-
-const LogPolicyVtable win_gui_logpolicy_vt = {
- .eventlog = win_gui_eventlog,
- .askappend = win_gui_askappend,
- .logging_error = win_gui_logging_error,
- .verbose = null_lp_verbose_yes,
-};
-
-/*
- * Warn about the obsolescent key file format.
- *
- * Uniquely among these functions, this one does _not_ expect a
- * frontend handle. This means that if PuTTY is ported to a
- * platform which requires frontend handles, this function will be
- * an anomaly. Fortunately, the problem it addresses will not have
- * been present on that platform, so it can plausibly be
- * implemented as an empty function.
- */
-void old_keyfile_warning(void)
-{
- static const char mbtitle[] = "%s Key File Warning";
- static const char message[] =
- "You are loading an SSH-2 private key which has an\n"
- "old version of the file format. This means your key\n"
- "file is not fully tamperproof. Future versions of\n"
- "%s may stop supporting this private key format,\n"
- "so we recommend you convert your key to the new\n"
- "format.\n"
- "\n"
- "You can perform this conversion by loading the key\n"
- "into PuTTYgen and then saving it again.";
-
- char *msg, *title;
- msg = dupprintf(message, appname);
- title = dupprintf(mbtitle, appname);
-
- MessageBox(NULL, msg, title, MB_OK);
-
- socket_reselect_all();
-
- sfree(msg);
- sfree(title);
-}
diff --git a/WINDOWS/WINDOW.C b/WINDOWS/WINDOW.C
index 82bbe8e6..979e2ed3 100644
--- a/WINDOWS/WINDOW.C
+++ b/WINDOWS/WINDOW.C
@@ -121,11 +121,51 @@ static int offset_width, offset_height;
static bool was_zoomed = false;
static int prev_rows, prev_cols;
+<<<<<<< HEAD
static void flash_window(WinGuiSeat *wgs, int mode);
static void sys_cursor_update(WinGuiSeat *wgs);
static bool get_fullscreen_rect(WinGuiSeat *wgs, RECT *ss);
static void conf_cache_data(WinGuiSeat *wgs);
+=======
+static void flash_window(int mode);
+static void sys_cursor_update(void);
+static bool get_fullscreen_rect(RECT *ss);
+
+static int caret_x = -1, caret_y = -1;
+
+static int kbd_codepage;
+
+static Ldisc *ldisc;
+static Backend *backend;
+
+static cmdline_get_passwd_input_state cmdline_get_passwd_state;
+
+static struct unicode_data ucsdata;
+static bool session_closed;
+static bool reconfiguring = false;
+
+static const SessionSpecial *specials = NULL;
+static HMENU specials_menu = NULL;
+static int n_specials = 0;
+
+#define TIMING_TIMER_ID 1234
+static long timing_next_time;
+
+static struct {
+ HMENU menu;
+} popup_menus[2];
+enum { SYSMENU, CTXMENU };
+static HMENU savedsess_menu;
+
+static Conf *conf;
+static LogContext *logctx;
+static Terminal *term;
+
+static void conf_cache_data(void);
+static int cursor_type;
+static int vtmode;
+>>>>>>> tags/0.78
static struct sesslist sesslist; /* for saved-session menu */
@@ -139,6 +179,24 @@ DECL_WINDOWS_FUNCTION(static, HRESULT, AdjustWindowRectExForDpi, (LPRECT lpRect,
static HBITMAP caretbm;
+<<<<<<< HEAD
+=======
+static int dbltime, lasttime, lastact;
+static Mouse_Button lastbtn;
+
+/* this allows xterm-style mouse handling. */
+static bool send_raw_mouse = false;
+static int wheel_accumulator = 0;
+
+static bool pointer_indicates_raw_mouse = false;
+
+static BusyStatus busy_status = BUSY_NOT;
+
+static wchar_t *window_name, *icon_name;
+
+static int compose_state = 0;
+
+>>>>>>> tags/0.78
static UINT wm_mousewheel = WM_MOUSEWHEEL;
struct WinGuiSeatListNode wgslisthead = {
@@ -289,7 +347,13 @@ static void start_backend(WinGuiSeat *wgs)
char *error, *realhost;
int i;
+<<<<<<< HEAD
wgs->cmdline_get_passwd_state = cmdline_get_passwd_input_state_new;
+=======
+ cmdline_get_passwd_state = cmdline_get_passwd_input_state_new;
+
+ vt = backend_vt_from_conf(conf);
+>>>>>>> tags/0.78
vt = backend_vt_from_conf(wgs->conf);
@@ -308,7 +372,11 @@ static void start_backend(WinGuiSeat *wgs)
msg = dupprintf("Unable to open terminal:\n%s", error);
} else {
msg = dupprintf("Unable to open connection to\n%s\n%s",
+<<<<<<< HEAD
conf_dest(wgs->conf), error);
+=======
+ conf_dest(conf), error);
+>>>>>>> tags/0.78
}
sfree(error);
MessageBox(NULL, msg, str, MB_ICONERROR | MB_OK);
@@ -351,8 +419,13 @@ static void close_session(void *vctx)
wgs->session_closed = true;
newtitle = dupprintf("%s (inactive)", appname);
+<<<<<<< HEAD
win_set_icon_title(&wgs->termwin, newtitle, DEFAULT_CODEPAGE);
win_set_title(&wgs->termwin, newtitle, DEFAULT_CODEPAGE);
+=======
+ win_set_icon_title(wintw, newtitle, DEFAULT_CODEPAGE);
+ win_set_title(wintw, newtitle, DEFAULT_CODEPAGE);
+>>>>>>> tags/0.78
sfree(newtitle);
if (wgs->ldisc) {
@@ -514,11 +587,19 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
/*
* Process the command line.
*/
+<<<<<<< HEAD
gui_term_process_cmdline(wgs->conf, cmdline);
memset(&wgs->ucsdata, 0, sizeof(wgs->ucsdata));
conf_cache_data(wgs);
+=======
+ gui_term_process_cmdline(conf, cmdline);
+
+ memset(&ucsdata, 0, sizeof(ucsdata));
+
+ conf_cache_data();
+>>>>>>> tags/0.78
/*
* Guess some defaults for the window size. This all gets
@@ -553,9 +634,15 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
if (vt && vt->flags & BACKEND_RESIZE_FORBIDDEN)
resize_forbidden = true;
wchar_t *uappname = dup_mb_to_wc(DEFAULT_CODEPAGE, 0, appname);
+<<<<<<< HEAD
wgs->window_name = dup_mb_to_wc(DEFAULT_CODEPAGE, 0, appname);
wgs->icon_name = dup_mb_to_wc(DEFAULT_CODEPAGE, 0, appname);
if (!conf_get_bool(wgs->conf, CONF_scrollbar))
+=======
+ window_name = dup_mb_to_wc(DEFAULT_CODEPAGE, 0, appname);
+ icon_name = dup_mb_to_wc(DEFAULT_CODEPAGE, 0, appname);
+ if (!conf_get_bool(conf, CONF_scrollbar))
+>>>>>>> tags/0.78
winmode &= ~(WS_VSCROLL);
if (conf_get_int(wgs->conf, CONF_resize_action) == RESIZE_DISABLED ||
resize_forbidden)
@@ -568,40 +655,65 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
#ifdef TEST_ANSI_WINDOW
/* For developer testing of ANSI window support, pretend
* CreateWindowExW failed */
+<<<<<<< HEAD
wgs->term_hwnd = NULL;
+=======
+ wgs.term_hwnd = NULL;
+>>>>>>> tags/0.78
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
#else
unicode_window = true;
sw_PeekMessage = PeekMessageW;
sw_DispatchMessage = DispatchMessageW;
sw_DefWindowProc = DefWindowProcW;
+<<<<<<< HEAD
wgs->term_hwnd = CreateWindowExW(
+=======
+ wgs.term_hwnd = CreateWindowExW(
+>>>>>>> tags/0.78
exwinmode, terminal_window_class_w(), uappname,
winmode, CW_USEDEFAULT, CW_USEDEFAULT,
guess_width, guess_height, NULL, NULL, inst, NULL);
#endif
#if defined LEGACY_WINDOWS || defined TEST_ANSI_WINDOW
+<<<<<<< HEAD
if (!wgs->term_hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
+=======
+ if (!wgs.term_hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
+>>>>>>> tags/0.78
/* Fall back to an ANSI window, swapping in all the ANSI
* window message handling functions */
unicode_window = false;
sw_PeekMessage = PeekMessageA;
sw_DispatchMessage = DispatchMessageA;
sw_DefWindowProc = DefWindowProcA;
+<<<<<<< HEAD
wgs->term_hwnd = CreateWindowExA(
+=======
+ wgs.term_hwnd = CreateWindowExA(
+>>>>>>> tags/0.78
exwinmode, terminal_window_class_a(), appname,
winmode, CW_USEDEFAULT, CW_USEDEFAULT,
guess_width, guess_height, NULL, NULL, inst, NULL);
}
#endif
+<<<<<<< HEAD
if (!wgs->term_hwnd) {
modalfatalbox("Unable to create terminal window: %s",
win_strerror(GetLastError()));
}
memset(&wgs->dpi_info, 0, sizeof(struct _dpi_info));
init_dpi_info(wgs);
+=======
+ if (!wgs.term_hwnd) {
+ modalfatalbox("Unable to create terminal window: %s",
+ win_strerror(GetLastError()));
+ }
+ memset(&dpi_info, 0, sizeof(struct _dpi_info));
+ init_dpi_info();
+>>>>>>> tags/0.78
sfree(uappname);
}
@@ -759,6 +871,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
gui_terminal_ready(wgs->term_hwnd, &wgs->seat, wgs->backend);
+ gui_terminal_ready(wgs.term_hwnd, &wgs.seat, backend);
+
while (1) {
int n;
DWORD timeout;
@@ -837,6 +951,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
return msg.wParam; /* ... but optimiser doesn't know */
}
+<<<<<<< HEAD
static void wgs_cleanup(WinGuiSeat *wgs)
{
deinit_fonts(wgs);
@@ -847,6 +962,8 @@ static void wgs_cleanup(WinGuiSeat *wgs)
sfree(wgs);
}
+=======
+>>>>>>> tags/0.78
char *handle_restrict_acl_cmdline_prefix(char *p)
{
/*
@@ -1345,11 +1462,19 @@ static int get_font_width(HDC hdc, const TEXTMETRIC *tm)
static void init_dpi_info(WinGuiSeat *wgs)
{
+<<<<<<< HEAD
if (wgs->dpi_info.cur_dpi.x == 0 || wgs->dpi_info.cur_dpi.y == 0) {
if (p_GetDpiForMonitor && p_MonitorFromWindow) {
UINT dpiX, dpiY;
HMONITOR currentMonitor = p_MonitorFromWindow(
wgs->term_hwnd, MONITOR_DEFAULTTOPRIMARY);
+=======
+ if (dpi_info.cur_dpi.x == 0 || dpi_info.cur_dpi.y == 0) {
+ if (p_GetDpiForMonitor && p_MonitorFromWindow) {
+ UINT dpiX, dpiY;
+ HMONITOR currentMonitor = p_MonitorFromWindow(
+ wgs.term_hwnd, MONITOR_DEFAULTTOPRIMARY);
+>>>>>>> tags/0.78
if (p_GetDpiForMonitor(currentMonitor, MDT_EFFECTIVE_DPI,
&dpiX, &dpiY) == S_OK) {
wgs->dpi_info.cur_dpi.x = (int)dpiX;
@@ -1472,12 +1597,21 @@ static void init_fonts(WinGuiSeat *wgs, int pick_width, int pick_height)
/* !!! Yes the next line is right */
if (cset == OEM_CHARSET)
+<<<<<<< HEAD
wgs->ucsdata.font_codepage = GetOEMCP();
else if (TranslateCharsetInfo ((DWORD *)(ULONG_PTR)cset,
&info, TCI_SRCCHARSET))
wgs->ucsdata.font_codepage = info.ciACP;
else
wgs->ucsdata.font_codepage = -1;
+=======
+ ucsdata.font_codepage = GetOEMCP();
+ else if (TranslateCharsetInfo ((DWORD *)(ULONG_PTR)cset,
+ &info, TCI_SRCCHARSET))
+ ucsdata.font_codepage = info.ciACP;
+ else
+ ucsdata.font_codepage = -1;
+>>>>>>> tags/0.78
GetCPInfo(wgs->ucsdata.font_codepage, &cpinfo);
wgs->ucsdata.dbcs_screenfont = (cpinfo.MaxCharSize > 1);
@@ -1658,9 +1792,15 @@ static void wintw_request_resize(TermWin *tw, int w, int h)
int width, height;
/* If the window is maximized suppress resizing attempts */
+<<<<<<< HEAD
if (IsZoomed(wgs->term_hwnd)) {
if (conf_get_int(wgs->conf, CONF_resize_action) == RESIZE_TERM) {
term_resize_request_completed(wgs->term);
+=======
+ if (IsZoomed(wgs.term_hwnd)) {
+ if (conf_get_int(conf, CONF_resize_action) == RESIZE_TERM) {
+ term_resize_request_completed(term);
+>>>>>>> tags/0.78
return;
}
}
@@ -1674,13 +1814,21 @@ static void wintw_request_resize(TermWin *tw, int w, int h)
/* Sanity checks ... */
{
RECT ss;
+<<<<<<< HEAD
if (get_fullscreen_rect(wgs, &ss)) {
+=======
+ if (get_fullscreen_rect(&ss)) {
+>>>>>>> tags/0.78
/* Make sure the values aren't too big */
width = (ss.right - ss.left - extra_width) / 4;
height = (ss.bottom - ss.top - extra_height) / 6;
if (w > width || h > height) {
+<<<<<<< HEAD
term_resize_request_completed(wgs->term);
+=======
+ term_resize_request_completed(term);
+>>>>>>> tags/0.78
return;
}
if (w < 15)
@@ -1690,12 +1838,21 @@ static void wintw_request_resize(TermWin *tw, int w, int h)
}
}
+<<<<<<< HEAD
if (conf_get_int(wgs->conf, CONF_resize_action) != RESIZE_FONT &&
!IsZoomed(wgs->term_hwnd)) {
width = extra_width + font_width * w;
height = extra_height + font_height * h;
SetWindowPos(wgs->term_hwnd, NULL, 0, 0, width, height,
+=======
+ if (conf_get_int(conf, CONF_resize_action) != RESIZE_FONT &&
+ !IsZoomed(wgs.term_hwnd)) {
+ width = extra_width + font_width * w;
+ height = extra_height + font_height * h;
+
+ SetWindowPos(wgs.term_hwnd, NULL, 0, 0, width, height,
+>>>>>>> tags/0.78
SWP_NOACTIVATE | SWP_NOCOPYBITS |
SWP_NOMOVE | SWP_NOZORDER);
} else {
@@ -1704,12 +1861,21 @@ static void wintw_request_resize(TermWin *tw, int w, int h)
* terminal the new size immediately, so that reset_window
* will know what to do.
*/
+<<<<<<< HEAD
term_size(wgs->term, h, w, conf_get_int(wgs->conf, CONF_savelines));
reset_window(wgs, 0);
}
term_resize_request_completed(wgs->term);
InvalidateRect(wgs->term_hwnd, NULL, true);
+=======
+ term_size(term, h, w, conf_get_int(conf, CONF_savelines));
+ reset_window(0);
+ }
+
+ term_resize_request_completed(term);
+ InvalidateRect(wgs.term_hwnd, NULL, true);
+>>>>>>> tags/0.78
}
static void recompute_window_offset(WinGuiSeat *wgs)
@@ -1837,6 +2003,7 @@ static void reset_window(WinGuiSeat *wgs, int reinit)
wgs->dpi_info.cur_dpi.x);
rect.right += (window_border * 2);
rect.bottom += (window_border * 2);
+<<<<<<< HEAD
OffsetRect(&wgs->dpi_info.new_wnd_rect,
((wgs->dpi_info.new_wnd_rect.right -
wgs->dpi_info.new_wnd_rect.left) -
@@ -1847,6 +2014,15 @@ static void reset_window(WinGuiSeat *wgs, int reinit)
SetWindowPos(wgs->term_hwnd, NULL,
wgs->dpi_info.new_wnd_rect.left,
wgs->dpi_info.new_wnd_rect.top,
+=======
+ OffsetRect(&dpi_info.new_wnd_rect,
+ ((dpi_info.new_wnd_rect.right - dpi_info.new_wnd_rect.left) -
+ (rect.right - rect.left)) / 2,
+ ((dpi_info.new_wnd_rect.bottom - dpi_info.new_wnd_rect.top) -
+ (rect.bottom - rect.top)) / 2);
+ SetWindowPos(wgs.term_hwnd, NULL,
+ dpi_info.new_wnd_rect.left, dpi_info.new_wnd_rect.top,
+>>>>>>> tags/0.78
rect.right - rect.left, rect.bottom - rect.top,
SWP_NOZORDER);
@@ -1900,7 +2076,11 @@ static void reset_window(WinGuiSeat *wgs, int reinit)
static RECT ss;
int width, height;
+<<<<<<< HEAD
get_fullscreen_rect(wgs, &ss);
+=======
+ get_fullscreen_rect(&ss);
+>>>>>>> tags/0.78
width = (ss.right - ss.left - extra_width) / font_width;
height = (ss.bottom - ss.top - extra_height) / font_height;
@@ -2016,10 +2196,17 @@ static Mouse_Button translate_button(WinGuiSeat *wgs, Mouse_Button button)
if (button == MBT_LEFT)
return MBT_SELECT;
if (button == MBT_MIDDLE)
+<<<<<<< HEAD
return conf_get_int(wgs->conf, CONF_mouse_is_xterm) == 1 ?
MBT_PASTE : MBT_EXTEND;
if (button == MBT_RIGHT)
return conf_get_int(wgs->conf, CONF_mouse_is_xterm) == 1 ?
+=======
+ return conf_get_int(conf, CONF_mouse_is_xterm) == 1 ?
+ MBT_PASTE : MBT_EXTEND;
+ if (button == MBT_RIGHT)
+ return conf_get_int(conf, CONF_mouse_is_xterm) == 1 ?
+>>>>>>> tags/0.78
MBT_EXTEND : MBT_PASTE;
return 0; /* shouldn't happen */
}
@@ -2059,6 +2246,11 @@ static bool is_alt_pressed(void)
return false;
}
+<<<<<<< HEAD
+=======
+static bool resizing;
+
+>>>>>>> tags/0.78
static void exit_callback(void *vctx)
{
WinGuiSeat *wgs = (WinGuiSeat *)vctx;
@@ -2088,6 +2280,14 @@ static void exit_callback(void *vctx)
}
static void win_seat_notify_remote_exit(Seat *seat)
+<<<<<<< HEAD
+=======
+{
+ queue_toplevel_callback(exit_callback, NULL);
+}
+
+void timer_change_notify(unsigned long next)
+>>>>>>> tags/0.78
{
WinGuiSeat *wgs = container_of(seat, WinGuiSeat, seat);
queue_toplevel_callback(exit_callback, wgs);
@@ -2256,7 +2456,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
int size;
serbuf = strbuf_new();
+<<<<<<< HEAD
conf_serialise(BinarySink_UPCAST(serbuf), wgs->conf);
+=======
+ conf_serialise(BinarySink_UPCAST(serbuf), conf);
+>>>>>>> tags/0.78
size = serbuf->len;
sa.nLength = sizeof(sa);
@@ -2348,8 +2552,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
{
/* Disable full-screen if resizing forbidden */
int i;
+<<<<<<< HEAD
for (i = 0; i < lenof(wgs->popup_menus); i++)
EnableMenuItem(wgs->popup_menus[i].menu, IDM_FULLSCREEN,
+=======
+ for (i = 0; i < lenof(popup_menus); i++)
+ EnableMenuItem(popup_menus[i].menu, IDM_FULLSCREEN,
+>>>>>>> tags/0.78
MF_BYCOMMAND |
(resize_action == RESIZE_DISABLED
? MF_GRAYED : MF_ENABLED));
@@ -2366,9 +2575,15 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
* Flush the line discipline's edit buffer in the
* case where local editing has just been disabled.
*/
+<<<<<<< HEAD
if (wgs->ldisc) {
ldisc_configure(wgs->ldisc, wgs->conf);
ldisc_echoedit_update(wgs->ldisc);
+=======
+ if (ldisc) {
+ ldisc_configure(ldisc, conf);
+ ldisc_echoedit_update(ldisc);
+>>>>>>> tags/0.78
}
if (conf_get_bool(wgs->conf, CONF_system_colour) !=
@@ -2412,9 +2627,15 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
GetWindowLongPtr(hwnd, GWL_EXSTYLE);
nexflag = exflag;
+<<<<<<< HEAD
if (conf_get_bool(wgs->conf, CONF_alwaysontop) !=
conf_get_bool(prev_conf, CONF_alwaysontop)) {
if (conf_get_bool(wgs->conf, CONF_alwaysontop)) {
+=======
+ if (conf_get_bool(conf, CONF_alwaysontop) !=
+ conf_get_bool(prev_conf, CONF_alwaysontop)) {
+ if (conf_get_bool(conf, CONF_alwaysontop)) {
+>>>>>>> tags/0.78
nexflag |= WS_EX_TOPMOST;
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE);
@@ -2424,13 +2645,21 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
SWP_NOMOVE | SWP_NOSIZE);
}
}
+<<<<<<< HEAD
if (conf_get_bool(wgs->conf, CONF_sunken_edge))
+=======
+ if (conf_get_bool(conf, CONF_sunken_edge))
+>>>>>>> tags/0.78
nexflag |= WS_EX_CLIENTEDGE;
else
nexflag &= ~(WS_EX_CLIENTEDGE);
nflg = flag;
+<<<<<<< HEAD
if (conf_get_bool(wgs->conf, is_full_screen(wgs) ?
+=======
+ if (conf_get_bool(conf, is_full_screen() ?
+>>>>>>> tags/0.78
CONF_scrollbar_in_fullscreen :
CONF_scrollbar))
nflg |= WS_VSCROLL;
@@ -2438,7 +2667,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
nflg &= ~WS_VSCROLL;
if (resize_action == RESIZE_DISABLED ||
+<<<<<<< HEAD
is_full_screen(wgs))
+=======
+ is_full_screen())
+>>>>>>> tags/0.78
nflg &= ~WS_THICKFRAME;
else
nflg |= WS_THICKFRAME;
@@ -2470,21 +2703,37 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
}
{
+<<<<<<< HEAD
FontSpec *font = conf_get_fontspec(wgs->conf, CONF_font);
+=======
+ FontSpec *font = conf_get_fontspec(conf, CONF_font);
+>>>>>>> tags/0.78
FontSpec *prev_font = conf_get_fontspec(prev_conf,
CONF_font);
if (!strcmp(font->name, prev_font->name) ||
+<<<<<<< HEAD
!strcmp(conf_get_str(wgs->conf, CONF_line_codepage),
+=======
+ !strcmp(conf_get_str(conf, CONF_line_codepage),
+>>>>>>> tags/0.78
conf_get_str(prev_conf, CONF_line_codepage)) ||
font->isbold != prev_font->isbold ||
font->height != prev_font->height ||
font->charset != prev_font->charset ||
+<<<<<<< HEAD
conf_get_int(wgs->conf, CONF_font_quality) !=
conf_get_int(prev_conf, CONF_font_quality) ||
conf_get_int(wgs->conf, CONF_vtmode) !=
conf_get_int(prev_conf, CONF_vtmode) ||
conf_get_int(wgs->conf, CONF_bold_style) !=
+=======
+ conf_get_int(conf, CONF_font_quality) !=
+ conf_get_int(prev_conf, CONF_font_quality) ||
+ conf_get_int(conf, CONF_vtmode) !=
+ conf_get_int(prev_conf, CONF_vtmode) ||
+ conf_get_int(conf, CONF_bold_style) !=
+>>>>>>> tags/0.78
conf_get_int(prev_conf, CONF_bold_style) ||
resize_action == RESIZE_DISABLED ||
resize_action == RESIZE_EITHER ||
@@ -2582,9 +2831,15 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
POINT cursorpos;
/* Just in case this happened in mid-select */
+<<<<<<< HEAD
term_cancel_selection_drag(wgs->term);
show_mouseptr(wgs, true); /* make sure pointer is visible */
+=======
+ term_cancel_selection_drag(term);
+
+ show_mouseptr(true); /* make sure pointer is visible */
+>>>>>>> tags/0.78
GetCursorPos(&cursorpos);
TrackPopupMenu(wgs->popup_menus[CTXMENU].menu,
TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON,
@@ -2664,7 +2919,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
if (pt.x == 0 && pt.y == 0) {
mouse_on_hotspot = true;
}
+<<<<<<< HEAD
if (is_full_screen(wgs) && press &&
+=======
+ if (is_full_screen() && press &&
+>>>>>>> tags/0.78
button == MBT_LEFT && mouse_on_hotspot) {
SendMessage(hwnd, WM_SYSCOMMAND, SC_MOUSEMENU,
MAKELPARAM(pt.x, pt.y));
@@ -2698,7 +2957,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
static LPARAM lp = 0;
if (wParam != wp || lParam != lp ||
last_mousemove != WM_MOUSEMOVE) {
+<<<<<<< HEAD
show_mouseptr(wgs, true);
+=======
+ show_mouseptr(true);
+>>>>>>> tags/0.78
wp = wParam; lp = lParam;
last_mousemove = WM_MOUSEMOVE;
}
@@ -2729,7 +2992,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
static LPARAM lp = 0;
if (wParam != wp || lParam != lp ||
last_mousemove != WM_NCMOUSEMOVE) {
+<<<<<<< HEAD
show_mouseptr(wgs, true);
+=======
+ show_mouseptr(true);
+>>>>>>> tags/0.78
wp = wParam; lp = lParam;
last_mousemove = WM_NCMOUSEMOVE;
}
@@ -2749,8 +3016,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
HideCaret(hwnd);
hdc = BeginPaint(hwnd, &p);
+<<<<<<< HEAD
if (wgs->pal) {
SelectPalette(hdc, wgs->pal, true);
+=======
+ if (pal) {
+ SelectPalette(hdc, pal, true);
+>>>>>>> tags/0.78
RealizePalette(hdc);
}
@@ -2805,10 +3077,17 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
HBRUSH fillcolour, oldbrush;
HPEN edge, oldpen;
fillcolour = CreateSolidBrush (
+<<<<<<< HEAD
wgs->colours[ATTR_DEFBG>>ATTR_BGSHIFT]);
oldbrush = SelectObject(hdc, fillcolour);
edge = CreatePen(PS_SOLID, 0,
wgs->colours[ATTR_DEFBG>>ATTR_BGSHIFT]);
+=======
+ colours[ATTR_DEFBG>>ATTR_BGSHIFT]);
+ oldbrush = SelectObject(hdc, fillcolour);
+ edge = CreatePen(PS_SOLID, 0,
+ colours[ATTR_DEFBG>>ATTR_BGSHIFT]);
+>>>>>>> tags/0.78
oldpen = SelectObject(hdc, edge);
/*
@@ -2824,8 +3103,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
ExcludeClipRect(hdc,
offset_width, offset_height,
+<<<<<<< HEAD
offset_width+font_width*wgs->term->cols,
offset_height+font_height*wgs->term->rows);
+=======
+ offset_width+font_width*term->cols,
+ offset_height+font_height*term->rows);
+>>>>>>> tags/0.78
Rectangle(hdc, p.rcPaint.left, p.rcPaint.top,
p.rcPaint.right, p.rcPaint.bottom);
@@ -3008,10 +3292,17 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
}
if (wParam == SIZE_MINIMIZED)
sw_SetWindowText(hwnd,
+<<<<<<< HEAD
conf_get_bool(wgs->conf, CONF_win_name_always) ?
wgs->window_name : wgs->icon_name);
if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)
sw_SetWindowText(hwnd, wgs->window_name);
+=======
+ conf_get_bool(conf, CONF_win_name_always) ?
+ window_name : icon_name);
+ if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)
+ sw_SetWindowText(hwnd, window_name);
+>>>>>>> tags/0.78
if (wParam == SIZE_RESTORED) {
processed_resize = false;
clear_full_screen(wgs);
@@ -3288,20 +3579,32 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
* instead we send the characters one by one.
*/
/* don't divide SURROGATE PAIR */
+<<<<<<< HEAD
if (wgs->ldisc) {
+=======
+ if (ldisc) {
+>>>>>>> tags/0.78
for (i = 0; i < n; i += 2) {
WCHAR hs = *(unsigned short *)(buff+i);
if (IS_HIGH_SURROGATE(hs) && i+2 < n) {
WCHAR ls = *(unsigned short *)(buff+i+2);
if (IS_LOW_SURROGATE(ls)) {
term_keyinputw(
+<<<<<<< HEAD
wgs->term, (unsigned short *)(buff+i), 2);
+=======
+ term, (unsigned short *)(buff+i), 2);
+>>>>>>> tags/0.78
i += 2;
continue;
}
}
term_keyinputw(
+<<<<<<< HEAD
wgs->term, (unsigned short *)(buff+i), 1);
+=======
+ term, (unsigned short *)(buff+i), 1);
+>>>>>>> tags/0.78
}
}
free(buff);
@@ -3347,9 +3650,15 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
}
} else {
char c = (unsigned char)wParam;
+<<<<<<< HEAD
term_seen_key_event(wgs->term);
if (wgs->ldisc)
term_keyinput(wgs->term, CP_ACP, &c, 1);
+=======
+ term_seen_key_event(term);
+ if (ldisc)
+ term_keyinput(term, CP_ACP, &c, 1);
+>>>>>>> tags/0.78
}
return 0;
case WM_SYSCOLORCHANGE:
@@ -4280,11 +4589,19 @@ static int TranslateKey(WinGuiSeat *wgs, UINT message, WPARAM wParam,
}
if (wParam == compose_keycode) {
+<<<<<<< HEAD
if (wgs->compose_state == 0 &&
(HIWORD(lParam) & (KF_UP | KF_REPEAT)) == 0)
wgs->compose_state = 1;
else if (wgs->compose_state == 1 && (HIWORD(lParam) & KF_UP))
wgs->compose_state = 2;
+=======
+ if (compose_state == 0 &&
+ (HIWORD(lParam) & (KF_UP | KF_REPEAT)) == 0)
+ compose_state = 1;
+ else if (compose_state == 1 && (HIWORD(lParam) & KF_UP))
+ compose_state = 2;
+>>>>>>> tags/0.78
else
wgs->compose_state = 0;
} else if (wgs->compose_state == 1 && wParam != VK_CONTROL)
@@ -4592,7 +4909,11 @@ static int TranslateKey(WinGuiSeat *wgs, UINT message, WPARAM wParam,
case VK_F20: fkey_number = 20; goto numbered_function_key;
numbered_function_key:
consumed_alt = false;
+<<<<<<< HEAD
p += format_function_key((char *)p, wgs->term, fkey_number,
+=======
+ p += format_function_key((char *)p, term, fkey_number,
+>>>>>>> tags/0.78
shift_state & 1, shift_state & 2,
left_alt, &consumed_alt);
if (consumed_alt)
@@ -4611,7 +4932,11 @@ static int TranslateKey(WinGuiSeat *wgs, UINT message, WPARAM wParam,
if (shift_state & 2)
break;
+<<<<<<< HEAD
p += format_small_keypad_key((char *)p, wgs->term, sk_key,
+=======
+ p += format_small_keypad_key((char *)p, term, sk_key,
+>>>>>>> tags/0.78
shift_state & 1, shift_state & 2,
left_alt, &consumed_alt);
if (consumed_alt)
@@ -4626,7 +4951,11 @@ static int TranslateKey(WinGuiSeat *wgs, UINT message, WPARAM wParam,
case VK_CLEAR: xkey = 'G'; goto arrow_key; /* close enough */
arrow_key:
consumed_alt = false;
+<<<<<<< HEAD
p += format_arrow_key((char *)p, wgs->term, xkey, shift_state & 1,
+=======
+ p += format_arrow_key((char *)p, term, xkey, shift_state & 1,
+>>>>>>> tags/0.78
shift_state & 2, left_alt, &consumed_alt);
if (consumed_alt)
left_alt = false; /* supersedes the usual prefixing of Esc */
@@ -4807,6 +5136,7 @@ static int TranslateKey(WinGuiSeat *wgs, UINT message, WPARAM wParam,
static void wintw_set_title(TermWin *tw, const char *title, int codepage)
{
+<<<<<<< HEAD
WinGuiSeat *wgs = container_of(tw, WinGuiSeat, termwin);
wchar_t *new_window_name = dup_mb_to_wc(codepage, 0, title);
if (!wcscmp(new_window_name, wgs->window_name)) {
@@ -4818,10 +5148,22 @@ static void wintw_set_title(TermWin *tw, const char *title, int codepage)
if (conf_get_bool(wgs->conf, CONF_win_name_always) ||
!IsIconic(wgs->term_hwnd))
sw_SetWindowText(wgs->term_hwnd, wgs->window_name);
+=======
+ wchar_t *new_window_name = dup_mb_to_wc(codepage, 0, title);
+ if (!wcscmp(new_window_name, window_name)) {
+ sfree(new_window_name);
+ return;
+ }
+ sfree(window_name);
+ window_name = new_window_name;
+ if (conf_get_bool(conf, CONF_win_name_always) || !IsIconic(wgs.term_hwnd))
+ sw_SetWindowText(wgs.term_hwnd, window_name);
+>>>>>>> tags/0.78
}
static void wintw_set_icon_title(TermWin *tw, const char *title, int codepage)
{
+<<<<<<< HEAD
WinGuiSeat *wgs = container_of(tw, WinGuiSeat, termwin);
wchar_t *new_icon_name = dup_mb_to_wc(codepage, 0, title);
if (!wcscmp(new_icon_name, wgs->icon_name)) {
@@ -4833,6 +5175,17 @@ static void wintw_set_icon_title(TermWin *tw, const char *title, int codepage)
if (!conf_get_bool(wgs->conf, CONF_win_name_always) &&
IsIconic(wgs->term_hwnd))
sw_SetWindowText(wgs->term_hwnd, wgs->icon_name);
+=======
+ wchar_t *new_icon_name = dup_mb_to_wc(codepage, 0, title);
+ if (!wcscmp(new_icon_name, icon_name)) {
+ sfree(new_icon_name);
+ return;
+ }
+ sfree(icon_name);
+ icon_name = new_icon_name;
+ if (!conf_get_bool(conf, CONF_win_name_always) && IsIconic(wgs.term_hwnd))
+ sw_SetWindowText(wgs.term_hwnd, icon_name);
+>>>>>>> tags/0.78
}
static void wintw_set_scrollbar(TermWin *tw, int total, int start, int page)
@@ -5134,7 +5487,11 @@ static void wintw_clip_write(
for (i = 0; i < OSC4_NCOLOURS; i++) {
if (palette[i] != 0) {
+<<<<<<< HEAD
const PALETTEENTRY *pe = &wgs->logpal->palPalEntry[i];
+=======
+ const PALETTEENTRY *pe = &logpal->palPalEntry[i];
+>>>>>>> tags/0.78
put_fmt(rtf, "\\red%d\\green%d\\blue%d;",
pe->peRed, pe->peGreen, pe->peBlue);
}
@@ -5684,7 +6041,11 @@ static void wintw_move(TermWin *tw, int x, int y)
int resize_action = conf_get_int(wgs->conf, CONF_resize_action);
if (resize_action == RESIZE_DISABLED ||
resize_action == RESIZE_FONT ||
+<<<<<<< HEAD
IsZoomed(wgs->term_hwnd))
+=======
+ IsZoomed(wgs.term_hwnd))
+>>>>>>> tags/0.78
return;
SetWindowPos(wgs->term_hwnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
@@ -5743,13 +6104,21 @@ static bool is_full_screen(WinGuiSeat *wgs)
/* Get the rect/size of a full screen window using the nearest available
* monitor in multimon systems; default to something sensible if only
* one monitor is present. */
+<<<<<<< HEAD
static bool get_fullscreen_rect(WinGuiSeat *wgs, RECT *ss)
+=======
+static bool get_fullscreen_rect(RECT *ss)
+>>>>>>> tags/0.78
{
#if defined(MONITOR_DEFAULTTONEAREST) && !defined(NO_MULTIMON)
if (p_GetMonitorInfoA && p_MonitorFromWindow) {
HMONITOR mon;
MONITORINFO mi;
+<<<<<<< HEAD
mon = p_MonitorFromWindow(wgs->term_hwnd, MONITOR_DEFAULTTONEAREST);
+=======
+ mon = p_MonitorFromWindow(wgs.term_hwnd, MONITOR_DEFAULTTONEAREST);
+>>>>>>> tags/0.78
mi.cbSize = sizeof(mi);
p_GetMonitorInfoA(mon, &mi);
@@ -5778,7 +6147,11 @@ static void make_full_screen(WinGuiSeat *wgs)
assert(IsZoomed(wgs->term_hwnd));
+<<<<<<< HEAD
if (is_full_screen(wgs))
+=======
+ if (is_full_screen())
+>>>>>>> tags/0.78
return;
/* Remove the window furniture. */
@@ -5791,8 +6164,13 @@ static void make_full_screen(WinGuiSeat *wgs)
SetWindowLongPtr(wgs->term_hwnd, GWL_STYLE, style);
/* Resize ourselves to exactly cover the nearest monitor. */
+<<<<<<< HEAD
get_fullscreen_rect(wgs, &ss);
SetWindowPos(wgs->term_hwnd, HWND_TOP, ss.left, ss.top,
+=======
+ get_fullscreen_rect(&ss);
+ SetWindowPos(wgs.term_hwnd, HWND_TOP, ss.left, ss.top,
+>>>>>>> tags/0.78
ss.right - ss.left, ss.bottom - ss.top, SWP_FRAMECHANGED);
/* We may have changed size as a result */
@@ -5860,6 +6238,7 @@ static void flip_full_screen(WinGuiSeat *wgs)
static size_t win_seat_output(Seat *seat, SeatOutputType type,
const void *data, size_t len)
{
+<<<<<<< HEAD
WinGuiSeat *wgs = container_of(seat, WinGuiSeat, seat);
return term_data(wgs->term, data, len);
}
@@ -5869,6 +6248,15 @@ static void wintw_unthrottle(TermWin *tw, size_t bufsize)
WinGuiSeat *wgs = container_of(tw, WinGuiSeat, termwin);
if (wgs->backend)
backend_unthrottle(wgs->backend, bufsize);
+=======
+ return term_data(term, data, len);
+}
+
+static void wintw_unthrottle(TermWin *win, size_t bufsize)
+{
+ if (backend)
+ backend_unthrottle(backend, bufsize);
+>>>>>>> tags/0.78
}
static bool win_seat_eof(Seat *seat)
@@ -5878,15 +6266,23 @@ static bool win_seat_eof(Seat *seat)
static SeatPromptResult win_seat_get_userpass_input(Seat *seat, prompts_t *p)
{
+<<<<<<< HEAD
WinGuiSeat *wgs = container_of(seat, WinGuiSeat, seat);
SeatPromptResult spr;
spr = cmdline_get_passwd_input(p, &wgs->cmdline_get_passwd_state, true);
if (spr.kind == SPRK_INCOMPLETE)
spr = term_get_userpass_input(wgs->term, p);
+=======
+ SeatPromptResult spr;
+ spr = cmdline_get_passwd_input(p, &cmdline_get_passwd_state, true);
+ if (spr.kind == SPRK_INCOMPLETE)
+ spr = term_get_userpass_input(term, p);
+>>>>>>> tags/0.78
return spr;
}
static void win_seat_set_trust_status(Seat *seat, bool trusted)
+<<<<<<< HEAD
{
WinGuiSeat *wgs = container_of(seat, WinGuiSeat, seat);
term_set_trust_status(wgs->term, trusted);
@@ -5894,6 +6290,14 @@ static void win_seat_set_trust_status(Seat *seat, bool trusted)
static bool win_seat_can_set_trust_status(Seat *seat)
{
+=======
+{
+ term_set_trust_status(term, trusted);
+}
+
+static bool win_seat_can_set_trust_status(Seat *seat)
+{
+>>>>>>> tags/0.78
return true;
}
diff --git a/WINDOWS/WINGSS.C b/WINDOWS/WINGSS.C
deleted file mode 100644
index 79c4921c..00000000
--- a/WINDOWS/WINGSS.C
+++ /dev/null
@@ -1,703 +0,0 @@
-#ifndef NO_GSSAPI
-
-#include <limits.h>
-#include "putty.h"
-
-#define SECURITY_WIN32
-#include <security.h>
-
-#include "pgssapi.h"
-#include "sshgss.h"
-#include "sshgssc.h"
-
-#include "misc.h"
-
-#define UNIX_EPOCH 11644473600ULL /* Seconds from Windows epoch */
-#define CNS_PERSEC 10000000ULL /* # 100ns per second */
-
-/*
- * Note, as a special case, 0 relative to the Windows epoch (unspecified) maps
- * to 0 relative to the POSIX epoch (unspecified)!
- */
-#define TIME_WIN_TO_POSIX(ft, t) do { \
- ULARGE_INTEGER uli; \
- uli.LowPart = (ft).dwLowDateTime; \
- uli.HighPart = (ft).dwHighDateTime; \
- if (uli.QuadPart != 0) \
- uli.QuadPart = uli.QuadPart / CNS_PERSEC - UNIX_EPOCH; \
- (t) = (time_t) uli.QuadPart; \
-} while(0)
-
-/* Windows code to set up the GSSAPI library list. */
-
-#ifdef _WIN64
-#define MIT_KERB_SUFFIX "64"
-#else
-#define MIT_KERB_SUFFIX "32"
-#endif
-
-const int ngsslibs = 3;
-const char *const gsslibnames[3] = {
- "MIT Kerberos GSSAPI"MIT_KERB_SUFFIX".DLL",
- "Microsoft SSPI SECUR32.DLL",
- "User-specified GSSAPI DLL",
-};
-const struct keyvalwhere gsslibkeywords[] = {
- { "gssapi32", 0, -1, -1 },
- { "sspi", 1, -1, -1 },
- { "custom", 2, -1, -1 },
-};
-
-DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
- AcquireCredentialsHandleA,
- (SEC_CHAR *, SEC_CHAR *, ULONG, PVOID,
- PVOID, SEC_GET_KEY_FN, PVOID, PCredHandle, PTimeStamp));
-DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
- InitializeSecurityContextA,
- (PCredHandle, PCtxtHandle, SEC_CHAR *, ULONG, ULONG,
- ULONG, PSecBufferDesc, ULONG, PCtxtHandle,
- PSecBufferDesc, PULONG, PTimeStamp));
-DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
- FreeContextBuffer,
- (PVOID));
-DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
- FreeCredentialsHandle,
- (PCredHandle));
-DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
- DeleteSecurityContext,
- (PCtxtHandle));
-DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
- QueryContextAttributesA,
- (PCtxtHandle, ULONG, PVOID));
-DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
- MakeSignature,
- (PCtxtHandle, ULONG, PSecBufferDesc, ULONG));
-DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
- VerifySignature,
- (PCtxtHandle, PSecBufferDesc, ULONG, PULONG));
-DECL_WINDOWS_FUNCTION(static, DLL_DIRECTORY_COOKIE,
- AddDllDirectory,
- (PCWSTR));
-
-typedef struct winSsh_gss_ctx {
- unsigned long maj_stat;
- unsigned long min_stat;
- CredHandle cred_handle;
- CtxtHandle context;
- PCtxtHandle context_handle;
- TimeStamp expiry;
-} winSsh_gss_ctx;
-
-
-const Ssh_gss_buf gss_mech_krb5={9,"\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"};
-
-const char *gsslogmsg = NULL;
-
-static void ssh_sspi_bind_fns(struct ssh_gss_library *lib);
-
-static tree234 *libraries_to_never_unload;
-static int library_to_never_unload_cmp(void *av, void *bv)
-{
- uintptr_t a = (uintptr_t)av, b = (uintptr_t)bv;
- return a < b ? -1 : a > b ? +1 : 0;
-}
-static void ensure_library_tree_exists(void)
-{
- if (!libraries_to_never_unload)
- libraries_to_never_unload = newtree234(library_to_never_unload_cmp);
-}
-static bool library_is_in_never_unload_tree(HMODULE module)
-{
- ensure_library_tree_exists();
- return find234(libraries_to_never_unload, module, NULL);
-}
-static void add_library_to_never_unload_tree(HMODULE module)
-{
- ensure_library_tree_exists();
- add234(libraries_to_never_unload, module);
-}
-
-struct ssh_gss_liblist *ssh_gss_setup(Conf *conf)
-{
- HMODULE module;
- HKEY regkey;
- struct ssh_gss_liblist *list = snew(struct ssh_gss_liblist);
- char *path;
- static HMODULE kernel32_module;
- if (!kernel32_module) {
- kernel32_module = load_system32_dll("kernel32.dll");
- }
-#if defined _MSC_VER && _MSC_VER < 1900
- /* Omit the type-check because older MSVCs don't have this function */
- GET_WINDOWS_FUNCTION_NO_TYPECHECK(kernel32_module, AddDllDirectory);
-#else
- GET_WINDOWS_FUNCTION(kernel32_module, AddDllDirectory);
-#endif
-
- list->libraries = snewn(3, struct ssh_gss_library);
- list->nlibraries = 0;
-
- /* MIT Kerberos GSSAPI implementation */
- module = NULL;
- if (RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\MIT\\Kerberos", &regkey)
- == ERROR_SUCCESS) {
- DWORD type, size;
- LONG ret;
- char *buffer;
-
- /* Find out the string length */
- ret = RegQueryValueEx(regkey, "InstallDir", NULL, &type, NULL, &size);
-
- if (ret == ERROR_SUCCESS && type == REG_SZ) {
- buffer = snewn(size + 20, char);
- ret = RegQueryValueEx(regkey, "InstallDir", NULL,
- &type, (LPBYTE)buffer, &size);
- if (ret == ERROR_SUCCESS && type == REG_SZ) {
- strcat (buffer, "\\bin");
- if(p_AddDllDirectory) {
- /* Add MIT Kerberos' path to the DLL search path,
- * it loads its own DLLs further down the road */
- wchar_t *dllPath =
- dup_mb_to_wc(DEFAULT_CODEPAGE, 0, buffer);
- p_AddDllDirectory(dllPath);
- sfree(dllPath);
- }
- strcat (buffer, "\\gssapi"MIT_KERB_SUFFIX".dll");
- module = LoadLibraryEx (buffer, NULL,
- LOAD_LIBRARY_SEARCH_SYSTEM32 |
- LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR |
- LOAD_LIBRARY_SEARCH_USER_DIRS);
-
- /*
- * The MIT Kerberos DLL suffers an internal segfault
- * for some reason if you unload and reload one within
- * the same process. So, make sure that after we load
- * this library, we never free it.
- *
- * Or rather: after we've loaded it once, if any
- * _further_ load returns the same module handle, we
- * immediately free it again (to prevent the Windows
- * API's internal reference count growing without
- * bound). But on the other hand we never free it in
- * ssh_gss_cleanup.
- */
- if (library_is_in_never_unload_tree(module))
- FreeLibrary(module);
- add_library_to_never_unload_tree(module);
- }
- sfree(buffer);
- }
- RegCloseKey(regkey);
- }
- if (module) {
- struct ssh_gss_library *lib =
- &list->libraries[list->nlibraries++];
-
- lib->id = 0;
- lib->gsslogmsg = "Using GSSAPI from GSSAPI"MIT_KERB_SUFFIX".DLL";
- lib->handle = (void *)module;
-
-#define BIND_GSS_FN(name) \
- lib->u.gssapi.name = (t_gss_##name) GetProcAddress(module, "gss_" #name)
-
- BIND_GSS_FN(delete_sec_context);
- BIND_GSS_FN(display_status);
- BIND_GSS_FN(get_mic);
- BIND_GSS_FN(verify_mic);
- BIND_GSS_FN(import_name);
- BIND_GSS_FN(init_sec_context);
- BIND_GSS_FN(release_buffer);
- BIND_GSS_FN(release_cred);
- BIND_GSS_FN(release_name);
- BIND_GSS_FN(acquire_cred);
- BIND_GSS_FN(inquire_cred_by_mech);
-
-#undef BIND_GSS_FN
-
- ssh_gssapi_bind_fns(lib);
- }
-
- /* Microsoft SSPI Implementation */
- module = load_system32_dll("secur32.dll");
- if (module) {
- struct ssh_gss_library *lib =
- &list->libraries[list->nlibraries++];
-
- lib->id = 1;
- lib->gsslogmsg = "Using SSPI from SECUR32.DLL";
- lib->handle = (void *)module;
-
- GET_WINDOWS_FUNCTION(module, AcquireCredentialsHandleA);
- GET_WINDOWS_FUNCTION(module, InitializeSecurityContextA);
- GET_WINDOWS_FUNCTION(module, FreeContextBuffer);
- GET_WINDOWS_FUNCTION(module, FreeCredentialsHandle);
- GET_WINDOWS_FUNCTION(module, DeleteSecurityContext);
- GET_WINDOWS_FUNCTION(module, QueryContextAttributesA);
- GET_WINDOWS_FUNCTION(module, MakeSignature);
- GET_WINDOWS_FUNCTION(module, VerifySignature);
-
- ssh_sspi_bind_fns(lib);
- }
-
- /*
- * Custom GSSAPI DLL.
- */
- module = NULL;
- path = conf_get_filename(conf, CONF_ssh_gss_custom)->path;
- if (*path) {
- if(p_AddDllDirectory) {
- /* Add the custom directory as well in case it chainloads
- * some other DLLs (e.g a non-installed MIT Kerberos
- * instance) */
- int pathlen = strlen(path);
-
- while (pathlen > 0 && path[pathlen-1] != ':' &&
- path[pathlen-1] != '\\')
- pathlen--;
-
- if (pathlen > 0 && path[pathlen-1] != '\\')
- pathlen--;
-
- if (pathlen > 0) {
- char *dirpath = dupprintf("%.*s", pathlen, path);
- wchar_t *dllPath = dup_mb_to_wc(DEFAULT_CODEPAGE, 0, dirpath);
- p_AddDllDirectory(dllPath);
- sfree(dllPath);
- sfree(dirpath);
- }
- }
-
- module = LoadLibraryEx(path, NULL,
- LOAD_LIBRARY_SEARCH_SYSTEM32 |
- LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR |
- LOAD_LIBRARY_SEARCH_USER_DIRS);
- }
- if (module) {
- struct ssh_gss_library *lib =
- &list->libraries[list->nlibraries++];
-
- lib->id = 2;
- lib->gsslogmsg = dupprintf("Using GSSAPI from user-specified"
- " library '%s'", path);
- lib->handle = (void *)module;
-
-#define BIND_GSS_FN(name) \
- lib->u.gssapi.name = (t_gss_##name) GetProcAddress(module, "gss_" #name)
-
- BIND_GSS_FN(delete_sec_context);
- BIND_GSS_FN(display_status);
- BIND_GSS_FN(get_mic);
- BIND_GSS_FN(verify_mic);
- BIND_GSS_FN(import_name);
- BIND_GSS_FN(init_sec_context);
- BIND_GSS_FN(release_buffer);
- BIND_GSS_FN(release_cred);
- BIND_GSS_FN(release_name);
- BIND_GSS_FN(acquire_cred);
- BIND_GSS_FN(inquire_cred_by_mech);
-
-#undef BIND_GSS_FN
-
- ssh_gssapi_bind_fns(lib);
- }
-
-
- return list;
-}
-
-void ssh_gss_cleanup(struct ssh_gss_liblist *list)
-{
- int i;
-
- /*
- * LoadLibrary and FreeLibrary are defined to employ reference
- * counting in the case where the same library is repeatedly
- * loaded, so even in a multiple-sessions-per-process context
- * (not that we currently expect ever to have such a thing on
- * Windows) it's safe to naively FreeLibrary everything here
- * without worrying about destroying it under the feet of
- * another SSH instance still using it.
- */
- for (i = 0; i < list->nlibraries; i++) {
- if (list->libraries[i].id != 0) {
- HMODULE module = (HMODULE)list->libraries[i].handle;
- if (!library_is_in_never_unload_tree(module))
- FreeLibrary(module);
- }
- if (list->libraries[i].id == 2) {
- /* The 'custom' id involves a dynamically allocated message.
- * Note that we must cast away the 'const' to free it. */
- sfree((char *)list->libraries[i].gsslogmsg);
- }
- }
- sfree(list->libraries);
- sfree(list);
-}
-
-static Ssh_gss_stat ssh_sspi_indicate_mech(struct ssh_gss_library *lib,
- Ssh_gss_buf *mech)
-{
- *mech = gss_mech_krb5;
- return SSH_GSS_OK;
-}
-
-
-static Ssh_gss_stat ssh_sspi_import_name(struct ssh_gss_library *lib,
- char *host, Ssh_gss_name *srv_name)
-{
- char *pStr;
-
- /* Check hostname */
- if (host == NULL) return SSH_GSS_FAILURE;
-
- /* copy it into form host/FQDN */
- pStr = dupcat("host/", host);
-
- *srv_name = (Ssh_gss_name) pStr;
-
- return SSH_GSS_OK;
-}
-
-static Ssh_gss_stat ssh_sspi_acquire_cred(struct ssh_gss_library *lib,
- Ssh_gss_ctx *ctx,
- time_t *expiry)
-{
- winSsh_gss_ctx *winctx = snew(winSsh_gss_ctx);
- memset(winctx, 0, sizeof(winSsh_gss_ctx));
-
- /* prepare our "wrapper" structure */
- winctx->maj_stat = winctx->min_stat = SEC_E_OK;
- winctx->context_handle = NULL;
-
- /* Specifying no principal name here means use the credentials of
- the current logged-in user */
-
- winctx->maj_stat = p_AcquireCredentialsHandleA(NULL,
- "Kerberos",
- SECPKG_CRED_OUTBOUND,
- NULL,
- NULL,
- NULL,
- NULL,
- &winctx->cred_handle,
- NULL);
-
- if (winctx->maj_stat != SEC_E_OK) {
- p_FreeCredentialsHandle(&winctx->cred_handle);
- sfree(winctx);
- return SSH_GSS_FAILURE;
- }
-
- /* Windows does not return a valid expiration from AcquireCredentials */
- if (expiry)
- *expiry = GSS_NO_EXPIRATION;
-
- *ctx = (Ssh_gss_ctx) winctx;
- return SSH_GSS_OK;
-}
-
-static void localexp_to_exp_lifetime(TimeStamp *localexp,
- time_t *expiry, unsigned long *lifetime)
-{
- FILETIME nowUTC;
- FILETIME expUTC;
- time_t now;
- time_t exp;
- time_t delta;
-
- if (!lifetime && !expiry)
- return;
-
- GetSystemTimeAsFileTime(&nowUTC);
- TIME_WIN_TO_POSIX(nowUTC, now);
-
- if (lifetime)
- *lifetime = 0;
- if (expiry)
- *expiry = GSS_NO_EXPIRATION;
-
- /*
- * Type oddity: localexp is a pointer to 'TimeStamp', whereas
- * LocalFileTimeToFileTime expects a pointer to FILETIME. However,
- * despite having different formal type names from the compiler's
- * point of view, these two structures are specified to be
- * isomorphic in the MS documentation, so it's legitimate to copy
- * between them:
- *
- * https://msdn.microsoft.com/en-us/library/windows/desktop/aa380511(v=vs.85).aspx
- */
- {
- FILETIME localexp_ft;
- enum { vorpal_sword = 1 / (sizeof(*localexp) == sizeof(localexp_ft)) };
- memcpy(&localexp_ft, localexp, sizeof(localexp_ft));
- if (!LocalFileTimeToFileTime(&localexp_ft, &expUTC))
- return;
- }
-
- TIME_WIN_TO_POSIX(expUTC, exp);
- delta = exp - now;
- if (exp == 0 || delta <= 0)
- return;
-
- if (expiry)
- *expiry = exp;
- if (lifetime) {
- if (delta <= ULONG_MAX)
- *lifetime = (unsigned long)delta;
- else
- *lifetime = ULONG_MAX;
- }
-}
-
-static Ssh_gss_stat ssh_sspi_init_sec_context(struct ssh_gss_library *lib,
- Ssh_gss_ctx *ctx,
- Ssh_gss_name srv_name,
- int to_deleg,
- Ssh_gss_buf *recv_tok,
- Ssh_gss_buf *send_tok,
- time_t *expiry,
- unsigned long *lifetime)
-{
- winSsh_gss_ctx *winctx = (winSsh_gss_ctx *) *ctx;
- SecBuffer wsend_tok = {send_tok->length,SECBUFFER_TOKEN,send_tok->value};
- SecBuffer wrecv_tok = {recv_tok->length,SECBUFFER_TOKEN,recv_tok->value};
- SecBufferDesc output_desc={SECBUFFER_VERSION,1,&wsend_tok};
- SecBufferDesc input_desc ={SECBUFFER_VERSION,1,&wrecv_tok};
- unsigned long flags=ISC_REQ_MUTUAL_AUTH|ISC_REQ_REPLAY_DETECT|
- ISC_REQ_CONFIDENTIALITY|ISC_REQ_ALLOCATE_MEMORY;
- unsigned long ret_flags=0;
- TimeStamp localexp;
-
- /* check if we have to delegate ... */
- if (to_deleg) flags |= ISC_REQ_DELEGATE;
- winctx->maj_stat = p_InitializeSecurityContextA(&winctx->cred_handle,
- winctx->context_handle,
- (char*) srv_name,
- flags,
- 0, /* reserved */
- SECURITY_NATIVE_DREP,
- &input_desc,
- 0, /* reserved */
- &winctx->context,
- &output_desc,
- &ret_flags,
- &localexp);
-
- localexp_to_exp_lifetime(&localexp, expiry, lifetime);
-
- /* prepare for the next round */
- winctx->context_handle = &winctx->context;
- send_tok->value = wsend_tok.pvBuffer;
- send_tok->length = wsend_tok.cbBuffer;
-
- /* check & return our status */
- if (winctx->maj_stat==SEC_E_OK) return SSH_GSS_S_COMPLETE;
- if (winctx->maj_stat==SEC_I_CONTINUE_NEEDED) return SSH_GSS_S_CONTINUE_NEEDED;
-
- return SSH_GSS_FAILURE;
-}
-
-static Ssh_gss_stat ssh_sspi_free_tok(struct ssh_gss_library *lib,
- Ssh_gss_buf *send_tok)
-{
- /* check input */
- if (send_tok == NULL) return SSH_GSS_FAILURE;
-
- /* free Windows buffer */
- p_FreeContextBuffer(send_tok->value);
- SSH_GSS_CLEAR_BUF(send_tok);
-
- return SSH_GSS_OK;
-}
-
-static Ssh_gss_stat ssh_sspi_release_cred(struct ssh_gss_library *lib,
- Ssh_gss_ctx *ctx)
-{
- winSsh_gss_ctx *winctx= (winSsh_gss_ctx *) *ctx;
-
- /* check input */
- if (winctx == NULL) return SSH_GSS_FAILURE;
-
- /* free Windows data */
- p_FreeCredentialsHandle(&winctx->cred_handle);
- p_DeleteSecurityContext(&winctx->context);
-
- /* delete our "wrapper" structure */
- sfree(winctx);
- *ctx = (Ssh_gss_ctx) NULL;
-
- return SSH_GSS_OK;
-}
-
-
-static Ssh_gss_stat ssh_sspi_release_name(struct ssh_gss_library *lib,
- Ssh_gss_name *srv_name)
-{
- char *pStr= (char *) *srv_name;
-
- if (pStr == NULL) return SSH_GSS_FAILURE;
- sfree(pStr);
- *srv_name = (Ssh_gss_name) NULL;
-
- return SSH_GSS_OK;
-}
-
-static Ssh_gss_stat ssh_sspi_display_status(struct ssh_gss_library *lib,
- Ssh_gss_ctx ctx, Ssh_gss_buf *buf)
-{
- winSsh_gss_ctx *winctx = (winSsh_gss_ctx *) ctx;
- const char *msg;
-
- if (winctx == NULL) return SSH_GSS_FAILURE;
-
- /* decode the error code */
- switch (winctx->maj_stat) {
- case SEC_E_OK: msg="SSPI status OK"; break;
- case SEC_E_INVALID_HANDLE: msg="The handle passed to the function"
- " is invalid.";
- break;
- case SEC_E_TARGET_UNKNOWN: msg="The target was not recognized."; break;
- case SEC_E_LOGON_DENIED: msg="The logon failed."; break;
- case SEC_E_INTERNAL_ERROR: msg="The Local Security Authority cannot"
- " be contacted.";
- break;
- case SEC_E_NO_CREDENTIALS: msg="No credentials are available in the"
- " security package.";
- break;
- case SEC_E_NO_AUTHENTICATING_AUTHORITY:
- msg="No authority could be contacted for authentication."
- "The domain name of the authenticating party could be wrong,"
- " the domain could be unreachable, or there might have been"
- " a trust relationship failure.";
- break;
- case SEC_E_INSUFFICIENT_MEMORY:
- msg="One or more of the SecBufferDesc structures passed as"
- " an OUT parameter has a buffer that is too small.";
- break;
- case SEC_E_INVALID_TOKEN:
- msg="The error is due to a malformed input token, such as a"
- " token corrupted in transit, a token"
- " of incorrect size, or a token passed into the wrong"
- " security package. Passing a token to"
- " the wrong package can happen if client and server did not"
- " negotiate the proper security package.";
- break;
- default:
- msg = "Internal SSPI error";
- break;
- }
-
- buf->value = dupstr(msg);
- buf->length = strlen(buf->value);
-
- return SSH_GSS_OK;
-}
-
-static Ssh_gss_stat ssh_sspi_get_mic(struct ssh_gss_library *lib,
- Ssh_gss_ctx ctx, Ssh_gss_buf *buf,
- Ssh_gss_buf *hash)
-{
- winSsh_gss_ctx *winctx= (winSsh_gss_ctx *) ctx;
- SecPkgContext_Sizes ContextSizes;
- SecBufferDesc InputBufferDescriptor;
- SecBuffer InputSecurityToken[2];
-
- if (winctx == NULL) return SSH_GSS_FAILURE;
-
- winctx->maj_stat = 0;
-
- memset(&ContextSizes, 0, sizeof(ContextSizes));
-
- winctx->maj_stat = p_QueryContextAttributesA(&winctx->context,
- SECPKG_ATTR_SIZES,
- &ContextSizes);
-
- if (winctx->maj_stat != SEC_E_OK ||
- ContextSizes.cbMaxSignature == 0)
- return winctx->maj_stat;
-
- InputBufferDescriptor.cBuffers = 2;
- InputBufferDescriptor.pBuffers = InputSecurityToken;
- InputBufferDescriptor.ulVersion = SECBUFFER_VERSION;
- InputSecurityToken[0].BufferType = SECBUFFER_DATA;
- InputSecurityToken[0].cbBuffer = buf->length;
- InputSecurityToken[0].pvBuffer = buf->value;
- InputSecurityToken[1].BufferType = SECBUFFER_TOKEN;
- InputSecurityToken[1].cbBuffer = ContextSizes.cbMaxSignature;
- InputSecurityToken[1].pvBuffer = snewn(ContextSizes.cbMaxSignature, char);
-
- winctx->maj_stat = p_MakeSignature(&winctx->context,
- 0,
- &InputBufferDescriptor,
- 0);
-
- if (winctx->maj_stat == SEC_E_OK) {
- hash->length = InputSecurityToken[1].cbBuffer;
- hash->value = InputSecurityToken[1].pvBuffer;
- }
-
- return winctx->maj_stat;
-}
-
-static Ssh_gss_stat ssh_sspi_verify_mic(struct ssh_gss_library *lib,
- Ssh_gss_ctx ctx,
- Ssh_gss_buf *buf,
- Ssh_gss_buf *mic)
-{
- winSsh_gss_ctx *winctx= (winSsh_gss_ctx *) ctx;
- SecBufferDesc InputBufferDescriptor;
- SecBuffer InputSecurityToken[2];
- ULONG qop;
-
- if (winctx == NULL) return SSH_GSS_FAILURE;
-
- winctx->maj_stat = 0;
-
- InputBufferDescriptor.cBuffers = 2;
- InputBufferDescriptor.pBuffers = InputSecurityToken;
- InputBufferDescriptor.ulVersion = SECBUFFER_VERSION;
- InputSecurityToken[0].BufferType = SECBUFFER_DATA;
- InputSecurityToken[0].cbBuffer = buf->length;
- InputSecurityToken[0].pvBuffer = buf->value;
- InputSecurityToken[1].BufferType = SECBUFFER_TOKEN;
- InputSecurityToken[1].cbBuffer = mic->length;
- InputSecurityToken[1].pvBuffer = mic->value;
-
- winctx->maj_stat = p_VerifySignature(&winctx->context,
- &InputBufferDescriptor,
- 0, &qop);
- return winctx->maj_stat;
-}
-
-static Ssh_gss_stat ssh_sspi_free_mic(struct ssh_gss_library *lib,
- Ssh_gss_buf *hash)
-{
- sfree(hash->value);
- return SSH_GSS_OK;
-}
-
-static void ssh_sspi_bind_fns(struct ssh_gss_library *lib)
-{
- lib->indicate_mech = ssh_sspi_indicate_mech;
- lib->import_name = ssh_sspi_import_name;
- lib->release_name = ssh_sspi_release_name;
- lib->init_sec_context = ssh_sspi_init_sec_context;
- lib->free_tok = ssh_sspi_free_tok;
- lib->acquire_cred = ssh_sspi_acquire_cred;
- lib->release_cred = ssh_sspi_release_cred;
- lib->get_mic = ssh_sspi_get_mic;
- lib->verify_mic = ssh_sspi_verify_mic;
- lib->free_mic = ssh_sspi_free_mic;
- lib->display_status = ssh_sspi_display_status;
-}
-
-#else
-
-/* Dummy function so this source file defines something if NO_GSSAPI
- is defined. */
-
-void ssh_gss_init(void)
-{
-}
-
-#endif
diff --git a/WINDOWS/WINHANDL.C b/WINDOWS/WINHANDL.C
deleted file mode 100644
index 82d2aded..00000000
--- a/WINDOWS/WINHANDL.C
+++ /dev/null
@@ -1,731 +0,0 @@
-/*
- * winhandl.c: Module to give Windows front ends the general
- * ability to deal with consoles, pipes, serial ports, or any other
- * type of data stream accessed through a Windows API HANDLE rather
- * than a WinSock SOCKET.
- *
- * We do this by spawning a subthread to continuously try to read
- * from the handle. Every time a read successfully returns some
- * data, the subthread sets an event object which is picked up by
- * the main thread, and the main thread then sets an event in
- * return to instruct the subthread to resume reading.
- *
- * Output works precisely the other way round, in a second
- * subthread. The output subthread should not be attempting to
- * write all the time, because it hasn't always got data _to_
- * write; so the output thread waits for an event object notifying
- * it to _attempt_ a write, and then it sets an event in return
- * when one completes.
- *
- * (It's terribly annoying having to spawn a subthread for each
- * direction of each handle. Technically it isn't necessary for
- * serial ports, since we could use overlapped I/O within the main
- * thread and wait directly on the event objects in the OVERLAPPED
- * structures. However, we can't use this trick for some types of
- * file handle at all - for some reason Windows restricts use of
- * OVERLAPPED to files which were opened with the overlapped flag -
- * and so we must use threads for those. This being the case, it's
- * simplest just to use threads for everything rather than trying
- * to keep track of multiple completely separate mechanisms.)
- */
-
-#include <assert.h>
-
-#include "putty.h"
-
-/* ----------------------------------------------------------------------
- * Generic definitions.
- */
-
-/*
- * Maximum amount of backlog we will allow to build up on an input
- * handle before we stop reading from it.
- */
-#define MAX_BACKLOG 32768
-
-struct handle_generic {
- /*
- * Initial fields common to both handle_input and handle_output
- * structures.
- *
- * The three HANDLEs are set up at initialisation time and are
- * thereafter read-only to both main thread and subthread.
- * `moribund' is only used by the main thread; `done' is
- * written by the main thread before signalling to the
- * subthread. `defunct' and `busy' are used only by the main
- * thread.
- */
- HANDLE h; /* the handle itself */
- HANDLE ev_to_main; /* event used to signal main thread */
- HANDLE ev_from_main; /* event used to signal back to us */
- bool moribund; /* are we going to kill this soon? */
- bool done; /* request subthread to terminate */
- bool defunct; /* has the subthread already gone? */
- bool busy; /* operation currently in progress? */
- void *privdata; /* for client to remember who they are */
-};
-
-typedef enum { HT_INPUT, HT_OUTPUT, HT_FOREIGN } HandleType;
-
-/* ----------------------------------------------------------------------
- * Input threads.
- */
-
-/*
- * Data required by an input thread.
- */
-struct handle_input {
- /*
- * Copy of the handle_generic structure.
- */
- HANDLE h; /* the handle itself */
- HANDLE ev_to_main; /* event used to signal main thread */
- HANDLE ev_from_main; /* event used to signal back to us */
- bool moribund; /* are we going to kill this soon? */
- bool done; /* request subthread to terminate */
- bool defunct; /* has the subthread already gone? */
- bool busy; /* operation currently in progress? */
- void *privdata; /* for client to remember who they are */
-
- /*
- * Data set at initialisation and then read-only.
- */
- int flags;
-
- /*
- * Data set by the input thread before signalling ev_to_main,
- * and read by the main thread after receiving that signal.
- */
- char buffer[4096]; /* the data read from the handle */
- DWORD len; /* how much data that was */
- int readerr; /* lets us know about read errors */
-
- /*
- * Callback function called by this module when data arrives on
- * an input handle.
- */
- handle_inputfn_t gotdata;
-};
-
-/*
- * The actual thread procedure for an input thread.
- */
-static DWORD WINAPI handle_input_threadfunc(void *param)
-{
- struct handle_input *ctx = (struct handle_input *) param;
- OVERLAPPED ovl, *povl;
- HANDLE oev;
- bool readret, finished;
- int readlen;
-
- if (ctx->flags & HANDLE_FLAG_OVERLAPPED) {
- povl = &ovl;
- oev = CreateEvent(NULL, true, false, NULL);
- } else {
- povl = NULL;
- }
-
- if (ctx->flags & HANDLE_FLAG_UNITBUFFER)
- readlen = 1;
- else
- readlen = sizeof(ctx->buffer);
-
- while (1) {
- if (povl) {
- memset(povl, 0, sizeof(OVERLAPPED));
- povl->hEvent = oev;
- }
- readret = ReadFile(ctx->h, ctx->buffer,readlen, &ctx->len, povl);
- if (!readret)
- ctx->readerr = GetLastError();
- else
- ctx->readerr = 0;
- if (povl && !readret && ctx->readerr == ERROR_IO_PENDING) {
- WaitForSingleObject(povl->hEvent, INFINITE);
- readret = GetOverlappedResult(ctx->h, povl, &ctx->len, false);
- if (!readret)
- ctx->readerr = GetLastError();
- else
- ctx->readerr = 0;
- }
-
- if (!readret) {
- /*
- * Windows apparently sends ERROR_BROKEN_PIPE when a
- * pipe we're reading from is closed normally from the
- * writing end. This is ludicrous; if that situation
- * isn't a natural EOF, _nothing_ is. So if we get that
- * particular error, we pretend it's EOF.
- */
- if (ctx->readerr == ERROR_BROKEN_PIPE)
- ctx->readerr = 0;
- ctx->len = 0;
- }
-
- if (readret && ctx->len == 0 &&
- (ctx->flags & HANDLE_FLAG_IGNOREEOF))
- continue;
-
- /*
- * If we just set ctx->len to 0, that means the read operation
- * has returned end-of-file. Telling that to the main thread
- * will cause it to set its 'defunct' flag and dispose of the
- * handle structure at the next opportunity, in which case we
- * mustn't touch ctx at all after the SetEvent. (Hence we do
- * even _this_ check before the SetEvent.)
- */
- finished = (ctx->len == 0);
-
- SetEvent(ctx->ev_to_main);
-
- if (finished)
- break;
-
- WaitForSingleObject(ctx->ev_from_main, INFINITE);
- if (ctx->done) {
- /*
- * The main thread has asked us to shut down. Send back an
- * event indicating that we've done so. Hereafter we must
- * not touch ctx at all, because the main thread might
- * have freed it.
- */
- SetEvent(ctx->ev_to_main);
- break;
- }
- }
-
- if (povl)
- CloseHandle(oev);
-
- return 0;
-}
-
-/*
- * This is called after a successful read, or from the
- * `unthrottle' function. It decides whether or not to begin a new
- * read operation.
- */
-static void handle_throttle(struct handle_input *ctx, int backlog)
-{
- if (ctx->defunct)
- return;
-
- /*
- * If there's a read operation already in progress, do nothing:
- * when that completes, we'll come back here and be in a
- * position to make a better decision.
- */
- if (ctx->busy)
- return;
-
- /*
- * Otherwise, we must decide whether to start a new read based
- * on the size of the backlog.
- */
- if (backlog < MAX_BACKLOG) {
- SetEvent(ctx->ev_from_main);
- ctx->busy = true;
- }
-}
-
-/* ----------------------------------------------------------------------
- * Output threads.
- */
-
-/*
- * Data required by an output thread.
- */
-struct handle_output {
- /*
- * Copy of the handle_generic structure.
- */
- HANDLE h; /* the handle itself */
- HANDLE ev_to_main; /* event used to signal main thread */
- HANDLE ev_from_main; /* event used to signal back to us */
- bool moribund; /* are we going to kill this soon? */
- bool done; /* request subthread to terminate */
- bool defunct; /* has the subthread already gone? */
- bool busy; /* operation currently in progress? */
- void *privdata; /* for client to remember who they are */
-
- /*
- * Data set at initialisation and then read-only.
- */
- int flags;
-
- /*
- * Data set by the main thread before signalling ev_from_main,
- * and read by the input thread after receiving that signal.
- */
- const char *buffer; /* the data to write */
- DWORD len; /* how much data there is */
-
- /*
- * Data set by the input thread before signalling ev_to_main,
- * and read by the main thread after receiving that signal.
- */
- DWORD lenwritten; /* how much data we actually wrote */
- int writeerr; /* return value from WriteFile */
-
- /*
- * Data only ever read or written by the main thread.
- */
- bufchain queued_data; /* data still waiting to be written */
- enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof;
-
- /*
- * Callback function called when the backlog in the bufchain
- * drops.
- */
- handle_outputfn_t sentdata;
-};
-
-static DWORD WINAPI handle_output_threadfunc(void *param)
-{
- struct handle_output *ctx = (struct handle_output *) param;
- OVERLAPPED ovl, *povl;
- HANDLE oev;
- bool writeret;
-
- if (ctx->flags & HANDLE_FLAG_OVERLAPPED) {
- povl = &ovl;
- oev = CreateEvent(NULL, true, false, NULL);
- } else {
- povl = NULL;
- }
-
- while (1) {
- WaitForSingleObject(ctx->ev_from_main, INFINITE);
- if (ctx->done) {
- /*
- * The main thread has asked us to shut down. Send back an
- * event indicating that we've done so. Hereafter we must
- * not touch ctx at all, because the main thread might
- * have freed it.
- */
- SetEvent(ctx->ev_to_main);
- break;
- }
- if (povl) {
- memset(povl, 0, sizeof(OVERLAPPED));
- povl->hEvent = oev;
- }
-
- writeret = WriteFile(ctx->h, ctx->buffer, ctx->len,
- &ctx->lenwritten, povl);
- if (!writeret)
- ctx->writeerr = GetLastError();
- else
- ctx->writeerr = 0;
- if (povl && !writeret && GetLastError() == ERROR_IO_PENDING) {
- writeret = GetOverlappedResult(ctx->h, povl,
- &ctx->lenwritten, true);
- if (!writeret)
- ctx->writeerr = GetLastError();
- else
- ctx->writeerr = 0;
- }
-
- SetEvent(ctx->ev_to_main);
- if (!writeret) {
- /*
- * The write operation has suffered an error. Telling that
- * to the main thread will cause it to set its 'defunct'
- * flag and dispose of the handle structure at the next
- * opportunity, so we must not touch ctx at all after
- * this.
- */
- break;
- }
- }
-
- if (povl)
- CloseHandle(oev);
-
- return 0;
-}
-
-static void handle_try_output(struct handle_output *ctx)
-{
- if (!ctx->busy && bufchain_size(&ctx->queued_data)) {
- ptrlen data = bufchain_prefix(&ctx->queued_data);
- ctx->buffer = data.ptr;
- ctx->len = min(data.len, ~(DWORD)0);
- SetEvent(ctx->ev_from_main);
- ctx->busy = true;
- } else if (!ctx->busy && bufchain_size(&ctx->queued_data) == 0 &&
- ctx->outgoingeof == EOF_PENDING) {
- CloseHandle(ctx->h);
- ctx->h = INVALID_HANDLE_VALUE;
- ctx->outgoingeof = EOF_SENT;
- }
-}
-
-/* ----------------------------------------------------------------------
- * 'Foreign events'. These are handle structures which just contain a
- * single event object passed to us by another module such as
- * winnps.c, so that they can make use of our handle_get_events /
- * handle_got_event mechanism for communicating with application main
- * loops.
- */
-struct handle_foreign {
- /*
- * Copy of the handle_generic structure.
- */
- HANDLE h; /* the handle itself */
- HANDLE ev_to_main; /* event used to signal main thread */
- HANDLE ev_from_main; /* event used to signal back to us */
- bool moribund; /* are we going to kill this soon? */
- bool done; /* request subthread to terminate */
- bool defunct; /* has the subthread already gone? */
- bool busy; /* operation currently in progress? */
- void *privdata; /* for client to remember who they are */
-
- /*
- * Our own data, just consisting of knowledge of who to call back.
- */
- void (*callback)(void *);
- void *ctx;
-};
-
-/* ----------------------------------------------------------------------
- * Unified code handling both input and output threads.
- */
-
-struct handle {
- HandleType type;
- union {
- struct handle_generic g;
- struct handle_input i;
- struct handle_output o;
- struct handle_foreign f;
- } u;
-};
-
-static tree234 *handles_by_evtomain;
-
-static int handle_cmp_evtomain(void *av, void *bv)
-{
- struct handle *a = (struct handle *)av;
- struct handle *b = (struct handle *)bv;
-
- if ((uintptr_t)a->u.g.ev_to_main < (uintptr_t)b->u.g.ev_to_main)
- return -1;
- else if ((uintptr_t)a->u.g.ev_to_main > (uintptr_t)b->u.g.ev_to_main)
- return +1;
- else
- return 0;
-}
-
-static int handle_find_evtomain(void *av, void *bv)
-{
- HANDLE *a = (HANDLE *)av;
- struct handle *b = (struct handle *)bv;
-
- if ((uintptr_t)*a < (uintptr_t)b->u.g.ev_to_main)
- return -1;
- else if ((uintptr_t)*a > (uintptr_t)b->u.g.ev_to_main)
- return +1;
- else
- return 0;
-}
-
-struct handle *handle_input_new(HANDLE handle, handle_inputfn_t gotdata,
- void *privdata, int flags)
-{
- struct handle *h = snew(struct handle);
- DWORD in_threadid; /* required for Win9x */
-
- h->type = HT_INPUT;
- h->u.i.h = handle;
- h->u.i.ev_to_main = CreateEvent(NULL, false, false, NULL);
- h->u.i.ev_from_main = CreateEvent(NULL, false, false, NULL);
- h->u.i.gotdata = gotdata;
- h->u.i.defunct = false;
- h->u.i.moribund = false;
- h->u.i.done = false;
- h->u.i.privdata = privdata;
- h->u.i.flags = flags;
-
- if (!handles_by_evtomain)
- handles_by_evtomain = newtree234(handle_cmp_evtomain);
- add234(handles_by_evtomain, h);
-
- HANDLE hThread = CreateThread(NULL, 0, handle_input_threadfunc,
- &h->u.i, 0, &in_threadid);
- if (hThread)
- CloseHandle(hThread); /* we don't need the thread handle */
- h->u.i.busy = true;
-
- return h;
-}
-
-struct handle *handle_output_new(HANDLE handle, handle_outputfn_t sentdata,
- void *privdata, int flags)
-{
- struct handle *h = snew(struct handle);
- DWORD out_threadid; /* required for Win9x */
-
- h->type = HT_OUTPUT;
- h->u.o.h = handle;
- h->u.o.ev_to_main = CreateEvent(NULL, false, false, NULL);
- h->u.o.ev_from_main = CreateEvent(NULL, false, false, NULL);
- h->u.o.busy = false;
- h->u.o.defunct = false;
- h->u.o.moribund = false;
- h->u.o.done = false;
- h->u.o.privdata = privdata;
- bufchain_init(&h->u.o.queued_data);
- h->u.o.outgoingeof = EOF_NO;
- h->u.o.sentdata = sentdata;
- h->u.o.flags = flags;
-
- if (!handles_by_evtomain)
- handles_by_evtomain = newtree234(handle_cmp_evtomain);
- add234(handles_by_evtomain, h);
-
- HANDLE hThread = CreateThread(NULL, 0, handle_output_threadfunc,
- &h->u.o, 0, &out_threadid);
- if (hThread)
- CloseHandle(hThread); /* we don't need the thread handle */
-
- return h;
-}
-
-struct handle *handle_add_foreign_event(HANDLE event,
- void (*callback)(void *), void *ctx)
-{
- struct handle *h = snew(struct handle);
-
- h->type = HT_FOREIGN;
- h->u.f.h = INVALID_HANDLE_VALUE;
- h->u.f.ev_to_main = event;
- h->u.f.ev_from_main = INVALID_HANDLE_VALUE;
- h->u.f.defunct = true; /* we have no thread in the first place */
- h->u.f.moribund = false;
- h->u.f.done = false;
- h->u.f.privdata = NULL;
- h->u.f.callback = callback;
- h->u.f.ctx = ctx;
- h->u.f.busy = true;
-
- if (!handles_by_evtomain)
- handles_by_evtomain = newtree234(handle_cmp_evtomain);
- add234(handles_by_evtomain, h);
-
- return h;
-}
-
-size_t handle_write(struct handle *h, const void *data, size_t len)
-{
- assert(h->type == HT_OUTPUT);
- assert(h->u.o.outgoingeof == EOF_NO);
- bufchain_add(&h->u.o.queued_data, data, len);
- handle_try_output(&h->u.o);
- return bufchain_size(&h->u.o.queued_data);
-}
-
-void handle_write_eof(struct handle *h)
-{
- /*
- * This function is called when we want to proactively send an
- * end-of-file notification on the handle. We can only do this by
- * actually closing the handle - so never call this on a
- * bidirectional handle if we're still interested in its incoming
- * direction!
- */
- assert(h->type == HT_OUTPUT);
- if (h->u.o.outgoingeof == EOF_NO) {
- h->u.o.outgoingeof = EOF_PENDING;
- handle_try_output(&h->u.o);
- }
-}
-
-HANDLE *handle_get_events(int *nevents)
-{
- HANDLE *ret;
- struct handle *h;
- int i;
- size_t n, size;
-
- /*
- * Go through our tree counting the handle objects currently
- * engaged in useful activity.
- */
- ret = NULL;
- n = size = 0;
- if (handles_by_evtomain) {
- for (i = 0; (h = index234(handles_by_evtomain, i)) != NULL; i++) {
- if (h->u.g.busy) {
- sgrowarray(ret, size, n);
- ret[n++] = h->u.g.ev_to_main;
- }
- }
- }
-
- *nevents = n;
- return ret;
-}
-
-static void handle_destroy(struct handle *h)
-{
- if (h->type == HT_OUTPUT)
- bufchain_clear(&h->u.o.queued_data);
- CloseHandle(h->u.g.ev_from_main);
- CloseHandle(h->u.g.ev_to_main);
- del234(handles_by_evtomain, h);
- sfree(h);
-}
-
-void handle_free(struct handle *h)
-{
- assert(h && !h->u.g.moribund);
- if (h->u.g.busy && h->type != HT_FOREIGN) {
- /*
- * If the handle is currently busy, we cannot immediately free
- * it, because its subthread is in the middle of something.
- * (Exception: foreign handles don't have a subthread.)
- *
- * Instead we must wait until it's finished its current
- * operation, because otherwise the subthread will write to
- * invalid memory after we free its context from under it. So
- * we set the moribund flag, which will be noticed next time
- * an operation completes.
- */
- h->u.g.moribund = true;
- } else if (h->u.g.defunct) {
- /*
- * There isn't even a subthread; we can go straight to
- * handle_destroy.
- */
- handle_destroy(h);
- } else {
- /*
- * The subthread is alive but not busy, so we now signal it
- * to die. Set the moribund flag to indicate that it will
- * want destroying after that.
- */
- h->u.g.moribund = true;
- h->u.g.done = true;
- h->u.g.busy = true;
- SetEvent(h->u.g.ev_from_main);
- }
-}
-
-void handle_got_event(HANDLE event)
-{
- struct handle *h;
-
- assert(handles_by_evtomain);
- h = find234(handles_by_evtomain, &event, handle_find_evtomain);
- if (!h) {
- /*
- * This isn't an error condition. If two or more event
- * objects were signalled during the same select operation,
- * and processing of the first caused the second handle to
- * be closed, then it will sometimes happen that we receive
- * an event notification here for a handle which is already
- * deceased. In that situation we simply do nothing.
- */
- return;
- }
-
- if (h->u.g.moribund) {
- /*
- * A moribund handle is one which we have either already
- * signalled to die, or are waiting until its current I/O op
- * completes to do so. Either way, it's treated as already
- * dead from the external user's point of view, so we ignore
- * the actual I/O result. We just signal the thread to die if
- * we haven't yet done so, or destroy the handle if not.
- */
- if (h->u.g.done) {
- handle_destroy(h);
- } else {
- h->u.g.done = true;
- h->u.g.busy = true;
- SetEvent(h->u.g.ev_from_main);
- }
- return;
- }
-
- switch (h->type) {
- int backlog;
-
- case HT_INPUT:
- h->u.i.busy = false;
-
- /*
- * A signal on an input handle means data has arrived.
- */
- if (h->u.i.len == 0) {
- /*
- * EOF, or (nearly equivalently) read error.
- */
- h->u.i.defunct = true;
- h->u.i.gotdata(h, NULL, 0, h->u.i.readerr);
- } else {
- backlog = h->u.i.gotdata(h, h->u.i.buffer, h->u.i.len, 0);
- handle_throttle(&h->u.i, backlog);
- }
- break;
-
- case HT_OUTPUT:
- h->u.o.busy = false;
-
- /*
- * A signal on an output handle means we have completed a
- * write. Call the callback to indicate that the output
- * buffer size has decreased, or to indicate an error.
- */
- if (h->u.o.writeerr) {
- /*
- * Write error. Send a negative value to the callback,
- * and mark the thread as defunct (because the output
- * thread is terminating by now).
- */
- h->u.o.defunct = true;
- h->u.o.sentdata(h, 0, h->u.o.writeerr);
- } else {
- bufchain_consume(&h->u.o.queued_data, h->u.o.lenwritten);
- noise_ultralight(NOISE_SOURCE_IOLEN, h->u.o.lenwritten);
- h->u.o.sentdata(h, bufchain_size(&h->u.o.queued_data), 0);
- handle_try_output(&h->u.o);
- }
- break;
-
- case HT_FOREIGN:
- /* Just call the callback. */
- h->u.f.callback(h->u.f.ctx);
- break;
- }
-}
-
-void handle_unthrottle(struct handle *h, size_t backlog)
-{
- assert(h->type == HT_INPUT);
- handle_throttle(&h->u.i, backlog);
-}
-
-size_t handle_backlog(struct handle *h)
-{
- assert(h->type == HT_OUTPUT);
- return bufchain_size(&h->u.o.queued_data);
-}
-
-void *handle_get_privdata(struct handle *h)
-{
- return h->u.g.privdata;
-}
-
-static void handle_sink_write(BinarySink *bs, const void *data, size_t len)
-{
- handle_sink *sink = BinarySink_DOWNCAST(bs, handle_sink);
- handle_write(sink->h, data, len);
-}
-
-void handle_sink_init(handle_sink *sink, struct handle *h)
-{
- sink->h = h;
- BinarySink_INIT(sink, handle_sink_write);
-}
diff --git a/WINDOWS/WINHELP.C b/WINDOWS/WINHELP.C
deleted file mode 100644
index df6ac37b..00000000
--- a/WINDOWS/WINHELP.C
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * winhelp.c: centralised functions to launch Windows HTML Help files.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#include "putty.h"
-#include "win_res.h"
-
-#ifdef NO_HTMLHELP
-
-/* If htmlhelp.h is not available, we can't do any of this at all */
-bool has_help(void) { return false; }
-void init_help(void) { }
-void shutdown_help(void) { }
-void launch_help(HWND hwnd, const char *topic) { }
-void quit_help(HWND hwnd) { }
-
-#else
-
-#include <htmlhelp.h>
-
-static char *chm_path = NULL;
-static bool chm_created_by_us = false;
-
-static bool requested_help;
-DECL_WINDOWS_FUNCTION(static, HWND, HtmlHelpA, (HWND, LPCSTR, UINT, DWORD_PTR));
-
-static HRSRC chm_hrsrc;
-static DWORD chm_resource_size = 0;
-static const void *chm_resource = NULL;
-
-int has_embedded_chm(void)
-{
- static bool checked = false;
- if (!checked) {
- checked = true;
-
- chm_hrsrc = FindResource(
- NULL, MAKEINTRESOURCE(ID_CUSTOM_CHMFILE),
- MAKEINTRESOURCE(TYPE_CUSTOM_CHMFILE));
- }
- return chm_hrsrc != NULL ? 1 : 0;
-}
-
-static bool find_chm_resource(void)
-{
- static bool checked = false;
- if (checked) /* we've been here already */
- goto out;
- checked = true;
-
- /*
- * Look for a CHM file embedded in this executable as a custom
- * resource.
- */
- if (!has_embedded_chm()) /* set up chm_hrsrc and check if it's NULL */
- goto out;
-
- chm_resource_size = SizeofResource(NULL, chm_hrsrc);
- if (chm_resource_size == 0)
- goto out;
-
- HGLOBAL chm_hglobal = LoadResource(NULL, chm_hrsrc);
- if (chm_hglobal == NULL)
- goto out;
-
- chm_resource = (const uint8_t *)LockResource(chm_hglobal);
-
- out:
- return chm_resource != NULL;
-}
-
-static bool load_chm_resource(void)
-{
- bool toret = false;
- char *filename = NULL;
- HANDLE filehandle = INVALID_HANDLE_VALUE;
- bool created = false;
-
- static bool tried_to_load = false;
- if (tried_to_load)
- goto out;
- tried_to_load = true;
-
- /*
- * We've found it! Now write it out into a separate file, so that
- * htmlhelp.exe can handle it.
- */
-
- /* GetTempPath is documented as returning a size of up to
- * MAX_PATH+1 which does not count the NUL */
- char tempdir[MAX_PATH + 2];
- if (GetTempPath(sizeof(tempdir), tempdir) == 0)
- goto out;
-
- unsigned long pid = GetCurrentProcessId();
-
- for (uint64_t counter = 0;; counter++) {
- filename = dupprintf(
- "%s\\putty_%lu_%"PRIu64".chm", tempdir, pid, counter);
- filehandle = CreateFile(
- filename, GENERIC_WRITE, FILE_SHARE_READ,
- NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (filehandle != INVALID_HANDLE_VALUE)
- break; /* success! */
-
- if (GetLastError() != ERROR_FILE_EXISTS)
- goto out; /* failed for some other reason! */
-
- sfree(filename);
- filename = NULL;
- }
- created = true;
-
- const uint8_t *p = (const uint8_t *)chm_resource;
- for (DWORD pos = 0; pos < chm_resource_size; pos++) {
- DWORD to_write = chm_resource_size - pos;
- DWORD written = 0;
-
- if (!WriteFile(filehandle, p + pos, to_write, &written, NULL))
- goto out;
- pos += written;
- }
-
- chm_path = filename;
- filename = NULL;
- chm_created_by_us = true;
- toret = true;
-
- out:
- if (created && !toret)
- DeleteFile(filename);
- sfree(filename);
- if (filehandle != INVALID_HANDLE_VALUE)
- CloseHandle(filehandle);
- return toret;
-}
-
-static bool find_chm_from_installation(void)
-{
- static const char *const reg_paths[] = {
- "Software\\SimonTatham\\PuTTY64\\CHMPath",
- "Software\\SimonTatham\\PuTTY\\CHMPath",
- };
-
- for (size_t i = 0; i < lenof(reg_paths); i++) {
- char *filename = registry_get_string(
- HKEY_LOCAL_MACHINE, reg_paths[i], NULL);
-
- if (filename) {
- chm_path = filename;
- chm_created_by_us = false;
- return true;
- }
- }
-
- return false;
-}
-
-void init_help(void)
-{
- /* Just in case of multiple calls */
- static bool already_called = false;
- if (already_called)
- return;
- already_called = true;
-
- /*
- * Don't even try looking for the CHM file if we can't even find
- * the HtmlHelp() API function.
- */
- HINSTANCE dllHH = load_system32_dll("hhctrl.ocx");
- GET_WINDOWS_FUNCTION(dllHH, HtmlHelpA);
- if (!p_HtmlHelpA) {
- FreeLibrary(dllHH);
- return;
- }
-
- /*
- * If there's a CHM file embedded in this executable, we should
- * use that as the first choice.
- */
- if (find_chm_resource())
- return;
-
- /*
- * Otherwise, try looking for the CHM in the location that the
- * installer marked in the registry.
- */
- if (find_chm_from_installation())
- return;
-}
-
-void shutdown_help(void)
-{
- if (chm_path && chm_created_by_us) {
- p_HtmlHelpA(NULL, NULL, HH_CLOSE_ALL, 0);
- DeleteFile(chm_path);
- }
- sfree(chm_path);
- chm_path = NULL;
- chm_created_by_us = false;
-}
-
-bool has_help(void)
-{
- return chm_path != NULL || chm_resource != NULL;
-}
-
-void launch_help(HWND hwnd, const char *topic)
-{
- if (!chm_path && chm_resource) {
- /*
- * If we've been called without already having a file name for
- * the CHM file, that might be because we've located it in our
- * resource section but not written it to a temp file yet. Do
- * so now, on first use.
- */
- load_chm_resource();
- }
-
- /* If we _still_ don't have a CHM pathname, we just can't display help. */
- if (!chm_path)
- return;
-
- if (topic) {
- char *fname = dupprintf(
- "%s::/%s.html>main", chm_path, topic);
- p_HtmlHelpA(hwnd, fname, HH_DISPLAY_TOPIC, 0);
- sfree(fname);
- } else {
- p_HtmlHelpA(hwnd, chm_path, HH_DISPLAY_TOPIC, 0);
- }
- requested_help = true;
-}
-
-void quit_help(HWND hwnd)
-{
- if (requested_help)
- p_HtmlHelpA(NULL, NULL, HH_CLOSE_ALL, 0);
- if (chm_path && chm_created_by_us)
- DeleteFile(chm_path);
-}
-
-#endif /* NO_HTMLHELP */
diff --git a/WINDOWS/WINHELP.H b/WINDOWS/WINHELP.H
deleted file mode 100644
index 9011df45..00000000
--- a/WINDOWS/WINHELP.H
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * winhelp.h - define Windows Help context names.
- * Each definition is simply a string which matches up with the
- * section names in the Halibut source, and is used for HTML Help.
- */
-
-/* Maximum length for WINHELP_CTX_foo strings */
-#define WINHELP_CTX_MAXLEN 80
-
-/* These are used in the cross-platform configuration dialog code. */
-
-#define HELPCTX(x) P(WINHELP_CTX_ ## x)
-
-#define WINHELP_CTX_no_help NULL
-
-#define WINHELP_CTX_session_hostname "config-hostname"
-#define WINHELP_CTX_session_saved "config-saving"
-#define WINHELP_CTX_session_coe "config-closeonexit"
-#define WINHELP_CTX_logging_main "config-logging"
-#define WINHELP_CTX_logging_filename "config-logfilename"
-#define WINHELP_CTX_logging_exists "config-logfileexists"
-#define WINHELP_CTX_logging_flush "config-logflush"
-#define WINHELP_CTX_logging_header "config-logheader"
-#define WINHELP_CTX_logging_ssh_omit_password "config-logssh"
-#define WINHELP_CTX_logging_ssh_omit_data "config-logssh"
-#define WINHELP_CTX_keyboard_backspace "config-backspace"
-#define WINHELP_CTX_keyboard_homeend "config-homeend"
-#define WINHELP_CTX_keyboard_funkeys "config-funkeys"
-#define WINHELP_CTX_keyboard_appkeypad "config-appkeypad"
-#define WINHELP_CTX_keyboard_appcursor "config-appcursor"
-#define WINHELP_CTX_keyboard_nethack "config-nethack"
-#define WINHELP_CTX_keyboard_compose "config-compose"
-#define WINHELP_CTX_keyboard_ctrlalt "config-ctrlalt"
-#define WINHELP_CTX_features_application "config-features-application"
-#define WINHELP_CTX_features_mouse "config-features-mouse"
-#define WINHELP_CTX_features_resize "config-features-resize"
-#define WINHELP_CTX_features_altscreen "config-features-altscreen"
-#define WINHELP_CTX_features_retitle "config-features-retitle"
-#define WINHELP_CTX_features_qtitle "config-features-qtitle"
-#define WINHELP_CTX_features_dbackspace "config-features-dbackspace"
-#define WINHELP_CTX_features_charset "config-features-charset"
-#define WINHELP_CTX_features_clearscroll "config-features-clearscroll"
-#define WINHELP_CTX_features_arabicshaping "config-features-shaping"
-#define WINHELP_CTX_features_bidi "config-features-bidi"
-#define WINHELP_CTX_terminal_autowrap "config-autowrap"
-#define WINHELP_CTX_terminal_decom "config-decom"
-#define WINHELP_CTX_terminal_lfhascr "config-crlf"
-#define WINHELP_CTX_terminal_crhaslf "config-lfcr"
-#define WINHELP_CTX_terminal_bce "config-erase"
-#define WINHELP_CTX_terminal_blink "config-blink"
-#define WINHELP_CTX_terminal_answerback "config-answerback"
-#define WINHELP_CTX_terminal_localecho "config-localecho"
-#define WINHELP_CTX_terminal_localedit "config-localedit"
-#define WINHELP_CTX_terminal_printing "config-printing"
-#define WINHELP_CTX_supdup_location "supdup-location"
-#define WINHELP_CTX_supdup_ascii "supdup-ascii"
-#define WINHELP_CTX_supdup_more "supdup-more"
-#define WINHELP_CTX_supdup_scroll "supdup-scroll"
-#define WINHELP_CTX_bell_style "config-bellstyle"
-#define WINHELP_CTX_bell_taskbar "config-belltaskbar"
-#define WINHELP_CTX_bell_overload "config-bellovl"
-#define WINHELP_CTX_window_size "config-winsize"
-#define WINHELP_CTX_window_resize "config-winsizelock"
-#define WINHELP_CTX_window_scrollback "config-scrollback"
-#define WINHELP_CTX_window_erased "config-erasetoscrollback"
-#define WINHELP_CTX_behaviour_closewarn "config-warnonclose"
-#define WINHELP_CTX_behaviour_altf4 "config-altf4"
-#define WINHELP_CTX_behaviour_altspace "config-altspace"
-#define WINHELP_CTX_behaviour_altonly "config-altonly"
-#define WINHELP_CTX_behaviour_alwaysontop "config-alwaysontop"
-#define WINHELP_CTX_behaviour_altenter "config-fullscreen"
-#define WINHELP_CTX_appearance_cursor "config-cursor"
-#define WINHELP_CTX_appearance_font "config-font"
-#define WINHELP_CTX_appearance_title "config-title"
-#define WINHELP_CTX_appearance_hidemouse "config-mouseptr"
-#define WINHELP_CTX_appearance_border "config-winborder"
-#define WINHELP_CTX_connection_termtype "config-termtype"
-#define WINHELP_CTX_connection_termspeed "config-termspeed"
-#define WINHELP_CTX_connection_username "config-username"
-#define WINHELP_CTX_connection_username_from_env "config-username-from-env"
-#define WINHELP_CTX_connection_keepalive "config-keepalive"
-#define WINHELP_CTX_connection_nodelay "config-nodelay"
-#define WINHELP_CTX_connection_ipversion "config-address-family"
-#define WINHELP_CTX_connection_tcpkeepalive "config-tcp-keepalives"
-#define WINHELP_CTX_connection_loghost "config-loghost"
-#define WINHELP_CTX_proxy_type "config-proxy-type"
-#define WINHELP_CTX_proxy_main "config-proxy"
-#define WINHELP_CTX_proxy_exclude "config-proxy-exclude"
-#define WINHELP_CTX_proxy_dns "config-proxy-dns"
-#define WINHELP_CTX_proxy_auth "config-proxy-auth"
-#define WINHELP_CTX_proxy_command "config-proxy-command"
-#define WINHELP_CTX_proxy_logging "config-proxy-logging"
-#define WINHELP_CTX_telnet_environ "config-environ"
-#define WINHELP_CTX_telnet_oldenviron "config-oldenviron"
-#define WINHELP_CTX_telnet_passive "config-ptelnet"
-#define WINHELP_CTX_telnet_specialkeys "config-telnetkey"
-#define WINHELP_CTX_telnet_newline "config-telnetnl"
-#define WINHELP_CTX_rlogin_localuser "config-rlogin-localuser"
-#define WINHELP_CTX_ssh_nopty "config-ssh-pty"
-#define WINHELP_CTX_ssh_ttymodes "config-ttymodes"
-#define WINHELP_CTX_ssh_noshell "config-ssh-noshell"
-#define WINHELP_CTX_ssh_ciphers "config-ssh-encryption"
-#define WINHELP_CTX_ssh_protocol "config-ssh-prot"
-#define WINHELP_CTX_ssh_command "config-command"
-#define WINHELP_CTX_ssh_compress "config-ssh-comp"
-#define WINHELP_CTX_ssh_share "config-ssh-sharing"
-#define WINHELP_CTX_ssh_kexlist "config-ssh-kex-order"
-#define WINHELP_CTX_ssh_hklist "config-ssh-hostkey-order"
-#define WINHELP_CTX_ssh_hk_known "config-ssh-prefer-known-hostkeys"
-#define WINHELP_CTX_ssh_gssapi_kex_delegation "config-ssh-kex-gssapi-delegation"
-#define WINHELP_CTX_ssh_kex_repeat "config-ssh-kex-rekey"
-#define WINHELP_CTX_ssh_kex_manual_hostkeys "config-ssh-kex-manual-hostkeys"
-#define WINHELP_CTX_ssh_auth_bypass "config-ssh-noauth"
-#define WINHELP_CTX_ssh_no_trivial_userauth "config-ssh-notrivialauth"
-#define WINHELP_CTX_ssh_auth_banner "config-ssh-banner"
-#define WINHELP_CTX_ssh_auth_privkey "config-ssh-privkey"
-#define WINHELP_CTX_ssh_auth_agentfwd "config-ssh-agentfwd"
-#define WINHELP_CTX_ssh_auth_changeuser "config-ssh-changeuser"
-#define WINHELP_CTX_ssh_auth_pageant "config-ssh-tryagent"
-#define WINHELP_CTX_ssh_auth_tis "config-ssh-tis"
-#define WINHELP_CTX_ssh_auth_ki "config-ssh-ki"
-#define WINHELP_CTX_ssh_gssapi "config-ssh-auth-gssapi"
-#define WINHELP_CTX_ssh_gssapi_delegation "config-ssh-auth-gssapi-delegation"
-#define WINHELP_CTX_ssh_gssapi_libraries "config-ssh-auth-gssapi-libraries"
-#define WINHELP_CTX_selection_buttons "config-mouse"
-#define WINHELP_CTX_selection_shiftdrag "config-mouseshift"
-#define WINHELP_CTX_selection_rect "config-rectselect"
-#define WINHELP_CTX_selection_linedraw "config-linedrawpaste"
-#define WINHELP_CTX_selection_autocopy "config-selection-autocopy"
-#define WINHELP_CTX_selection_clipactions "config-selection-clipactions"
-#define WINHELP_CTX_selection_pastectrl "config-paste-ctrl-char"
-#define WINHELP_CTX_copy_charclasses "config-charclasses"
-#define WINHELP_CTX_copy_rtf "config-rtfcopy"
-#define WINHELP_CTX_colours_ansi "config-ansicolour"
-#define WINHELP_CTX_colours_xterm256 "config-xtermcolour"
-#define WINHELP_CTX_colours_truecolour "config-truecolour"
-#define WINHELP_CTX_colours_bold "config-boldcolour"
-#define WINHELP_CTX_colours_system "config-syscolour"
-#define WINHELP_CTX_colours_logpal "config-logpalette"
-#define WINHELP_CTX_colours_config "config-colourcfg"
-#define WINHELP_CTX_translation_codepage "config-charset"
-#define WINHELP_CTX_translation_cjk_ambig_wide "config-cjk-ambig-wide"
-#define WINHELP_CTX_translation_cyrillic "config-cyr"
-#define WINHELP_CTX_translation_linedraw "config-linedraw"
-#define WINHELP_CTX_translation_utf8linedraw "config-utf8linedraw"
-#define WINHELP_CTX_ssh_tunnels_x11 "config-ssh-x11"
-#define WINHELP_CTX_ssh_tunnels_x11auth "config-ssh-x11auth"
-#define WINHELP_CTX_ssh_tunnels_xauthority "config-ssh-xauthority"
-#define WINHELP_CTX_ssh_tunnels_portfwd "config-ssh-portfwd"
-#define WINHELP_CTX_ssh_tunnels_portfwd_localhost "config-ssh-portfwd-localhost"
-#define WINHELP_CTX_ssh_tunnels_portfwd_ipversion "config-ssh-portfwd-address-family"
-#define WINHELP_CTX_ssh_bugs_ignore1 "config-ssh-bug-ignore1"
-#define WINHELP_CTX_ssh_bugs_plainpw1 "config-ssh-bug-plainpw1"
-#define WINHELP_CTX_ssh_bugs_rsa1 "config-ssh-bug-rsa1"
-#define WINHELP_CTX_ssh_bugs_ignore2 "config-ssh-bug-ignore2"
-#define WINHELP_CTX_ssh_bugs_hmac2 "config-ssh-bug-hmac2"
-#define WINHELP_CTX_ssh_bugs_derivekey2 "config-ssh-bug-derivekey2"
-#define WINHELP_CTX_ssh_bugs_rsapad2 "config-ssh-bug-sig"
-#define WINHELP_CTX_ssh_bugs_pksessid2 "config-ssh-bug-pksessid2"
-#define WINHELP_CTX_ssh_bugs_rekey2 "config-ssh-bug-rekey"
-#define WINHELP_CTX_ssh_bugs_maxpkt2 "config-ssh-bug-maxpkt2"
-#define WINHELP_CTX_ssh_bugs_winadj "config-ssh-bug-winadj"
-#define WINHELP_CTX_ssh_bugs_chanreq "config-ssh-bug-chanreq"
-#define WINHELP_CTX_ssh_bugs_oldgex2 "config-ssh-bug-oldgex2"
-#define WINHELP_CTX_serial_line "config-serial-line"
-#define WINHELP_CTX_serial_speed "config-serial-speed"
-#define WINHELP_CTX_serial_databits "config-serial-databits"
-#define WINHELP_CTX_serial_stopbits "config-serial-stopbits"
-#define WINHELP_CTX_serial_parity "config-serial-parity"
-#define WINHELP_CTX_serial_flow "config-serial-flow"
-
-#define WINHELP_CTX_pageant_general "pageant"
-#define WINHELP_CTX_pageant_keylist "pageant-mainwin-keylist"
-#define WINHELP_CTX_pageant_addkey "pageant-mainwin-addkey"
-#define WINHELP_CTX_pageant_remkey "pageant-mainwin-remkey"
-#define WINHELP_CTX_pageant_deferred "pageant-deferred-decryption"
-#define WINHELP_CTX_pgpfingerprints "pgpkeys"
-#define WINHELP_CTX_puttygen_general "pubkey-puttygen"
-#define WINHELP_CTX_puttygen_keytype "puttygen-keytype"
-#define WINHELP_CTX_puttygen_bits "puttygen-strength"
-#define WINHELP_CTX_puttygen_generate "puttygen-generate"
-#define WINHELP_CTX_puttygen_fingerprint "puttygen-fingerprint"
-#define WINHELP_CTX_puttygen_comment "puttygen-comment"
-#define WINHELP_CTX_puttygen_passphrase "puttygen-passphrase"
-#define WINHELP_CTX_puttygen_savepriv "puttygen-savepriv"
-#define WINHELP_CTX_puttygen_savepub "puttygen-savepub"
-#define WINHELP_CTX_puttygen_pastekey "puttygen-pastekey"
-#define WINHELP_CTX_puttygen_load "puttygen-load"
-#define WINHELP_CTX_puttygen_conversions "puttygen-conversions"
-#define WINHELP_CTX_puttygen_ppkver "puttygen-save-ppk-version"
-#define WINHELP_CTX_puttygen_kdfparam "puttygen-save-passphrase-hashing"
-
-/* These are used in Windows-specific bits of the frontend.
- * We (ab)use "help context identifiers" (dwContextId) to identify them. */
-
-#define HELPCTXID(x) WINHELP_CTXID_ ## x
-
-#define WINHELP_CTXID_no_help 0
-#define WINHELP_CTX_errors_hostkey_absent "errors-hostkey-absent"
-#define WINHELP_CTXID_errors_hostkey_absent 1
-#define WINHELP_CTX_errors_hostkey_changed "errors-hostkey-wrong"
-#define WINHELP_CTXID_errors_hostkey_changed 2
-#define WINHELP_CTX_errors_cantloadkey "errors-cant-load-key"
-#define WINHELP_CTXID_errors_cantloadkey 3
-#define WINHELP_CTX_option_cleanup "using-cleanup"
-#define WINHELP_CTXID_option_cleanup 4
-#define WINHELP_CTX_pgp_fingerprints "pgpkeys"
-#define WINHELP_CTXID_pgp_fingerprints 5
diff --git a/WINDOWS/WINJUMP.C b/WINDOWS/WINJUMP.C
deleted file mode 100644
index 358504fd..00000000
--- a/WINDOWS/WINJUMP.C
+++ /dev/null
@@ -1,748 +0,0 @@
-/*
- * winjump.c: support for Windows 7 jump lists.
- *
- * The Windows 7 jumplist is a customizable list defined by the
- * application. It is persistent across application restarts: the OS
- * maintains the list when the app is not running. The list is shown
- * when the user right-clicks on the taskbar button of a running app
- * or a pinned non-running application. We use the jumplist to
- * maintain a list of recently started saved sessions, started either
- * by doubleclicking on a saved session, or with the command line
- * "-load" parameter.
- *
- * Since the jumplist is write-only: it can only be replaced and the
- * current list cannot be read, we must maintain the contents of the
- * list persistantly in the registry. The file winstore.h contains
- * functions to directly manipulate these registry entries. This file
- * contains higher level functions to manipulate the jumplist.
- */
-
-#include <assert.h>
-
-#include "putty.h"
-#include "storage.h"
-
-#define MAX_JUMPLIST_ITEMS 30 /* PuTTY will never show more items in
- * the jumplist than this, regardless of
- * user preferences. */
-
-/*
- * COM structures and functions.
- */
-#ifndef PROPERTYKEY_DEFINED
-#define PROPERTYKEY_DEFINED
-typedef struct _tagpropertykey {
- GUID fmtid;
- DWORD pid;
-} PROPERTYKEY;
-#endif
-#ifndef _REFPROPVARIANT_DEFINED
-#define _REFPROPVARIANT_DEFINED
-typedef PROPVARIANT *REFPROPVARIANT;
-#endif
-/* MinGW doesn't define this yet: */
-#ifndef _PROPVARIANTINIT_DEFINED_
-#define _PROPVARIANTINIT_DEFINED_
-#define PropVariantInit(pvar) memset((pvar),0,sizeof(PROPVARIANT))
-#endif
-
-#define IID_IShellLink IID_IShellLinkA
-
-typedef struct ICustomDestinationListVtbl {
- HRESULT ( __stdcall *QueryInterface ) (
- /* [in] ICustomDestinationList*/ void *This,
- /* [in] */ const GUID * const riid,
- /* [out] */ void **ppvObject);
-
- ULONG ( __stdcall *AddRef )(
- /* [in] ICustomDestinationList*/ void *This);
-
- ULONG ( __stdcall *Release )(
- /* [in] ICustomDestinationList*/ void *This);
-
- HRESULT ( __stdcall *SetAppID )(
- /* [in] ICustomDestinationList*/ void *This,
- /* [string][in] */ LPCWSTR pszAppID);
-
- HRESULT ( __stdcall *BeginList )(
- /* [in] ICustomDestinationList*/ void *This,
- /* [out] */ UINT *pcMinSlots,
- /* [in] */ const GUID * const riid,
- /* [out] */ void **ppv);
-
- HRESULT ( __stdcall *AppendCategory )(
- /* [in] ICustomDestinationList*/ void *This,
- /* [string][in] */ LPCWSTR pszCategory,
- /* [in] IObjectArray*/ void *poa);
-
- HRESULT ( __stdcall *AppendKnownCategory )(
- /* [in] ICustomDestinationList*/ void *This,
- /* [in] KNOWNDESTCATEGORY*/ int category);
-
- HRESULT ( __stdcall *AddUserTasks )(
- /* [in] ICustomDestinationList*/ void *This,
- /* [in] IObjectArray*/ void *poa);
-
- HRESULT ( __stdcall *CommitList )(
- /* [in] ICustomDestinationList*/ void *This);
-
- HRESULT ( __stdcall *GetRemovedDestinations )(
- /* [in] ICustomDestinationList*/ void *This,
- /* [in] */ const IID * const riid,
- /* [out] */ void **ppv);
-
- HRESULT ( __stdcall *DeleteList )(
- /* [in] ICustomDestinationList*/ void *This,
- /* [string][unique][in] */ LPCWSTR pszAppID);
-
- HRESULT ( __stdcall *AbortList )(
- /* [in] ICustomDestinationList*/ void *This);
-
-} ICustomDestinationListVtbl;
-
-typedef struct ICustomDestinationList
-{
- ICustomDestinationListVtbl *lpVtbl;
-} ICustomDestinationList;
-
-typedef struct IObjectArrayVtbl
-{
- HRESULT ( __stdcall *QueryInterface )(
- /* [in] IObjectArray*/ void *This,
- /* [in] */ const GUID * const riid,
- /* [out] */ void **ppvObject);
-
- ULONG ( __stdcall *AddRef )(
- /* [in] IObjectArray*/ void *This);
-
- ULONG ( __stdcall *Release )(
- /* [in] IObjectArray*/ void *This);
-
- HRESULT ( __stdcall *GetCount )(
- /* [in] IObjectArray*/ void *This,
- /* [out] */ UINT *pcObjects);
-
- HRESULT ( __stdcall *GetAt )(
- /* [in] IObjectArray*/ void *This,
- /* [in] */ UINT uiIndex,
- /* [in] */ const GUID * const riid,
- /* [out] */ void **ppv);
-
-} IObjectArrayVtbl;
-
-typedef struct IObjectArray
-{
- IObjectArrayVtbl *lpVtbl;
-} IObjectArray;
-
-typedef struct IShellLinkVtbl
-{
- HRESULT ( __stdcall *QueryInterface )(
- /* [in] IShellLink*/ void *This,
- /* [in] */ const GUID * const riid,
- /* [out] */ void **ppvObject);
-
- ULONG ( __stdcall *AddRef )(
- /* [in] IShellLink*/ void *This);
-
- ULONG ( __stdcall *Release )(
- /* [in] IShellLink*/ void *This);
-
- HRESULT ( __stdcall *GetPath )(
- /* [in] IShellLink*/ void *This,
- /* [string][out] */ LPSTR pszFile,
- /* [in] */ int cch,
- /* [unique][out][in] */ WIN32_FIND_DATAA *pfd,
- /* [in] */ DWORD fFlags);
-
- HRESULT ( __stdcall *GetIDList )(
- /* [in] IShellLink*/ void *This,
- /* [out] LPITEMIDLIST*/ void **ppidl);
-
- HRESULT ( __stdcall *SetIDList )(
- /* [in] IShellLink*/ void *This,
- /* [in] LPITEMIDLIST*/ void *pidl);
-
- HRESULT ( __stdcall *GetDescription )(
- /* [in] IShellLink*/ void *This,
- /* [string][out] */ LPSTR pszName,
- /* [in] */ int cch);
-
- HRESULT ( __stdcall *SetDescription )(
- /* [in] IShellLink*/ void *This,
- /* [string][in] */ LPCSTR pszName);
-
- HRESULT ( __stdcall *GetWorkingDirectory )(
- /* [in] IShellLink*/ void *This,
- /* [string][out] */ LPSTR pszDir,
- /* [in] */ int cch);
-
- HRESULT ( __stdcall *SetWorkingDirectory )(
- /* [in] IShellLink*/ void *This,
- /* [string][in] */ LPCSTR pszDir);
-
- HRESULT ( __stdcall *GetArguments )(
- /* [in] IShellLink*/ void *This,
- /* [string][out] */ LPSTR pszArgs,
- /* [in] */ int cch);
-
- HRESULT ( __stdcall *SetArguments )(
- /* [in] IShellLink*/ void *This,
- /* [string][in] */ LPCSTR pszArgs);
-
- HRESULT ( __stdcall *GetHotkey )(
- /* [in] IShellLink*/ void *This,
- /* [out] */ WORD *pwHotkey);
-
- HRESULT ( __stdcall *SetHotkey )(
- /* [in] IShellLink*/ void *This,
- /* [in] */ WORD wHotkey);
-
- HRESULT ( __stdcall *GetShowCmd )(
- /* [in] IShellLink*/ void *This,
- /* [out] */ int *piShowCmd);
-
- HRESULT ( __stdcall *SetShowCmd )(
- /* [in] IShellLink*/ void *This,
- /* [in] */ int iShowCmd);
-
- HRESULT ( __stdcall *GetIconLocation )(
- /* [in] IShellLink*/ void *This,
- /* [string][out] */ LPSTR pszIconPath,
- /* [in] */ int cch,
- /* [out] */ int *piIcon);
-
- HRESULT ( __stdcall *SetIconLocation )(
- /* [in] IShellLink*/ void *This,
- /* [string][in] */ LPCSTR pszIconPath,
- /* [in] */ int iIcon);
-
- HRESULT ( __stdcall *SetRelativePath )(
- /* [in] IShellLink*/ void *This,
- /* [string][in] */ LPCSTR pszPathRel,
- /* [in] */ DWORD dwReserved);
-
- HRESULT ( __stdcall *Resolve )(
- /* [in] IShellLink*/ void *This,
- /* [unique][in] */ HWND hwnd,
- /* [in] */ DWORD fFlags);
-
- HRESULT ( __stdcall *SetPath )(
- /* [in] IShellLink*/ void *This,
- /* [string][in] */ LPCSTR pszFile);
-
-} IShellLinkVtbl;
-
-typedef struct IShellLink
-{
- IShellLinkVtbl *lpVtbl;
-} IShellLink;
-
-typedef struct IObjectCollectionVtbl
-{
- HRESULT ( __stdcall *QueryInterface )(
- /* [in] IShellLink*/ void *This,
- /* [in] */ const GUID * const riid,
- /* [out] */ void **ppvObject);
-
- ULONG ( __stdcall *AddRef )(
- /* [in] IShellLink*/ void *This);
-
- ULONG ( __stdcall *Release )(
- /* [in] IShellLink*/ void *This);
-
- HRESULT ( __stdcall *GetCount )(
- /* [in] IShellLink*/ void *This,
- /* [out] */ UINT *pcObjects);
-
- HRESULT ( __stdcall *GetAt )(
- /* [in] IShellLink*/ void *This,
- /* [in] */ UINT uiIndex,
- /* [in] */ const GUID * const riid,
- /* [iid_is][out] */ void **ppv);
-
- HRESULT ( __stdcall *AddObject )(
- /* [in] IShellLink*/ void *This,
- /* [in] */ void *punk);
-
- HRESULT ( __stdcall *AddFromArray )(
- /* [in] IShellLink*/ void *This,
- /* [in] */ IObjectArray *poaSource);
-
- HRESULT ( __stdcall *RemoveObjectAt )(
- /* [in] IShellLink*/ void *This,
- /* [in] */ UINT uiIndex);
-
- HRESULT ( __stdcall *Clear )(
- /* [in] IShellLink*/ void *This);
-
-} IObjectCollectionVtbl;
-
-typedef struct IObjectCollection
-{
- IObjectCollectionVtbl *lpVtbl;
-} IObjectCollection;
-
-typedef struct IPropertyStoreVtbl
-{
- HRESULT ( __stdcall *QueryInterface )(
- /* [in] IPropertyStore*/ void *This,
- /* [in] */ const GUID * const riid,
- /* [iid_is][out] */ void **ppvObject);
-
- ULONG ( __stdcall *AddRef )(
- /* [in] IPropertyStore*/ void *This);
-
- ULONG ( __stdcall *Release )(
- /* [in] IPropertyStore*/ void *This);
-
- HRESULT ( __stdcall *GetCount )(
- /* [in] IPropertyStore*/ void *This,
- /* [out] */ DWORD *cProps);
-
- HRESULT ( __stdcall *GetAt )(
- /* [in] IPropertyStore*/ void *This,
- /* [in] */ DWORD iProp,
- /* [out] */ PROPERTYKEY *pkey);
-
- HRESULT ( __stdcall *GetValue )(
- /* [in] IPropertyStore*/ void *This,
- /* [in] */ const PROPERTYKEY * const key,
- /* [out] */ PROPVARIANT *pv);
-
- HRESULT ( __stdcall *SetValue )(
- /* [in] IPropertyStore*/ void *This,
- /* [in] */ const PROPERTYKEY * const key,
- /* [in] */ REFPROPVARIANT propvar);
-
- HRESULT ( __stdcall *Commit )(
- /* [in] IPropertyStore*/ void *This);
-} IPropertyStoreVtbl;
-
-typedef struct IPropertyStore
-{
- IPropertyStoreVtbl *lpVtbl;
-} IPropertyStore;
-
-static const CLSID CLSID_DestinationList = {
- 0x77f10cf0, 0x3db5, 0x4966, {0xb5,0x20,0xb7,0xc5,0x4f,0xd3,0x5e,0xd6}
-};
-static const CLSID CLSID_ShellLink = {
- 0x00021401, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}
-};
-static const CLSID CLSID_EnumerableObjectCollection = {
- 0x2d3468c1, 0x36a7, 0x43b6, {0xac,0x24,0xd3,0xf0,0x2f,0xd9,0x60,0x7a}
-};
-static const IID IID_IObjectCollection = {
- 0x5632b1a4, 0xe38a, 0x400a, {0x92,0x8a,0xd4,0xcd,0x63,0x23,0x02,0x95}
-};
-static const IID IID_IShellLink = {
- 0x000214ee, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}
-};
-static const IID IID_ICustomDestinationList = {
- 0x6332debf, 0x87b5, 0x4670, {0x90,0xc0,0x5e,0x57,0xb4,0x08,0xa4,0x9e}
-};
-static const IID IID_IObjectArray = {
- 0x92ca9dcd, 0x5622, 0x4bba, {0xa8,0x05,0x5e,0x9f,0x54,0x1b,0xd8,0xc9}
-};
-static const IID IID_IPropertyStore = {
- 0x886d8eeb, 0x8cf2, 0x4446, {0x8d,0x02,0xcd,0xba,0x1d,0xbd,0xcf,0x99}
-};
-static const PROPERTYKEY PKEY_Title = {
- {0xf29f85e0, 0x4ff9, 0x1068, {0xab,0x91,0x08,0x00,0x2b,0x27,0xb3,0xd9}},
- 0x00000002
-};
-
-/* Type-checking macro to provide arguments for CoCreateInstance()
- * etc, ensuring that 'obj' really is a 'type **'. */
-#define typecheck(checkexpr, result) \
- (sizeof(checkexpr) ? (result) : (result))
-#define COMPTR(type, obj) &IID_##type, \
- typecheck((obj)-(type **)(obj), (void **)(void *)(obj))
-
-static char putty_path[2048];
-
-/*
- * Function to make an IShellLink describing a particular PuTTY
- * command. If 'appname' is null, the command run will be the one
- * returned by GetModuleFileName, i.e. our own executable; if it's
- * non-null then it will be assumed to be a filename in the same
- * directory as our own executable, and the return value will be NULL
- * if that file doesn't exist.
- *
- * If 'sessionname' is null then no command line will be passed to the
- * program. If it's non-null, the command line will be that text
- * prefixed with an @ (to load a PuTTY saved session).
- *
- * Hence, you can launch a saved session using make_shell_link(NULL,
- * sessionname), and launch another app using e.g.
- * make_shell_link("puttygen.exe", NULL).
- */
-static IShellLink *make_shell_link(const char *appname,
- const char *sessionname)
-{
- IShellLink *ret;
- char *app_path, *param_string, *desc_string;
- IPropertyStore *pPS;
- PROPVARIANT pv;
-
- /* Retrieve path to executable. */
- if (!putty_path[0])
- GetModuleFileName(NULL, putty_path, sizeof(putty_path) - 1);
- if (appname) {
- char *p, *q = putty_path;
- FILE *fp;
-
- if ((p = strrchr(q, '\\')) != NULL) q = p+1;
- if ((p = strrchr(q, ':')) != NULL) q = p+1;
- app_path = dupprintf("%.*s%s", (int)(q - putty_path), putty_path,
- appname);
- if ((fp = fopen(app_path, "r")) == NULL) {
- sfree(app_path);
- return NULL;
- }
- fclose(fp);
- } else {
- app_path = dupstr(putty_path);
- }
-
- /* Check if this is a valid session, otherwise don't add. */
- if (sessionname) {
- settings_r *psettings_tmp = open_settings_r(sessionname);
- if (!psettings_tmp) {
- sfree(app_path);
- return NULL;
- }
- close_settings_r(psettings_tmp);
- }
-
- /* Create the new item. */
- if (!SUCCEEDED(CoCreateInstance(&CLSID_ShellLink, NULL,
- CLSCTX_INPROC_SERVER,
- COMPTR(IShellLink, &ret)))) {
- sfree(app_path);
- return NULL;
- }
-
- /* Set path, parameters, icon and description. */
- ret->lpVtbl->SetPath(ret, app_path);
-
- if (sessionname) {
- /* The leading space is reported to work around a Windows 10
- * behaviour change in which an argument string starting with
- * '@' causes the SetArguments method to silently do the wrong
- * thing. */
- param_string = dupcat(" @", sessionname);
- } else {
- param_string = dupstr("");
- }
- ret->lpVtbl->SetArguments(ret, param_string);
- sfree(param_string);
-
- if (sessionname) {
- desc_string = dupcat("Connect to PuTTY session '", sessionname, "'");
- } else {
- assert(appname);
- desc_string = dupprintf("Run %.*s",
- (int)strcspn(appname, "."), appname);
- }
- ret->lpVtbl->SetDescription(ret, desc_string);
- sfree(desc_string);
-
- ret->lpVtbl->SetIconLocation(ret, app_path, 0);
-
- /* To set the link title, we require the property store of the link. */
- if (SUCCEEDED(ret->lpVtbl->QueryInterface(ret,
- COMPTR(IPropertyStore, &pPS)))) {
- PropVariantInit(&pv);
- pv.vt = VT_LPSTR;
- if (sessionname) {
- pv.pszVal = dupstr(sessionname);
- } else {
- assert(appname);
- pv.pszVal = dupprintf("Run %.*s",
- (int)strcspn(appname, "."), appname);
- }
- pPS->lpVtbl->SetValue(pPS, &PKEY_Title, &pv);
- sfree(pv.pszVal);
- pPS->lpVtbl->Commit(pPS);
- pPS->lpVtbl->Release(pPS);
- }
-
- sfree(app_path);
-
- return ret;
-}
-
-/* Updates jumplist from registry. */
-static void update_jumplist_from_registry(void)
-{
- const char *piterator;
- UINT num_items;
- int jumplist_counter;
- UINT nremoved;
-
- /* Variables used by the cleanup code must be initialised to NULL,
- * so that we don't try to free or release them if they were never
- * set up. */
- ICustomDestinationList *pCDL = NULL;
- char *pjumplist_reg_entries = NULL;
- IObjectCollection *collection = NULL;
- IObjectArray *array = NULL;
- IShellLink *link = NULL;
- IObjectArray *pRemoved = NULL;
- bool need_abort = false;
-
- /*
- * Create an ICustomDestinationList: the top-level object which
- * deals with jump list management.
- */
- if (!SUCCEEDED(CoCreateInstance(&CLSID_DestinationList, NULL,
- CLSCTX_INPROC_SERVER,
- COMPTR(ICustomDestinationList, &pCDL))))
- goto cleanup;
-
- /*
- * Call its BeginList method to start compiling a list. This gives
- * us back 'num_items' (a hint derived from systemwide
- * configuration about how many things to put on the list) and
- * 'pRemoved' (user configuration about things to leave off the
- * list).
- */
- if (!SUCCEEDED(pCDL->lpVtbl->BeginList(pCDL, &num_items,
- COMPTR(IObjectArray, &pRemoved))))
- goto cleanup;
- need_abort = true;
- if (!SUCCEEDED(pRemoved->lpVtbl->GetCount(pRemoved, &nremoved)))
- nremoved = 0;
-
- /*
- * Create an object collection to form the 'Recent Sessions'
- * category on the jump list.
- */
- if (!SUCCEEDED(CoCreateInstance(&CLSID_EnumerableObjectCollection,
- NULL, CLSCTX_INPROC_SERVER,
- COMPTR(IObjectCollection, &collection))))
- goto cleanup;
-
- /*
- * Go through the jump list entries from the registry and add each
- * one to the collection.
- */
- pjumplist_reg_entries = get_jumplist_registry_entries();
- piterator = pjumplist_reg_entries;
- jumplist_counter = 0;
- while (*piterator != '\0' &&
- (jumplist_counter < min(MAX_JUMPLIST_ITEMS, (int) num_items))) {
- link = make_shell_link(NULL, piterator);
- if (link) {
- UINT i;
- bool found;
-
- /*
- * Check that the link isn't in the user-removed list.
- */
- for (i = 0, found = false; i < nremoved && !found; i++) {
- IShellLink *rlink;
- if (SUCCEEDED(pRemoved->lpVtbl->GetAt
- (pRemoved, i, COMPTR(IShellLink, &rlink)))) {
- char desc1[2048], desc2[2048];
- if (SUCCEEDED(link->lpVtbl->GetDescription
- (link, desc1, sizeof(desc1)-1)) &&
- SUCCEEDED(rlink->lpVtbl->GetDescription
- (rlink, desc2, sizeof(desc2)-1)) &&
- !strcmp(desc1, desc2)) {
- found = true;
- }
- rlink->lpVtbl->Release(rlink);
- }
- }
-
- if (!found) {
- collection->lpVtbl->AddObject(collection, link);
- jumplist_counter++;
- }
-
- link->lpVtbl->Release(link);
- link = NULL;
- }
- piterator += strlen(piterator) + 1;
- }
- sfree(pjumplist_reg_entries);
- pjumplist_reg_entries = NULL;
-
- /*
- * Get the array form of the collection we've just constructed,
- * and put it in the jump list.
- */
- if (!SUCCEEDED(collection->lpVtbl->QueryInterface
- (collection, COMPTR(IObjectArray, &array))))
- goto cleanup;
-
- pCDL->lpVtbl->AppendCategory(pCDL, L"Recent Sessions", array);
-
- /*
- * Create an object collection to form the 'Tasks' category on the
- * jump list.
- */
- if (!SUCCEEDED(CoCreateInstance(&CLSID_EnumerableObjectCollection,
- NULL, CLSCTX_INPROC_SERVER,
- COMPTR(IObjectCollection, &collection))))
- goto cleanup;
-
- /*
- * Add task entries for PuTTYgen and Pageant.
- */
- piterator = "Pageant.exe\0PuTTYgen.exe\0\0";
- while (*piterator != '\0') {
- link = make_shell_link(piterator, NULL);
- if (link) {
- collection->lpVtbl->AddObject(collection, link);
- link->lpVtbl->Release(link);
- link = NULL;
- }
- piterator += strlen(piterator) + 1;
- }
-
- /*
- * Get the array form of the collection we've just constructed,
- * and put it in the jump list.
- */
- if (!SUCCEEDED(collection->lpVtbl->QueryInterface
- (collection, COMPTR(IObjectArray, &array))))
- goto cleanup;
-
- pCDL->lpVtbl->AddUserTasks(pCDL, array);
-
- /*
- * Now we can clean up the array and collection variables, so as
- * to be able to reuse them.
- */
- array->lpVtbl->Release(array);
- array = NULL;
- collection->lpVtbl->Release(collection);
- collection = NULL;
-
- /*
- * Create another object collection to form the user tasks
- * category.
- */
- if (!SUCCEEDED(CoCreateInstance(&CLSID_EnumerableObjectCollection,
- NULL, CLSCTX_INPROC_SERVER,
- COMPTR(IObjectCollection, &collection))))
- goto cleanup;
-
- /*
- * Get the array form of the collection we've just constructed,
- * and put it in the jump list.
- */
- if (!SUCCEEDED(collection->lpVtbl->QueryInterface
- (collection, COMPTR(IObjectArray, &array))))
- goto cleanup;
-
- pCDL->lpVtbl->AddUserTasks(pCDL, array);
-
- /*
- * Now we can clean up the array and collection variables, so as
- * to be able to reuse them.
- */
- array->lpVtbl->Release(array);
- array = NULL;
- collection->lpVtbl->Release(collection);
- collection = NULL;
-
- /*
- * Commit the jump list.
- */
- pCDL->lpVtbl->CommitList(pCDL);
- need_abort = false;
-
- /*
- * Clean up.
- */
- cleanup:
- if (pRemoved) pRemoved->lpVtbl->Release(pRemoved);
- if (pCDL && need_abort) pCDL->lpVtbl->AbortList(pCDL);
- if (pCDL) pCDL->lpVtbl->Release(pCDL);
- if (collection) collection->lpVtbl->Release(collection);
- if (array) array->lpVtbl->Release(array);
- if (link) link->lpVtbl->Release(link);
- sfree(pjumplist_reg_entries);
-}
-
-/* Clears the entire jumplist. */
-void clear_jumplist(void)
-{
- ICustomDestinationList *pCDL;
-
- if (CoCreateInstance(&CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER,
- COMPTR(ICustomDestinationList, &pCDL)) == S_OK) {
- pCDL->lpVtbl->DeleteList(pCDL, NULL);
- pCDL->lpVtbl->Release(pCDL);
- }
-
-}
-
-/* Adds a saved session to the Windows 7 jumplist. */
-void add_session_to_jumplist(const char * const sessionname)
-{
- if ((osMajorVersion < 6) || (osMajorVersion == 6 && osMinorVersion < 1))
- return; /* do nothing on pre-Win7 systems */
-
- if (add_to_jumplist_registry(sessionname) == JUMPLISTREG_OK) {
- update_jumplist_from_registry();
- } else {
- /* Make sure we don't leave the jumplist dangling. */
- clear_jumplist();
- }
-}
-
-/* Removes a saved session from the Windows jumplist. */
-void remove_session_from_jumplist(const char * const sessionname)
-{
- if ((osMajorVersion < 6) || (osMajorVersion == 6 && osMinorVersion < 1))
- return; /* do nothing on pre-Win7 systems */
-
- if (remove_from_jumplist_registry(sessionname) == JUMPLISTREG_OK) {
- update_jumplist_from_registry();
- } else {
- /* Make sure we don't leave the jumplist dangling. */
- clear_jumplist();
- }
-}
-
-/* Set Explicit App User Model Id to fix removable media error with
- jump lists */
-
-bool set_explicit_app_user_model_id(void)
-{
- DECL_WINDOWS_FUNCTION(static, HRESULT, SetCurrentProcessExplicitAppUserModelID,
- (PCWSTR));
-
- static HMODULE shell32_module = 0;
-
- if (!shell32_module)
- {
- shell32_module = load_system32_dll("Shell32.dll");
- /*
- * We can't typecheck this function here, because it's defined
- * in <shobjidl.h>, which we're not including due to clashes
- * with all the manual-COM machinery above.
- */
- GET_WINDOWS_FUNCTION_NO_TYPECHECK(
- shell32_module, SetCurrentProcessExplicitAppUserModelID);
- }
-
- if (p_SetCurrentProcessExplicitAppUserModelID)
- {
- if (p_SetCurrentProcessExplicitAppUserModelID(L"SimonTatham.PuTTY") == S_OK)
- {
- return true;
- }
- return false;
- }
- /* Function doesn't exist, which is ok for Pre-7 systems */
-
- return true;
-
-}
diff --git a/WINDOWS/WINMISC.C b/WINDOWS/WINMISC.C
deleted file mode 100644
index 759df011..00000000
--- a/WINDOWS/WINMISC.C
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * winmisc.c: miscellaneous Windows-specific things
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-#include "putty.h"
-#ifndef SECURITY_WIN32
-#define SECURITY_WIN32
-#endif
-#include <security.h>
-
-DWORD osMajorVersion, osMinorVersion, osPlatformId;
-
-char *platform_get_x_display(void) {
- /* We may as well check for DISPLAY in case it's useful. */
- return dupstr(getenv("DISPLAY"));
-}
-
-Filename *filename_from_str(const char *str)
-{
- Filename *ret = snew(Filename);
- ret->path = dupstr(str);
- return ret;
-}
-
-Filename *filename_copy(const Filename *fn)
-{
- return filename_from_str(fn->path);
-}
-
-const char *filename_to_str(const Filename *fn)
-{
- return fn->path;
-}
-
-bool filename_equal(const Filename *f1, const Filename *f2)
-{
- return !strcmp(f1->path, f2->path);
-}
-
-bool filename_is_null(const Filename *fn)
-{
- return !*fn->path;
-}
-
-void filename_free(Filename *fn)
-{
- sfree(fn->path);
- sfree(fn);
-}
-
-void filename_serialise(BinarySink *bs, const Filename *f)
-{
- put_asciz(bs, f->path);
-}
-Filename *filename_deserialise(BinarySource *src)
-{
- return filename_from_str(get_asciz(src));
-}
-
-char filename_char_sanitise(char c)
-{
- if (strchr("<>:\"/\\|?*", c))
- return '.';
- return c;
-}
-
-char *get_username(void)
-{
- DWORD namelen;
- char *user;
- bool got_username = false;
- DECL_WINDOWS_FUNCTION(static, BOOLEAN, GetUserNameExA,
- (EXTENDED_NAME_FORMAT, LPSTR, PULONG));
-
- {
- static bool tried_usernameex = false;
- if (!tried_usernameex) {
- /* Not available on Win9x, so load dynamically */
- HMODULE secur32 = load_system32_dll("secur32.dll");
- /* If MIT Kerberos is installed, the following call to
- GET_WINDOWS_FUNCTION makes Windows implicitly load
- sspicli.dll WITHOUT proper path sanitizing, so better
- load it properly before */
- HMODULE sspicli = load_system32_dll("sspicli.dll");
- (void)sspicli; /* squash compiler warning about unused variable */
- GET_WINDOWS_FUNCTION(secur32, GetUserNameExA);
- tried_usernameex = true;
- }
- }
-
- if (p_GetUserNameExA) {
- /*
- * If available, use the principal -- this avoids the problem
- * that the local username is case-insensitive but Kerberos
- * usernames are case-sensitive.
- */
-
- /* Get the length */
- namelen = 0;
- (void) p_GetUserNameExA(NameUserPrincipal, NULL, &namelen);
-
- user = snewn(namelen, char);
- got_username = p_GetUserNameExA(NameUserPrincipal, user, &namelen);
- if (got_username) {
- char *p = strchr(user, '@');
- if (p) *p = 0;
- } else {
- sfree(user);
- }
- }
-
- if (!got_username) {
- /* Fall back to local user name */
- namelen = 0;
- if (!GetUserName(NULL, &namelen)) {
- /*
- * Apparently this doesn't work at least on Windows XP SP2.
- * Thus assume a maximum of 256. It will fail again if it
- * doesn't fit.
- */
- namelen = 256;
- }
-
- user = snewn(namelen, char);
- got_username = GetUserName(user, &namelen);
- if (!got_username) {
- sfree(user);
- }
- }
-
- return got_username ? user : NULL;
-}
-
-void dll_hijacking_protection(void)
-{
- /*
- * If the OS provides it, call SetDefaultDllDirectories() to
- * prevent DLLs from being loaded from the directory containing
- * our own binary, and instead only load from system32.
- *
- * This is a protection against hijacking attacks, if someone runs
- * PuTTY directly from their web browser's download directory
- * having previously been enticed into clicking on an unwise link
- * that downloaded a malicious DLL to the same directory under one
- * of various magic names that seem to be things that standard
- * Windows DLLs delegate to.
- *
- * It shouldn't break deliberate loading of user-provided DLLs
- * such as GSSAPI providers, because those are specified by their
- * full pathname by the user-provided configuration.
- */
- static HMODULE kernel32_module;
- DECL_WINDOWS_FUNCTION(static, BOOL, SetDefaultDllDirectories, (DWORD));
-
- if (!kernel32_module) {
- kernel32_module = load_system32_dll("kernel32.dll");
-#if (defined _MSC_VER && _MSC_VER < 1900)
- /* For older Visual Studio, this function isn't available in
- * the header files to type-check */
- GET_WINDOWS_FUNCTION_NO_TYPECHECK(
- kernel32_module, SetDefaultDllDirectories);
-#else
- GET_WINDOWS_FUNCTION(kernel32_module, SetDefaultDllDirectories);
-#endif
- }
-
- if (p_SetDefaultDllDirectories) {
- /* LOAD_LIBRARY_SEARCH_SYSTEM32 and explicitly specified
- * directories only */
- p_SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32 |
- LOAD_LIBRARY_SEARCH_USER_DIRS);
- }
-}
-
-void init_winver(void)
-{
- OSVERSIONINFO osVersion;
- static HMODULE kernel32_module;
- DECL_WINDOWS_FUNCTION(static, BOOL, GetVersionExA, (LPOSVERSIONINFO));
-
- if (!kernel32_module) {
- kernel32_module = load_system32_dll("kernel32.dll");
- /* Deliberately don't type-check this function, because that
- * would involve using its declaration in a header file which
- * triggers a deprecation warning. I know it's deprecated (see
- * below) and don't need telling. */
- GET_WINDOWS_FUNCTION_NO_TYPECHECK(kernel32_module, GetVersionExA);
- }
-
- ZeroMemory(&osVersion, sizeof(osVersion));
- osVersion.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
- if (p_GetVersionExA && p_GetVersionExA(&osVersion)) {
- osMajorVersion = osVersion.dwMajorVersion;
- osMinorVersion = osVersion.dwMinorVersion;
- osPlatformId = osVersion.dwPlatformId;
- } else {
- /*
- * GetVersionEx is deprecated, so allow for it perhaps going
- * away in future API versions. If it's not there, simply
- * assume that's because Windows is too _new_, so fill in the
- * variables we care about to a value that will always compare
- * higher than any given test threshold.
- *
- * Normally we should be checking against the presence of a
- * specific function if possible in any case.
- */
- osMajorVersion = osMinorVersion = UINT_MAX; /* a very high number */
- osPlatformId = VER_PLATFORM_WIN32_NT; /* not Win32s or Win95-like */
- }
-}
-
-HMODULE load_system32_dll(const char *libname)
-{
- /*
- * Wrapper function to load a DLL out of c:\windows\system32
- * without going through the full DLL search path. (Hence no
- * attack is possible by placing a substitute DLL earlier on that
- * path.)
- */
- static char *sysdir = NULL;
- static size_t sysdirsize = 0;
- char *fullpath;
- HMODULE ret;
-
- if (!sysdir) {
- size_t len;
- while ((len = GetSystemDirectory(sysdir, sysdirsize)) >= sysdirsize)
- sgrowarray(sysdir, sysdirsize, len);
- }
-
- fullpath = dupcat(sysdir, "\\", libname);
- ret = LoadLibrary(fullpath);
- sfree(fullpath);
- return ret;
-}
-
-/*
- * A tree234 containing mappings from system error codes to strings.
- */
-
-struct errstring {
- int error;
- char *text;
-};
-
-static int errstring_find(void *av, void *bv)
-{
- int *a = (int *)av;
- struct errstring *b = (struct errstring *)bv;
- if (*a < b->error)
- return -1;
- if (*a > b->error)
- return +1;
- return 0;
-}
-static int errstring_compare(void *av, void *bv)
-{
- struct errstring *a = (struct errstring *)av;
- return errstring_find(&a->error, bv);
-}
-
-static tree234 *errstrings = NULL;
-
-const char *win_strerror(int error)
-{
- struct errstring *es;
-
- if (!errstrings)
- errstrings = newtree234(errstring_compare);
-
- es = find234(errstrings, &error, errstring_find);
-
- if (!es) {
- char msgtext[65536]; /* maximum size for FormatMessage is 64K */
-
- es = snew(struct errstring);
- es->error = error;
- if (!FormatMessage((FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS), NULL, error,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- msgtext, lenof(msgtext)-1, NULL)) {
- sprintf(msgtext,
- "(unable to format: FormatMessage returned %u)",
- (unsigned int)GetLastError());
- } else {
- int len = strlen(msgtext);
- if (len > 0 && msgtext[len-1] == '\n')
- msgtext[len-1] = '\0';
- }
- es->text = dupprintf("Error %d: %s", error, msgtext);
- add234(errstrings, es);
- }
-
- return es->text;
-}
-
-FontSpec *fontspec_new(const char *name, bool bold, int height, int charset)
-{
- FontSpec *f = snew(FontSpec);
- f->name = dupstr(name);
- f->isbold = bold;
- f->height = height;
- f->charset = charset;
- return f;
-}
-FontSpec *fontspec_copy(const FontSpec *f)
-{
- return fontspec_new(f->name, f->isbold, f->height, f->charset);
-}
-void fontspec_free(FontSpec *f)
-{
- sfree(f->name);
- sfree(f);
-}
-void fontspec_serialise(BinarySink *bs, FontSpec *f)
-{
- put_asciz(bs, f->name);
- put_uint32(bs, f->isbold);
- put_uint32(bs, f->height);
- put_uint32(bs, f->charset);
-}
-FontSpec *fontspec_deserialise(BinarySource *src)
-{
- const char *name = get_asciz(src);
- unsigned isbold = get_uint32(src);
- unsigned height = get_uint32(src);
- unsigned charset = get_uint32(src);
- return fontspec_new(name, isbold, height, charset);
-}
-
-bool open_for_write_would_lose_data(const Filename *fn)
-{
- WIN32_FILE_ATTRIBUTE_DATA attrs;
- if (!GetFileAttributesEx(fn->path, GetFileExInfoStandard, &attrs)) {
- /*
- * Generally, if we don't identify a specific reason why we
- * should return true from this function, we return false, and
- * let the subsequent attempt to open the file for real give a
- * more useful error message.
- */
- return false;
- }
- if (attrs.dwFileAttributes & (FILE_ATTRIBUTE_DEVICE |
- FILE_ATTRIBUTE_DIRECTORY)) {
- /*
- * File is something other than an ordinary disk file, so
- * opening it for writing will not cause truncation. (It may
- * not _succeed_ either, but that's not our problem here!)
- */
- return false;
- }
- if (attrs.nFileSizeHigh == 0 && attrs.nFileSizeLow == 0) {
- /*
- * File is zero-length (or may be a named pipe, which
- * dwFileAttributes can't tell apart from a regular file), so
- * opening it for writing won't truncate any data away because
- * there's nothing to truncate anyway.
- */
- return false;
- }
- return true;
-}
-
-void escape_registry_key(const char *in, strbuf *out)
-{
- bool candot = false;
- static const char hex[16] = "0123456789ABCDEF";
-
- while (*in) {
- if (*in == ' ' || *in == '\\' || *in == '*' || *in == '?' ||
- *in == '%' || *in < ' ' || *in > '~' || (*in == '.'
- && !candot)) {
- put_byte(out, '%');
- put_byte(out, hex[((unsigned char) *in) >> 4]);
- put_byte(out, hex[((unsigned char) *in) & 15]);
- } else
- put_byte(out, *in);
- in++;
- candot = true;
- }
-}
-
-void unescape_registry_key(const char *in, strbuf *out)
-{
- 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);
-
- put_byte(out, (i << 4) + j);
- in += 3;
- } else {
- put_byte(out, *in++);
- }
- }
-}
-
-#ifdef DEBUG
-static FILE *debug_fp = NULL;
-static HANDLE debug_hdl = INVALID_HANDLE_VALUE;
-static int debug_got_console = 0;
-
-void dputs(const char *buf)
-{
- DWORD dw;
-
- if (!debug_got_console) {
- if (AllocConsole()) {
- debug_got_console = 1;
- debug_hdl = GetStdHandle(STD_OUTPUT_HANDLE);
- }
- }
- if (!debug_fp) {
- debug_fp = fopen("debug.log", "w");
- }
-
- if (debug_hdl != INVALID_HANDLE_VALUE) {
- WriteFile(debug_hdl, buf, strlen(buf), &dw, NULL);
- }
- fputs(buf, debug_fp);
- fflush(debug_fp);
-}
-#endif
-
-char *registry_get_string(HKEY root, const char *path, const char *leaf)
-{
- HKEY key = root;
- bool need_close_key = false;
- char *toret = NULL, *str = NULL;
-
- if (path) {
- if (RegCreateKey(key, path, &key) != ERROR_SUCCESS)
- goto out;
- need_close_key = true;
- }
-
- DWORD type, size;
- if (RegQueryValueEx(key, leaf, 0, &type, NULL, &size) != ERROR_SUCCESS)
- goto out;
- if (type != REG_SZ)
- goto out;
-
- str = snewn(size + 1, char);
- DWORD size_got = size;
- if (RegQueryValueEx(key, leaf, 0, &type, (LPBYTE)str,
- &size_got) != ERROR_SUCCESS)
- goto out;
- if (type != REG_SZ || size_got > size)
- goto out;
- str[size_got] = '\0';
-
- toret = str;
- str = NULL;
-
- out:
- if (need_close_key)
- RegCloseKey(key);
- sfree(str);
- return toret;
-}
diff --git a/WINDOWS/WINNET.C b/WINDOWS/WINNET.C
deleted file mode 100644
index 3b4da3cc..00000000
--- a/WINDOWS/WINNET.C
+++ /dev/null
@@ -1,1825 +0,0 @@
-/*
- * Windows networking abstraction.
- *
- * For the IPv6 code in here I am indebted to Jeroen Massar and
- * unfix.org.
- */
-
-#include <winsock2.h> /* need to put this first, for winelib builds */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#define NEED_DECLARATION_OF_SELECT /* in order to initialise it */
-
-#include "putty.h"
-#include "network.h"
-#include "tree234.h"
-#include "ssh.h"
-
-#include <ws2tcpip.h>
-
-#ifndef NO_IPV6
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmissing-braces"
-#endif
-const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
-const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-#endif
-
-#define ipv4_is_loopback(addr) \
- ((p_ntohl(addr.s_addr) & 0xFF000000L) == 0x7F000000L)
-
-/*
- * Mutable state that goes with a SockAddr: stores information
- * about where in the list of candidate IP(v*) addresses we've
- * currently got to.
- */
-typedef struct SockAddrStep_tag SockAddrStep;
-struct SockAddrStep_tag {
-#ifndef NO_IPV6
- struct addrinfo *ai; /* steps along addr->ais */
-#endif
- int curraddr;
-};
-
-typedef struct NetSocket NetSocket;
-struct NetSocket {
- const char *error;
- SOCKET s;
- Plug *plug;
- bufchain output_data;
- bool connected;
- bool writable;
- bool frozen; /* this causes readability notifications to be ignored */
- bool frozen_readable; /* this means we missed at least one readability
- * notification while we were frozen */
- bool localhost_only; /* for listening sockets */
- char oobdata[1];
- size_t sending_oob;
- bool oobinline, nodelay, keepalive, privport;
- enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof;
- SockAddr *addr;
- SockAddrStep step;
- int port;
- int pending_error; /* in case send() returns error */
- /*
- * We sometimes need pairs of Socket structures to be linked:
- * if we are listening on the same IPv6 and v4 port, for
- * example. So here we define `parent' and `child' pointers to
- * track this link.
- */
- NetSocket *parent, *child;
-
- Socket sock;
-};
-
-struct SockAddr {
- int refcount;
- char *error;
- bool resolved;
- bool namedpipe; /* indicates that this SockAddr is phony, holding a Windows
- * named pipe pathname instead of a network address */
-#ifndef NO_IPV6
- struct addrinfo *ais; /* Addresses IPv6 style. */
-#endif
- unsigned long *addresses; /* Addresses IPv4 style. */
- int naddresses;
- char hostname[512]; /* Store an unresolved host name. */
-};
-
-/*
- * Which address family this address belongs to. AF_INET for IPv4;
- * AF_INET6 for IPv6; AF_UNSPEC indicates that name resolution has
- * not been done and a simple host name is held in this SockAddr
- * structure.
- */
-#ifndef NO_IPV6
-#define SOCKADDR_FAMILY(addr, step) \
- (!(addr)->resolved ? AF_UNSPEC : \
- (step).ai ? (step).ai->ai_family : AF_INET)
-#else
-#define SOCKADDR_FAMILY(addr, step) \
- (!(addr)->resolved ? AF_UNSPEC : AF_INET)
-#endif
-
-/*
- * Start a SockAddrStep structure to step through multiple
- * addresses.
- */
-#ifndef NO_IPV6
-#define START_STEP(addr, step) \
- ((step).ai = (addr)->ais, (step).curraddr = 0)
-#else
-#define START_STEP(addr, step) \
- ((step).curraddr = 0)
-#endif
-
-static tree234 *sktree;
-
-static int cmpfortree(void *av, void *bv)
-{
- NetSocket *a = (NetSocket *)av, *b = (NetSocket *)bv;
- uintptr_t as = (uintptr_t) a->s, bs = (uintptr_t) b->s;
- if (as < bs)
- return -1;
- if (as > bs)
- return +1;
- if (a < b)
- return -1;
- if (a > b)
- return +1;
- return 0;
-}
-
-static int cmpforsearch(void *av, void *bv)
-{
- NetSocket *b = (NetSocket *)bv;
- uintptr_t as = (uintptr_t) av, bs = (uintptr_t) b->s;
- if (as < bs)
- return -1;
- if (as > bs)
- return +1;
- return 0;
-}
-
-DECL_WINDOWS_FUNCTION(static, int, WSAStartup, (WORD, LPWSADATA));
-DECL_WINDOWS_FUNCTION(static, int, WSACleanup, (void));
-DECL_WINDOWS_FUNCTION(static, int, closesocket, (SOCKET));
-DECL_WINDOWS_FUNCTION(static, u_long, ntohl, (u_long));
-DECL_WINDOWS_FUNCTION(static, u_long, htonl, (u_long));
-DECL_WINDOWS_FUNCTION(static, u_short, htons, (u_short));
-DECL_WINDOWS_FUNCTION(static, u_short, ntohs, (u_short));
-DECL_WINDOWS_FUNCTION(static, int, gethostname, (char *, int));
-DECL_WINDOWS_FUNCTION(static, struct hostent FAR *, gethostbyname,
- (const char FAR *));
-DECL_WINDOWS_FUNCTION(static, struct servent FAR *, getservbyname,
- (const char FAR *, const char FAR *));
-DECL_WINDOWS_FUNCTION(static, unsigned long, inet_addr, (const char FAR *));
-DECL_WINDOWS_FUNCTION(static, char FAR *, inet_ntoa, (struct in_addr));
-DECL_WINDOWS_FUNCTION(static, const char FAR *, inet_ntop,
- (int, void FAR *, char *, size_t));
-DECL_WINDOWS_FUNCTION(static, int, connect,
- (SOCKET, const struct sockaddr FAR *, int));
-DECL_WINDOWS_FUNCTION(static, int, bind,
- (SOCKET, const struct sockaddr FAR *, int));
-DECL_WINDOWS_FUNCTION(static, int, setsockopt,
- (SOCKET, int, int, const char FAR *, int));
-DECL_WINDOWS_FUNCTION(static, SOCKET, socket, (int, int, int));
-DECL_WINDOWS_FUNCTION(static, int, listen, (SOCKET, int));
-DECL_WINDOWS_FUNCTION(static, int, send, (SOCKET, const char FAR *, int, int));
-DECL_WINDOWS_FUNCTION(static, int, shutdown, (SOCKET, int));
-DECL_WINDOWS_FUNCTION(static, int, ioctlsocket,
- (SOCKET, long, u_long FAR *));
-DECL_WINDOWS_FUNCTION(static, SOCKET, accept,
- (SOCKET, struct sockaddr FAR *, int FAR *));
-DECL_WINDOWS_FUNCTION(static, int, getpeername,
- (SOCKET, struct sockaddr FAR *, int FAR *));
-DECL_WINDOWS_FUNCTION(static, int, recv, (SOCKET, char FAR *, int, int));
-DECL_WINDOWS_FUNCTION(static, int, WSAIoctl,
- (SOCKET, DWORD, LPVOID, DWORD, LPVOID, DWORD,
- LPDWORD, LPWSAOVERLAPPED,
- LPWSAOVERLAPPED_COMPLETION_ROUTINE));
-#ifndef NO_IPV6
-DECL_WINDOWS_FUNCTION(static, int, getaddrinfo,
- (const char *nodename, const char *servname,
- const struct addrinfo *hints, struct addrinfo **res));
-DECL_WINDOWS_FUNCTION(static, void, freeaddrinfo, (struct addrinfo *res));
-DECL_WINDOWS_FUNCTION(static, int, getnameinfo,
- (const struct sockaddr FAR * sa, socklen_t salen,
- char FAR * host, DWORD hostlen, char FAR * serv,
- DWORD servlen, int flags));
-DECL_WINDOWS_FUNCTION(static, char *, gai_strerror, (int ecode));
-DECL_WINDOWS_FUNCTION(static, int, WSAAddressToStringA,
- (LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFO,
- LPSTR, LPDWORD));
-#endif
-
-static HMODULE winsock_module = NULL;
-static WSADATA wsadata;
-#ifndef NO_IPV6
-static HMODULE winsock2_module = NULL;
-static HMODULE wship6_module = NULL;
-#endif
-
-static bool sk_startup(int hi, int lo)
-{
- WORD winsock_ver;
-
- winsock_ver = MAKEWORD(hi, lo);
-
- if (p_WSAStartup(winsock_ver, &wsadata)) {
- return false;
- }
-
- if (LOBYTE(wsadata.wVersion) != LOBYTE(winsock_ver)) {
- return false;
- }
-
- return true;
-}
-
-DEF_WINDOWS_FUNCTION(WSAAsyncSelect);
-DEF_WINDOWS_FUNCTION(WSAEventSelect);
-DEF_WINDOWS_FUNCTION(WSAGetLastError);
-DEF_WINDOWS_FUNCTION(WSAEnumNetworkEvents);
-DEF_WINDOWS_FUNCTION(select);
-
-void sk_init(void)
-{
-#ifndef NO_IPV6
- winsock2_module =
-#endif
- winsock_module = load_system32_dll("ws2_32.dll");
- if (!winsock_module) {
- winsock_module = load_system32_dll("wsock32.dll");
- }
- if (!winsock_module)
- modalfatalbox("Unable to load any WinSock library");
-
-#ifndef NO_IPV6
- /* Check if we have getaddrinfo in Winsock */
- if (GetProcAddress(winsock_module, "getaddrinfo") != NULL) {
- GET_WINDOWS_FUNCTION(winsock_module, getaddrinfo);
- GET_WINDOWS_FUNCTION(winsock_module, freeaddrinfo);
- GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, getnameinfo);
- /* This function would fail its type-check if we did one,
- * because the VS header file provides an inline definition
- * which is __cdecl instead of WINAPI. */
- GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, gai_strerror);
- } else {
- /* Fall back to wship6.dll for Windows 2000 */
- wship6_module = load_system32_dll("wship6.dll");
- if (wship6_module) {
- GET_WINDOWS_FUNCTION(wship6_module, getaddrinfo);
- GET_WINDOWS_FUNCTION(wship6_module, freeaddrinfo);
- /* See comment above about type check */
- GET_WINDOWS_FUNCTION_NO_TYPECHECK(wship6_module, getnameinfo);
- GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, gai_strerror);
- } else {
- }
- }
- GET_WINDOWS_FUNCTION(winsock2_module, WSAAddressToStringA);
-#endif
-
- GET_WINDOWS_FUNCTION(winsock_module, WSAAsyncSelect);
- GET_WINDOWS_FUNCTION(winsock_module, WSAEventSelect);
- /* We don't type-check select because at least some MinGW versions
- * of the Windows API headers seem to disagree with the
- * documentation on whether the 'struct timeval *' pointer is
- * const or not. */
- GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, select);
- GET_WINDOWS_FUNCTION(winsock_module, WSAGetLastError);
- GET_WINDOWS_FUNCTION(winsock_module, WSAEnumNetworkEvents);
- GET_WINDOWS_FUNCTION(winsock_module, WSAStartup);
- GET_WINDOWS_FUNCTION(winsock_module, WSACleanup);
- GET_WINDOWS_FUNCTION(winsock_module, closesocket);
- GET_WINDOWS_FUNCTION(winsock_module, ntohl);
- GET_WINDOWS_FUNCTION(winsock_module, htonl);
- GET_WINDOWS_FUNCTION(winsock_module, htons);
- GET_WINDOWS_FUNCTION(winsock_module, ntohs);
- GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, gethostname);
- GET_WINDOWS_FUNCTION(winsock_module, gethostbyname);
- GET_WINDOWS_FUNCTION(winsock_module, getservbyname);
- GET_WINDOWS_FUNCTION(winsock_module, inet_addr);
- GET_WINDOWS_FUNCTION(winsock_module, inet_ntoa);
- /* Older Visual Studio, and MinGW as of Ubuntu 16.04, don't know
- * about this function at all, so can't type-check it. Also there
- * seems to be some disagreement in the VS headers about whether
- * the second argument is void * or const void *, so I omit the
- * type check. */
- GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, inet_ntop);
- GET_WINDOWS_FUNCTION(winsock_module, connect);
- GET_WINDOWS_FUNCTION(winsock_module, bind);
- GET_WINDOWS_FUNCTION(winsock_module, setsockopt);
- GET_WINDOWS_FUNCTION(winsock_module, socket);
- GET_WINDOWS_FUNCTION(winsock_module, listen);
- GET_WINDOWS_FUNCTION(winsock_module, send);
- GET_WINDOWS_FUNCTION(winsock_module, shutdown);
- GET_WINDOWS_FUNCTION(winsock_module, ioctlsocket);
- GET_WINDOWS_FUNCTION(winsock_module, accept);
- GET_WINDOWS_FUNCTION(winsock_module, getpeername);
- GET_WINDOWS_FUNCTION(winsock_module, recv);
- GET_WINDOWS_FUNCTION(winsock_module, WSAIoctl);
-
- /* Try to get the best WinSock version we can get */
- if (!sk_startup(2,2) &&
- !sk_startup(2,0) &&
- !sk_startup(1,1)) {
- modalfatalbox("Unable to initialise WinSock");
- }
-
- sktree = newtree234(cmpfortree);
-}
-
-void sk_cleanup(void)
-{
- NetSocket *s;
- int i;
-
- if (sktree) {
- for (i = 0; (s = index234(sktree, i)) != NULL; i++) {
- p_closesocket(s->s);
- }
- freetree234(sktree);
- sktree = NULL;
- }
-
- if (p_WSACleanup)
- p_WSACleanup();
- if (winsock_module)
- FreeLibrary(winsock_module);
-#ifndef NO_IPV6
- if (wship6_module)
- FreeLibrary(wship6_module);
-#endif
-}
-
-const char *winsock_error_string(int error)
-{
- /*
- * Error codes we know about and have historically had reasonably
- * sensible error messages for.
- */
- switch (error) {
- case WSAEACCES:
- return "Network error: Permission denied";
- case WSAEADDRINUSE:
- return "Network error: Address already in use";
- case WSAEADDRNOTAVAIL:
- return "Network error: Cannot assign requested address";
- case WSAEAFNOSUPPORT:
- return
- "Network error: Address family not supported by protocol family";
- case WSAEALREADY:
- return "Network error: Operation already in progress";
- case WSAECONNABORTED:
- return "Network error: Software caused connection abort";
- case WSAECONNREFUSED:
- return "Network error: Connection refused";
- case WSAECONNRESET:
- return "Network error: Connection reset by peer";
- case WSAEDESTADDRREQ:
- return "Network error: Destination address required";
- case WSAEFAULT:
- return "Network error: Bad address";
- case WSAEHOSTDOWN:
- return "Network error: Host is down";
- case WSAEHOSTUNREACH:
- return "Network error: No route to host";
- case WSAEINPROGRESS:
- return "Network error: Operation now in progress";
- case WSAEINTR:
- return "Network error: Interrupted function call";
- case WSAEINVAL:
- return "Network error: Invalid argument";
- case WSAEISCONN:
- return "Network error: Socket is already connected";
- case WSAEMFILE:
- return "Network error: Too many open files";
- case WSAEMSGSIZE:
- return "Network error: Message too long";
- case WSAENETDOWN:
- return "Network error: Network is down";
- case WSAENETRESET:
- return "Network error: Network dropped connection on reset";
- case WSAENETUNREACH:
- return "Network error: Network is unreachable";
- case WSAENOBUFS:
- return "Network error: No buffer space available";
- case WSAENOPROTOOPT:
- return "Network error: Bad protocol option";
- case WSAENOTCONN:
- return "Network error: Socket is not connected";
- case WSAENOTSOCK:
- return "Network error: Socket operation on non-socket";
- case WSAEOPNOTSUPP:
- return "Network error: Operation not supported";
- case WSAEPFNOSUPPORT:
- return "Network error: Protocol family not supported";
- case WSAEPROCLIM:
- return "Network error: Too many processes";
- case WSAEPROTONOSUPPORT:
- return "Network error: Protocol not supported";
- case WSAEPROTOTYPE:
- return "Network error: Protocol wrong type for socket";
- case WSAESHUTDOWN:
- return "Network error: Cannot send after socket shutdown";
- case WSAESOCKTNOSUPPORT:
- return "Network error: Socket type not supported";
- case WSAETIMEDOUT:
- return "Network error: Connection timed out";
- case WSAEWOULDBLOCK:
- return "Network error: Resource temporarily unavailable";
- case WSAEDISCON:
- return "Network error: Graceful shutdown in progress";
- }
-
- /*
- * Handle any other error code by delegating to win_strerror.
- */
- return win_strerror(error);
-}
-
-SockAddr *sk_namelookup(const char *host, char **canonicalname,
- int address_family)
-{
- SockAddr *ret = snew(SockAddr);
- unsigned long a;
- char realhost[8192];
- int hint_family;
-
- /* Default to IPv4. */
- hint_family = (address_family == ADDRTYPE_IPV4 ? AF_INET :
-#ifndef NO_IPV6
- address_family == ADDRTYPE_IPV6 ? AF_INET6 :
-#endif
- AF_UNSPEC);
-
- /* Clear the structure and default to IPv4. */
- memset(ret, 0, sizeof(SockAddr));
-#ifndef NO_IPV6
- ret->ais = NULL;
-#endif
- ret->namedpipe = false;
- ret->addresses = NULL;
- ret->resolved = false;
- ret->refcount = 1;
- *realhost = '\0';
-
- if ((a = p_inet_addr(host)) == (unsigned long) INADDR_NONE) {
- struct hostent *h = NULL;
- int err = 0;
-#ifndef NO_IPV6
- /*
- * Use getaddrinfo when it's available
- */
- if (p_getaddrinfo) {
- struct addrinfo hints;
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = hint_family;
- hints.ai_flags = AI_CANONNAME;
- {
- /* strip [] on IPv6 address literals */
- char *trimmed_host = host_strduptrim(host);
- err = p_getaddrinfo(trimmed_host, NULL, &hints, &ret->ais);
- sfree(trimmed_host);
- }
- if (err == 0)
- ret->resolved = true;
- } else
-#endif
- {
- /*
- * Otherwise use the IPv4-only gethostbyname...
- * (NOTE: we don't use gethostbyname as a fallback!)
- */
- if ( (h = p_gethostbyname(host)) )
- ret->resolved = true;
- else
- err = p_WSAGetLastError();
- }
-
- if (!ret->resolved) {
- ret->error = (err == WSAENETDOWN ? "Network is down" :
- err == WSAHOST_NOT_FOUND ? "Host does not exist" :
- err == WSATRY_AGAIN ? "Host not found" :
-#ifndef NO_IPV6
- p_getaddrinfo&&p_gai_strerror ? p_gai_strerror(err) :
-#endif
- "gethostbyname: unknown error");
- } else {
- ret->error = NULL;
-
-#ifndef NO_IPV6
- /* If we got an address info use that... */
- if (ret->ais) {
- /* Are we in IPv4 fallback mode? */
- /* We put the IPv4 address into the a variable so we can further-on use the IPv4 code... */
- if (ret->ais->ai_family == AF_INET)
- memcpy(&a,
- (char *) &((SOCKADDR_IN *) ret->ais->
- ai_addr)->sin_addr, sizeof(a));
-
- if (ret->ais->ai_canonname)
- strncpy(realhost, ret->ais->ai_canonname, lenof(realhost));
- else
- strncpy(realhost, host, lenof(realhost));
- }
- /* We used the IPv4-only gethostbyname()... */
- else
-#endif
- {
- int n;
- for (n = 0; h->h_addr_list[n]; n++);
- ret->addresses = snewn(n, unsigned long);
- ret->naddresses = n;
- for (n = 0; n < ret->naddresses; n++) {
- memcpy(&a, h->h_addr_list[n], sizeof(a));
- ret->addresses[n] = p_ntohl(a);
- }
- memcpy(&a, h->h_addr, sizeof(a));
- /* This way we are always sure the h->h_name is valid :) */
- strncpy(realhost, h->h_name, sizeof(realhost));
- }
- }
- } else {
- /*
- * This must be a numeric IPv4 address because it caused a
- * success return from inet_addr.
- */
- ret->addresses = snewn(1, unsigned long);
- ret->naddresses = 1;
- ret->addresses[0] = p_ntohl(a);
- ret->resolved = true;
- strncpy(realhost, host, sizeof(realhost));
- }
- realhost[lenof(realhost)-1] = '\0';
- *canonicalname = dupstr(realhost);
- return ret;
-}
-
-SockAddr *sk_nonamelookup(const char *host)
-{
- SockAddr *ret = snew(SockAddr);
- ret->error = NULL;
- ret->resolved = false;
-#ifndef NO_IPV6
- ret->ais = NULL;
-#endif
- ret->namedpipe = false;
- ret->addresses = NULL;
- ret->naddresses = 0;
- ret->refcount = 1;
- strncpy(ret->hostname, host, lenof(ret->hostname));
- ret->hostname[lenof(ret->hostname)-1] = '\0';
- return ret;
-}
-
-SockAddr *sk_namedpipe_addr(const char *pipename)
-{
- SockAddr *ret = snew(SockAddr);
- ret->error = NULL;
- ret->resolved = false;
-#ifndef NO_IPV6
- ret->ais = NULL;
-#endif
- ret->namedpipe = true;
- ret->addresses = NULL;
- ret->naddresses = 0;
- ret->refcount = 1;
- strncpy(ret->hostname, pipename, lenof(ret->hostname));
- ret->hostname[lenof(ret->hostname)-1] = '\0';
- return ret;
-}
-
-static bool sk_nextaddr(SockAddr *addr, SockAddrStep *step)
-{
-#ifndef NO_IPV6
- if (step->ai) {
- if (step->ai->ai_next) {
- step->ai = step->ai->ai_next;
- return true;
- } else
- return false;
- }
-#endif
- if (step->curraddr+1 < addr->naddresses) {
- step->curraddr++;
- return true;
- } else {
- return false;
- }
-}
-
-void sk_getaddr(SockAddr *addr, char *buf, int buflen)
-{
- SockAddrStep step;
- START_STEP(addr, step);
-
-#ifndef NO_IPV6
- if (step.ai) {
- int err = 0;
- if (p_WSAAddressToStringA) {
- DWORD dwbuflen = buflen;
- err = p_WSAAddressToStringA(step.ai->ai_addr, step.ai->ai_addrlen,
- NULL, buf, &dwbuflen);
- } else
- err = -1;
- if (err) {
- strncpy(buf, addr->hostname, buflen);
- if (!buf[0])
- strncpy(buf, "<unknown>", buflen);
- buf[buflen-1] = '\0';
- }
- } else
-#endif
- if (SOCKADDR_FAMILY(addr, step) == AF_INET) {
- struct in_addr a;
- assert(addr->addresses && step.curraddr < addr->naddresses);
- a.s_addr = p_htonl(addr->addresses[step.curraddr]);
- strncpy(buf, p_inet_ntoa(a), buflen);
- buf[buflen-1] = '\0';
- } else {
- strncpy(buf, addr->hostname, buflen);
- buf[buflen-1] = '\0';
- }
-}
-
-/*
- * This constructs a SockAddr that points at one specific sub-address
- * of a parent SockAddr. The returned SockAddr does not own all its
- * own memory: it points into the old one's data structures, so it
- * MUST NOT be used after the old one is freed, and it MUST NOT be
- * passed to sk_addr_free. (The latter is why it's returned by value
- * rather than dynamically allocated - that should clue in anyone
- * writing a call to it that something is weird about it.)
- */
-static SockAddr sk_extractaddr_tmp(
- SockAddr *addr, const SockAddrStep *step)
-{
- SockAddr toret;
- toret = *addr; /* structure copy */
- toret.refcount = 1;
-
-#ifndef NO_IPV6
- toret.ais = step->ai;
-#endif
- if (SOCKADDR_FAMILY(addr, *step) == AF_INET
-#ifndef NO_IPV6
- && !toret.ais
-#endif
- )
- toret.addresses += step->curraddr;
-
- return toret;
-}
-
-bool sk_addr_needs_port(SockAddr *addr)
-{
- return !addr->namedpipe;
-}
-
-bool sk_hostname_is_local(const char *name)
-{
- return !strcmp(name, "localhost") ||
- !strcmp(name, "::1") ||
- !strncmp(name, "127.", 4);
-}
-
-static INTERFACE_INFO local_interfaces[16];
-static int n_local_interfaces; /* 0=not yet, -1=failed, >0=number */
-
-static bool ipv4_is_local_addr(struct in_addr addr)
-{
- if (ipv4_is_loopback(addr))
- return true; /* loopback addresses are local */
- if (!n_local_interfaces) {
- SOCKET s = p_socket(AF_INET, SOCK_DGRAM, 0);
- DWORD retbytes;
-
- SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0);
-
- if (p_WSAIoctl &&
- p_WSAIoctl(s, SIO_GET_INTERFACE_LIST, NULL, 0,
- local_interfaces, sizeof(local_interfaces),
- &retbytes, NULL, NULL) == 0)
- n_local_interfaces = retbytes / sizeof(INTERFACE_INFO);
- else
- n_local_interfaces = -1;
- }
- if (n_local_interfaces > 0) {
- int i;
- for (i = 0; i < n_local_interfaces; i++) {
- SOCKADDR_IN *address =
- (SOCKADDR_IN *)&local_interfaces[i].iiAddress;
- if (address->sin_addr.s_addr == addr.s_addr)
- return true; /* this address is local */
- }
- }
- return false; /* this address is not local */
-}
-
-bool sk_address_is_local(SockAddr *addr)
-{
- SockAddrStep step;
- int family;
- START_STEP(addr, step);
- family = SOCKADDR_FAMILY(addr, step);
-
-#ifndef NO_IPV6
- if (family == AF_INET6) {
- return IN6_IS_ADDR_LOOPBACK(&((const struct sockaddr_in6 *)step.ai->ai_addr)->sin6_addr);
- } else
-#endif
- if (family == AF_INET) {
-#ifndef NO_IPV6
- if (step.ai) {
- return ipv4_is_local_addr(((struct sockaddr_in *)step.ai->ai_addr)
- ->sin_addr);
- } else
-#endif
- {
- struct in_addr a;
- assert(addr->addresses && step.curraddr < addr->naddresses);
- a.s_addr = p_htonl(addr->addresses[step.curraddr]);
- return ipv4_is_local_addr(a);
- }
- } else {
- assert(family == AF_UNSPEC);
- return false; /* we don't know; assume not */
- }
-}
-
-bool sk_address_is_special_local(SockAddr *addr)
-{
- return false; /* no Unix-domain socket analogue here */
-}
-
-int sk_addrtype(SockAddr *addr)
-{
- SockAddrStep step;
- int family;
- START_STEP(addr, step);
- family = SOCKADDR_FAMILY(addr, step);
-
- return (family == AF_INET ? ADDRTYPE_IPV4 :
-#ifndef NO_IPV6
- family == AF_INET6 ? ADDRTYPE_IPV6 :
-#endif
- ADDRTYPE_NAME);
-}
-
-void sk_addrcopy(SockAddr *addr, char *buf)
-{
- SockAddrStep step;
- int family;
- START_STEP(addr, step);
- family = SOCKADDR_FAMILY(addr, step);
-
- assert(family != AF_UNSPEC);
-#ifndef NO_IPV6
- if (step.ai) {
- if (family == AF_INET)
- memcpy(buf, &((struct sockaddr_in *)step.ai->ai_addr)->sin_addr,
- sizeof(struct in_addr));
- else if (family == AF_INET6)
- memcpy(buf, &((struct sockaddr_in6 *)step.ai->ai_addr)->sin6_addr,
- sizeof(struct in6_addr));
- else
- unreachable("bad address family in sk_addrcopy");
- } else
-#endif
- if (family == AF_INET) {
- struct in_addr a;
- assert(addr->addresses && step.curraddr < addr->naddresses);
- a.s_addr = p_htonl(addr->addresses[step.curraddr]);
- memcpy(buf, (char*) &a.s_addr, 4);
- }
-}
-
-void sk_addr_free(SockAddr *addr)
-{
- if (--addr->refcount > 0)
- return;
-#ifndef NO_IPV6
- if (addr->ais && p_freeaddrinfo)
- p_freeaddrinfo(addr->ais);
-#endif
- if (addr->addresses)
- sfree(addr->addresses);
- sfree(addr);
-}
-
-SockAddr *sk_addr_dup(SockAddr *addr)
-{
- addr->refcount++;
- return addr;
-}
-
-static Plug *sk_net_plug(Socket *sock, Plug *p)
-{
- NetSocket *s = container_of(sock, NetSocket, sock);
- Plug *ret = s->plug;
- if (p)
- s->plug = p;
- return ret;
-}
-
-static void sk_net_close(Socket *s);
-static size_t sk_net_write(Socket *s, const void *data, size_t len);
-static size_t sk_net_write_oob(Socket *s, const void *data, size_t len);
-static void sk_net_write_eof(Socket *s);
-static void sk_net_set_frozen(Socket *s, bool is_frozen);
-static const char *sk_net_socket_error(Socket *s);
-static SocketPeerInfo *sk_net_peer_info(Socket *s);
-
-static const SocketVtable NetSocket_sockvt = {
- .plug = sk_net_plug,
- .close = sk_net_close,
- .write = sk_net_write,
- .write_oob = sk_net_write_oob,
- .write_eof = sk_net_write_eof,
- .set_frozen = sk_net_set_frozen,
- .socket_error = sk_net_socket_error,
- .peer_info = sk_net_peer_info,
-};
-
-static Socket *sk_net_accept(accept_ctx_t ctx, Plug *plug)
-{
- DWORD err;
- const char *errstr;
- NetSocket *ret;
-
- /*
- * Create NetSocket structure.
- */
- ret = snew(NetSocket);
- ret->sock.vt = &NetSocket_sockvt;
- ret->error = NULL;
- ret->plug = plug;
- bufchain_init(&ret->output_data);
- ret->writable = true; /* to start with */
- ret->sending_oob = 0;
- ret->outgoingeof = EOF_NO;
- ret->frozen = true;
- ret->frozen_readable = false;
- ret->localhost_only = false; /* unused, but best init anyway */
- ret->pending_error = 0;
- ret->parent = ret->child = NULL;
- ret->addr = NULL;
-
- ret->s = (SOCKET)ctx.p;
-
- if (ret->s == INVALID_SOCKET) {
- err = p_WSAGetLastError();
- ret->error = winsock_error_string(err);
- return &ret->sock;
- }
-
- ret->oobinline = false;
-
- /* Set up a select mechanism. This could be an AsyncSelect on a
- * window, or an EventSelect on an event object. */
- errstr = do_select(ret->s, true);
- if (errstr) {
- ret->error = errstr;
- return &ret->sock;
- }
-
- add234(sktree, ret);
-
- return &ret->sock;
-}
-
-static DWORD try_connect(NetSocket *sock)
-{
- SOCKET s;
-#ifndef NO_IPV6
- SOCKADDR_IN6 a6;
-#endif
- SOCKADDR_IN a;
- DWORD err;
- const char *errstr;
- short localport;
- int family;
-
- if (sock->s != INVALID_SOCKET) {
- do_select(sock->s, false);
- p_closesocket(sock->s);
- }
-
- {
- SockAddr thisaddr = sk_extractaddr_tmp(
- sock->addr, &sock->step);
- plug_log(sock->plug, PLUGLOG_CONNECT_TRYING,
- &thisaddr, sock->port, NULL, 0);
- }
-
- /*
- * Open socket.
- */
- family = SOCKADDR_FAMILY(sock->addr, sock->step);
-
- /*
- * Remove the socket from the tree before we overwrite its
- * internal socket id, because that forms part of the tree's
- * sorting criterion. We'll add it back before exiting this
- * function, whether we changed anything or not.
- */
- del234(sktree, sock);
-
- s = p_socket(family, SOCK_STREAM, 0);
- sock->s = s;
-
- if (s == INVALID_SOCKET) {
- err = p_WSAGetLastError();
- sock->error = winsock_error_string(err);
- goto ret;
- }
-
- SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0);
-
- if (sock->oobinline) {
- BOOL b = true;
- p_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (void *) &b, sizeof(b));
- }
-
- if (sock->nodelay) {
- BOOL b = true;
- p_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b));
- }
-
- if (sock->keepalive) {
- BOOL b = true;
- p_setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *) &b, sizeof(b));
- }
-
- /*
- * Bind to local address.
- */
- if (sock->privport)
- localport = 1023; /* count from 1023 downwards */
- else
- localport = 0; /* just use port 0 (ie winsock picks) */
-
- /* Loop round trying to bind */
- while (1) {
- int sockcode;
-
-#ifndef NO_IPV6
- if (family == AF_INET6) {
- memset(&a6, 0, sizeof(a6));
- a6.sin6_family = AF_INET6;
- /*a6.sin6_addr = in6addr_any; */ /* == 0 done by memset() */
- a6.sin6_port = p_htons(localport);
- } else
-#endif
- {
- a.sin_family = AF_INET;
- a.sin_addr.s_addr = p_htonl(INADDR_ANY);
- a.sin_port = p_htons(localport);
- }
-#ifndef NO_IPV6
- sockcode = p_bind(s, (family == AF_INET6 ?
- (struct sockaddr *) &a6 :
- (struct sockaddr *) &a),
- (family == AF_INET6 ? sizeof(a6) : sizeof(a)));
-#else
- sockcode = p_bind(s, (struct sockaddr *) &a, sizeof(a));
-#endif
- if (sockcode != SOCKET_ERROR) {
- err = 0;
- break; /* done */
- } else {
- err = p_WSAGetLastError();
- if (err != WSAEADDRINUSE) /* failed, for a bad reason */
- break;
- }
-
- if (localport == 0)
- break; /* we're only looping once */
- localport--;
- if (localport == 0)
- break; /* we might have got to the end */
- }
-
- if (err) {
- sock->error = winsock_error_string(err);
- goto ret;
- }
-
- /*
- * Connect to remote address.
- */
-#ifndef NO_IPV6
- if (sock->step.ai) {
- if (family == AF_INET6) {
- a6.sin6_family = AF_INET6;
- a6.sin6_port = p_htons((short) sock->port);
- a6.sin6_addr =
- ((struct sockaddr_in6 *) sock->step.ai->ai_addr)->sin6_addr;
- a6.sin6_flowinfo = ((struct sockaddr_in6 *) sock->step.ai->ai_addr)->sin6_flowinfo;
- a6.sin6_scope_id = ((struct sockaddr_in6 *) sock->step.ai->ai_addr)->sin6_scope_id;
- } else {
- a.sin_family = AF_INET;
- a.sin_addr =
- ((struct sockaddr_in *) sock->step.ai->ai_addr)->sin_addr;
- a.sin_port = p_htons((short) sock->port);
- }
- } else
-#endif
- {
- assert(sock->addr->addresses && sock->step.curraddr < sock->addr->naddresses);
- a.sin_family = AF_INET;
- a.sin_addr.s_addr = p_htonl(sock->addr->addresses[sock->step.curraddr]);
- a.sin_port = p_htons((short) sock->port);
- }
-
- /* Set up a select mechanism. This could be an AsyncSelect on a
- * window, or an EventSelect on an event object. */
- errstr = do_select(s, true);
- if (errstr) {
- sock->error = errstr;
- err = 1;
- goto ret;
- }
-
- if ((
-#ifndef NO_IPV6
- p_connect(s,
- ((family == AF_INET6) ? (struct sockaddr *) &a6 :
- (struct sockaddr *) &a),
- (family == AF_INET6) ? sizeof(a6) : sizeof(a))
-#else
- p_connect(s, (struct sockaddr *) &a, sizeof(a))
-#endif
- ) == SOCKET_ERROR) {
- err = p_WSAGetLastError();
- /*
- * We expect a potential EWOULDBLOCK here, because the
- * chances are the front end has done a select for
- * FD_CONNECT, so that connect() will complete
- * asynchronously.
- */
- if ( err != WSAEWOULDBLOCK ) {
- sock->error = winsock_error_string(err);
- goto ret;
- }
- } else {
- /*
- * If we _don't_ get EWOULDBLOCK, the connect has completed
- * and we should set the socket as writable.
- */
- sock->writable = true;
- SockAddr thisaddr = sk_extractaddr_tmp(sock->addr, &sock->step);
- plug_log(sock->plug, PLUGLOG_CONNECT_SUCCESS,
- &thisaddr, sock->port, NULL, 0);
- }
-
- err = 0;
-
- ret:
-
- /*
- * No matter what happened, put the socket back in the tree.
- */
- add234(sktree, sock);
-
- if (err) {
- SockAddr thisaddr = sk_extractaddr_tmp(
- sock->addr, &sock->step);
- plug_log(sock->plug, PLUGLOG_CONNECT_FAILED,
- &thisaddr, sock->port, sock->error, err);
- }
- return err;
-}
-
-Socket *sk_new(SockAddr *addr, int port, bool privport, bool oobinline,
- bool nodelay, bool keepalive, Plug *plug)
-{
- NetSocket *ret;
- DWORD err;
-
- /*
- * Create NetSocket structure.
- */
- ret = snew(NetSocket);
- ret->sock.vt = &NetSocket_sockvt;
- ret->error = NULL;
- ret->plug = plug;
- bufchain_init(&ret->output_data);
- ret->connected = false; /* to start with */
- ret->writable = false; /* to start with */
- ret->sending_oob = 0;
- ret->outgoingeof = EOF_NO;
- ret->frozen = false;
- ret->frozen_readable = false;
- ret->localhost_only = false; /* unused, but best init anyway */
- ret->pending_error = 0;
- ret->parent = ret->child = NULL;
- ret->oobinline = oobinline;
- ret->nodelay = nodelay;
- ret->keepalive = keepalive;
- ret->privport = privport;
- ret->port = port;
- ret->addr = addr;
- START_STEP(ret->addr, ret->step);
- ret->s = INVALID_SOCKET;
-
- err = 0;
- do {
- err = try_connect(ret);
- } while (err && sk_nextaddr(ret->addr, &ret->step));
-
- return &ret->sock;
-}
-
-Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug,
- bool local_host_only, int orig_address_family)
-{
- SOCKET s;
-#ifndef NO_IPV6
- SOCKADDR_IN6 a6;
-#endif
- SOCKADDR_IN a;
-
- DWORD err;
- const char *errstr;
- NetSocket *ret;
- int retcode;
-
- int address_family;
-
- /*
- * Create NetSocket structure.
- */
- ret = snew(NetSocket);
- ret->sock.vt = &NetSocket_sockvt;
- ret->error = NULL;
- ret->plug = plug;
- bufchain_init(&ret->output_data);
- ret->writable = false; /* to start with */
- ret->sending_oob = 0;
- ret->outgoingeof = EOF_NO;
- ret->frozen = false;
- ret->frozen_readable = false;
- ret->localhost_only = local_host_only;
- ret->pending_error = 0;
- ret->parent = ret->child = NULL;
- ret->addr = NULL;
-
- /*
- * Translate address_family from platform-independent constants
- * into local reality.
- */
- address_family = (orig_address_family == ADDRTYPE_IPV4 ? AF_INET :
-#ifndef NO_IPV6
- orig_address_family == ADDRTYPE_IPV6 ? AF_INET6 :
-#endif
- AF_UNSPEC);
-
- /*
- * Our default, if passed the `don't care' value
- * ADDRTYPE_UNSPEC, is to listen on IPv4. If IPv6 is supported,
- * we will also set up a second socket listening on IPv6, but
- * the v4 one is primary since that ought to work even on
- * non-v6-supporting systems.
- */
- if (address_family == AF_UNSPEC) address_family = AF_INET;
-
- /*
- * Open socket.
- */
- s = p_socket(address_family, SOCK_STREAM, 0);
- ret->s = s;
-
- if (s == INVALID_SOCKET) {
- err = p_WSAGetLastError();
- ret->error = winsock_error_string(err);
- return &ret->sock;
- }
-
- SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0);
-
- ret->oobinline = false;
-
- {
- BOOL on = true;
- p_setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
- (const char *)&on, sizeof(on));
- }
-
-#ifndef NO_IPV6
- if (address_family == AF_INET6) {
- memset(&a6, 0, sizeof(a6));
- a6.sin6_family = AF_INET6;
- if (local_host_only)
- a6.sin6_addr = in6addr_loopback;
- else
- a6.sin6_addr = in6addr_any;
- if (srcaddr != NULL && p_getaddrinfo) {
- struct addrinfo hints;
- struct addrinfo *ai;
- int err;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_INET6;
- hints.ai_flags = 0;
- {
- /* strip [] on IPv6 address literals */
- char *trimmed_addr = host_strduptrim(srcaddr);
- err = p_getaddrinfo(trimmed_addr, NULL, &hints, &ai);
- sfree(trimmed_addr);
- }
- if (err == 0 && ai->ai_family == AF_INET6) {
- a6.sin6_addr =
- ((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
- }
- }
- a6.sin6_port = p_htons(port);
- } else
-#endif
- {
- bool got_addr = false;
- a.sin_family = AF_INET;
-
- /*
- * Bind to source address. First try an explicitly
- * specified one...
- */
- if (srcaddr) {
- a.sin_addr.s_addr = p_inet_addr(srcaddr);
- if (a.sin_addr.s_addr != INADDR_NONE) {
- /* Override localhost_only with specified listen addr. */
- ret->localhost_only = ipv4_is_loopback(a.sin_addr);
- got_addr = true;
- }
- }
-
- /*
- * ... and failing that, go with one of the standard ones.
- */
- if (!got_addr) {
- if (local_host_only)
- a.sin_addr.s_addr = p_htonl(INADDR_LOOPBACK);
- else
- a.sin_addr.s_addr = p_htonl(INADDR_ANY);
- }
-
- a.sin_port = p_htons((short)port);
- }
-#ifndef NO_IPV6
- retcode = p_bind(s, (address_family == AF_INET6 ?
- (struct sockaddr *) &a6 :
- (struct sockaddr *) &a),
- (address_family ==
- AF_INET6 ? sizeof(a6) : sizeof(a)));
-#else
- retcode = p_bind(s, (struct sockaddr *) &a, sizeof(a));
-#endif
- if (retcode != SOCKET_ERROR) {
- err = 0;
- } else {
- err = p_WSAGetLastError();
- }
-
- if (err) {
- p_closesocket(s);
- ret->error = winsock_error_string(err);
- return &ret->sock;
- }
-
-
- if (p_listen(s, SOMAXCONN) == SOCKET_ERROR) {
- p_closesocket(s);
- ret->error = winsock_error_string(p_WSAGetLastError());
- return &ret->sock;
- }
-
- /* Set up a select mechanism. This could be an AsyncSelect on a
- * window, or an EventSelect on an event object. */
- errstr = do_select(s, true);
- if (errstr) {
- p_closesocket(s);
- ret->error = errstr;
- return &ret->sock;
- }
-
- add234(sktree, ret);
-
-#ifndef NO_IPV6
- /*
- * If we were given ADDRTYPE_UNSPEC, we must also create an
- * IPv6 listening socket and link it to this one.
- */
- if (address_family == AF_INET && orig_address_family == ADDRTYPE_UNSPEC) {
- Socket *other = sk_newlistener(srcaddr, port, plug,
- local_host_only, ADDRTYPE_IPV6);
-
- if (other) {
- NetSocket *ns = container_of(other, NetSocket, sock);
- if (!ns->error) {
- ns->parent = ret;
- ret->child = ns;
- } else {
- sfree(ns);
- }
- }
- }
-#endif
-
- return &ret->sock;
-}
-
-static void sk_net_close(Socket *sock)
-{
- NetSocket *s = container_of(sock, NetSocket, sock);
-
- if (s->child)
- sk_net_close(&s->child->sock);
-
- bufchain_clear(&s->output_data);
-
- del234(sktree, s);
- do_select(s->s, false);
- p_closesocket(s->s);
- if (s->addr)
- sk_addr_free(s->addr);
- delete_callbacks_for_context(s);
- sfree(s);
-}
-
-/*
- * Deal with socket errors detected in try_send().
- */
-static void socket_error_callback(void *vs)
-{
- NetSocket *s = (NetSocket *)vs;
-
- /*
- * Just in case other socket work has caused this socket to vanish
- * or become somehow non-erroneous before this callback arrived...
- */
- if (!find234(sktree, s, NULL) || !s->pending_error)
- return;
-
- /*
- * An error has occurred on this socket. Pass it to the plug.
- */
- plug_closing(s->plug, winsock_error_string(s->pending_error),
- s->pending_error, 0);
-}
-
-/*
- * The function which tries to send on a socket once it's deemed
- * writable.
- */
-void try_send(NetSocket *s)
-{
- while (s->sending_oob || bufchain_size(&s->output_data) > 0) {
- int nsent;
- DWORD err;
- const void *data;
- size_t len;
- int urgentflag;
-
- if (s->sending_oob) {
- urgentflag = MSG_OOB;
- len = s->sending_oob;
- data = &s->oobdata;
- } else {
- urgentflag = 0;
- ptrlen bufdata = bufchain_prefix(&s->output_data);
- data = bufdata.ptr;
- len = bufdata.len;
- }
- len = min(len, INT_MAX); /* WinSock send() takes an int */
- nsent = p_send(s->s, data, len, urgentflag);
- noise_ultralight(NOISE_SOURCE_IOLEN, nsent);
- if (nsent <= 0) {
- err = (nsent < 0 ? p_WSAGetLastError() : 0);
- if ((err < WSABASEERR && nsent < 0) || err == WSAEWOULDBLOCK) {
- /*
- * Perfectly normal: we've sent all we can for the moment.
- *
- * (Some WinSock send() implementations can return
- * <0 but leave no sensible error indication -
- * WSAGetLastError() is called but returns zero or
- * a small number - so we check that case and treat
- * it just like WSAEWOULDBLOCK.)
- */
- s->writable = false;
- return;
- } else {
- /*
- * If send() returns a socket error, we unfortunately
- * can't just call plug_closing(), because it's quite
- * likely that we're currently _in_ a call from the
- * code we'd be calling back to, so we'd have to make
- * half the SSH code reentrant. Instead we flag a
- * pending error on the socket, to be dealt with (by
- * calling plug_closing()) at some suitable future
- * moment.
- */
- s->pending_error = err;
- queue_toplevel_callback(socket_error_callback, s);
- return;
- }
- } else {
- if (s->sending_oob) {
- if (nsent < len) {
- memmove(s->oobdata, s->oobdata+nsent, len-nsent);
- s->sending_oob = len - nsent;
- } else {
- s->sending_oob = 0;
- }
- } else {
- bufchain_consume(&s->output_data, nsent);
- }
- }
- }
-
- /*
- * If we reach here, we've finished sending everything we might
- * have needed to send. Send EOF, if we need to.
- */
- if (s->outgoingeof == EOF_PENDING) {
- p_shutdown(s->s, SD_SEND);
- s->outgoingeof = EOF_SENT;
- }
-}
-
-static size_t sk_net_write(Socket *sock, const void *buf, size_t len)
-{
- NetSocket *s = container_of(sock, NetSocket, sock);
-
- assert(s->outgoingeof == EOF_NO);
-
- /*
- * Add the data to the buffer list on the socket.
- */
- bufchain_add(&s->output_data, buf, len);
-
- /*
- * Now try sending from the start of the buffer list.
- */
- if (s->writable)
- try_send(s);
-
- return bufchain_size(&s->output_data);
-}
-
-static size_t sk_net_write_oob(Socket *sock, const void *buf, size_t len)
-{
- NetSocket *s = container_of(sock, NetSocket, sock);
-
- assert(s->outgoingeof == EOF_NO);
-
- /*
- * Replace the buffer list on the socket with the data.
- */
- bufchain_clear(&s->output_data);
- assert(len <= sizeof(s->oobdata));
- memcpy(s->oobdata, buf, len);
- s->sending_oob = len;
-
- /*
- * Now try sending from the start of the buffer list.
- */
- if (s->writable)
- try_send(s);
-
- return s->sending_oob;
-}
-
-static void sk_net_write_eof(Socket *sock)
-{
- NetSocket *s = container_of(sock, NetSocket, sock);
-
- assert(s->outgoingeof == EOF_NO);
-
- /*
- * Mark the socket as pending outgoing EOF.
- */
- s->outgoingeof = EOF_PENDING;
-
- /*
- * Now try sending from the start of the buffer list.
- */
- if (s->writable)
- try_send(s);
-}
-
-void select_result(WPARAM wParam, LPARAM lParam)
-{
- int ret;
- DWORD err;
- char buf[20480]; /* nice big buffer for plenty of speed */
- NetSocket *s;
- bool atmark;
-
- /* wParam is the socket itself */
-
- if (wParam == 0)
- return; /* boggle */
-
- s = find234(sktree, (void *) wParam, cmpforsearch);
- if (!s)
- return; /* boggle */
-
- if ((err = WSAGETSELECTERROR(lParam)) != 0) {
- /*
- * An error has occurred on this socket. Pass it to the
- * plug.
- */
- if (s->addr) {
- SockAddr thisaddr = sk_extractaddr_tmp(
- s->addr, &s->step);
- plug_log(s->plug, PLUGLOG_CONNECT_FAILED, &thisaddr, s->port,
- winsock_error_string(err), err);
- while (err && s->addr && sk_nextaddr(s->addr, &s->step)) {
- err = try_connect(s);
- }
- }
- if (err != 0)
- plug_closing(s->plug, winsock_error_string(err), err, 0);
- return;
- }
-
- noise_ultralight(NOISE_SOURCE_IOID, wParam);
-
- switch (WSAGETSELECTEVENT(lParam)) {
- case FD_CONNECT:
- s->connected = true;
- s->writable = true;
-
- /*
- * Once a socket is connected, we can stop falling back
- * through the candidate addresses to connect to. But first,
- * let the plug know we were successful.
- */
- if (s->addr) {
- SockAddr thisaddr = sk_extractaddr_tmp(
- s->addr, &s->step);
- plug_log(s->plug, PLUGLOG_CONNECT_SUCCESS,
- &thisaddr, s->port, NULL, 0);
-
- sk_addr_free(s->addr);
- s->addr = NULL;
- }
- break;
- case FD_READ:
- /* In the case the socket is still frozen, we don't even bother */
- if (s->frozen) {
- s->frozen_readable = true;
- break;
- }
-
- /*
- * We have received data on the socket. For an oobinline
- * socket, this might be data _before_ an urgent pointer,
- * in which case we send it to the back end with type==1
- * (data prior to urgent).
- */
- if (s->oobinline) {
- u_long atmark_from_ioctl = 1;
- p_ioctlsocket(s->s, SIOCATMARK, &atmark_from_ioctl);
- /*
- * Avoid checking the return value from ioctlsocket(),
- * on the grounds that some WinSock wrappers don't
- * support it. If it does nothing, we get atmark==1,
- * which is equivalent to `no OOB pending', so the
- * effect will be to non-OOB-ify any OOB data.
- */
- atmark = atmark_from_ioctl;
- } else
- atmark = true;
-
- ret = p_recv(s->s, buf, sizeof(buf), 0);
- noise_ultralight(NOISE_SOURCE_IOLEN, ret);
- if (ret < 0) {
- err = p_WSAGetLastError();
- if (err == WSAEWOULDBLOCK) {
- break;
- }
- }
- if (ret < 0) {
- plug_closing(s->plug, winsock_error_string(err), err, 0);
- } else if (0 == ret) {
- plug_closing(s->plug, NULL, 0, 0);
- } else {
- plug_receive(s->plug, atmark ? 0 : 1, buf, ret);
- }
- break;
- case FD_OOB:
- /*
- * This will only happen on a non-oobinline socket. It
- * indicates that we can immediately perform an OOB read
- * and get back OOB data, which we will send to the back
- * end with type==2 (urgent data).
- */
- ret = p_recv(s->s, buf, sizeof(buf), MSG_OOB);
- noise_ultralight(NOISE_SOURCE_IOLEN, ret);
- if (ret <= 0) {
- int err = p_WSAGetLastError();
- plug_closing(s->plug, winsock_error_string(err), err, 0);
- } else {
- plug_receive(s->plug, 2, buf, ret);
- }
- break;
- case FD_WRITE: {
- int bufsize_before, bufsize_after;
- s->writable = true;
- bufsize_before = s->sending_oob + bufchain_size(&s->output_data);
- try_send(s);
- bufsize_after = s->sending_oob + bufchain_size(&s->output_data);
- if (bufsize_after < bufsize_before)
- plug_sent(s->plug, bufsize_after);
- break;
- }
- case FD_CLOSE:
- /* Signal a close on the socket. First read any outstanding data. */
- do {
- ret = p_recv(s->s, buf, sizeof(buf), 0);
- if (ret < 0) {
- err = p_WSAGetLastError();
- if (err == WSAEWOULDBLOCK)
- break;
- plug_closing(s->plug, winsock_error_string(err), err, 0);
- } else {
- if (ret)
- plug_receive(s->plug, 0, buf, ret);
- else
- plug_closing(s->plug, NULL, 0, 0);
- }
- } while (ret > 0);
- return;
- case FD_ACCEPT: {
-#ifdef NO_IPV6
- struct sockaddr_in isa;
-#else
- struct sockaddr_storage isa;
-#endif
- int addrlen = sizeof(isa);
- SOCKET t; /* socket of connection */
- accept_ctx_t actx;
-
- memset(&isa, 0, sizeof(isa));
- err = 0;
- t = p_accept(s->s,(struct sockaddr *)&isa,&addrlen);
- if (t == INVALID_SOCKET)
- {
- err = p_WSAGetLastError();
- if (err == WSATRY_AGAIN)
- break;
- }
-
- actx.p = (void *)t;
-
-#ifndef NO_IPV6
- if (isa.ss_family == AF_INET &&
- s->localhost_only &&
- !ipv4_is_local_addr(((struct sockaddr_in *)&isa)->sin_addr))
-#else
- if (s->localhost_only && !ipv4_is_local_addr(isa.sin_addr))
-#endif
- {
- p_closesocket(t); /* dodgy WinSock let nonlocal through */
- } else if (plug_accepting(s->plug, sk_net_accept, actx)) {
- p_closesocket(t); /* denied or error */
- }
- break;
- }
- }
-}
-
-/*
- * Special error values are returned from sk_namelookup and sk_new
- * if there's a problem. These functions extract an error message,
- * or return NULL if there's no problem.
- */
-const char *sk_addr_error(SockAddr *addr)
-{
- return addr->error;
-}
-static const char *sk_net_socket_error(Socket *sock)
-{
- NetSocket *s = container_of(sock, NetSocket, sock);
- return s->error;
-}
-
-static SocketPeerInfo *sk_net_peer_info(Socket *sock)
-{
- NetSocket *s = container_of(sock, NetSocket, sock);
-#ifdef NO_IPV6
- struct sockaddr_in addr;
-#else
- struct sockaddr_storage addr;
- char buf[INET6_ADDRSTRLEN];
-#endif
- int addrlen = sizeof(addr);
- SocketPeerInfo *pi;
-
- if (p_getpeername(s->s, (struct sockaddr *)&addr, &addrlen) < 0)
- return NULL;
-
- pi = snew(SocketPeerInfo);
- pi->addressfamily = ADDRTYPE_UNSPEC;
- pi->addr_text = NULL;
- pi->port = -1;
- pi->log_text = NULL;
-
- if (((struct sockaddr *)&addr)->sa_family == AF_INET) {
- pi->addressfamily = ADDRTYPE_IPV4;
- memcpy(pi->addr_bin.ipv4, &((struct sockaddr_in *)&addr)->sin_addr, 4);
- pi->port = p_ntohs(((struct sockaddr_in *)&addr)->sin_port);
- pi->addr_text = dupstr(
- p_inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr));
- pi->log_text = dupprintf("%s:%d", pi->addr_text, pi->port);
-
-#ifndef NO_IPV6
- } else if (((struct sockaddr *)&addr)->sa_family == AF_INET6) {
- pi->addressfamily = ADDRTYPE_IPV6;
- memcpy(pi->addr_bin.ipv6,
- &((struct sockaddr_in6 *)&addr)->sin6_addr, 16);
- pi->port = p_ntohs(((struct sockaddr_in6 *)&addr)->sin6_port);
- pi->addr_text = dupstr(
- p_inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr,
- buf, sizeof(buf)));
- pi->log_text = dupprintf("[%s]:%d", pi->addr_text, pi->port);
-
-#endif
- } else {
- sfree(pi);
- return NULL;
- }
-
- return pi;
-}
-
-static void sk_net_set_frozen(Socket *sock, bool is_frozen)
-{
- NetSocket *s = container_of(sock, NetSocket, sock);
- if (s->frozen == is_frozen)
- return;
- s->frozen = is_frozen;
- if (!is_frozen) {
- do_select(s->s, true);
- if (s->frozen_readable) {
- char c;
- p_recv(s->s, &c, 1, MSG_PEEK);
- }
- }
- s->frozen_readable = false;
-}
-
-void socket_reselect_all(void)
-{
- NetSocket *s;
- int i;
-
- for (i = 0; (s = index234(sktree, i)) != NULL; i++) {
- if (!s->frozen)
- do_select(s->s, true);
- }
-}
-
-/*
- * For Plink: enumerate all sockets currently active.
- */
-SOCKET first_socket(int *state)
-{
- NetSocket *s;
- *state = 0;
- s = index234(sktree, (*state)++);
- return s ? s->s : INVALID_SOCKET;
-}
-
-SOCKET next_socket(int *state)
-{
- NetSocket *s = index234(sktree, (*state)++);
- return s ? s->s : INVALID_SOCKET;
-}
-
-bool socket_writable(SOCKET skt)
-{
- NetSocket *s = find234(sktree, (void *)skt, cmpforsearch);
-
- if (s)
- return bufchain_size(&s->output_data) > 0;
- else
- return false;
-}
-
-int net_service_lookup(char *service)
-{
- struct servent *se;
- se = p_getservbyname(service, NULL);
- if (se != NULL)
- return p_ntohs(se->s_port);
- else
- return 0;
-}
-
-char *get_hostname(void)
-{
- char hostbuf[256]; /* MSDN docs for gethostname() promise this is enough */
- if (p_gethostname(hostbuf, sizeof(hostbuf)) < 0)
- return NULL;
- return dupstr(hostbuf);
-}
-
-SockAddr *platform_get_x11_unix_address(const char *display, int displaynum)
-{
- SockAddr *ret = snew(SockAddr);
- memset(ret, 0, sizeof(SockAddr));
- ret->error = "unix sockets not supported on this platform";
- ret->refcount = 1;
- return ret;
-}
diff --git a/WINDOWS/WINNOISE.C b/WINDOWS/WINNOISE.C
deleted file mode 100644
index 65c4c92d..00000000
--- a/WINDOWS/WINNOISE.C
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Noise generation for PuTTY's cryptographic random number
- * generator.
- */
-
-#include <stdio.h>
-
-#include "putty.h"
-#include "ssh.h"
-#include "storage.h"
-
-#include <wincrypt.h>
-
-DECL_WINDOWS_FUNCTION(static, BOOL, CryptAcquireContextA,
- (HCRYPTPROV *, LPCTSTR, LPCTSTR, DWORD, DWORD));
-DECL_WINDOWS_FUNCTION(static, BOOL, CryptGenRandom,
- (HCRYPTPROV, DWORD, BYTE *));
-DECL_WINDOWS_FUNCTION(static, BOOL, CryptReleaseContext,
- (HCRYPTPROV, DWORD));
-static HMODULE wincrypt_module = NULL;
-
-bool win_read_random(void *buf, unsigned wanted)
-{
- bool toret = false;
- HCRYPTPROV crypt_provider;
-
- if (!wincrypt_module) {
- wincrypt_module = load_system32_dll("advapi32.dll");
- GET_WINDOWS_FUNCTION(wincrypt_module, CryptAcquireContextA);
- GET_WINDOWS_FUNCTION(wincrypt_module, CryptGenRandom);
- GET_WINDOWS_FUNCTION(wincrypt_module, CryptReleaseContext);
- }
-
- if (wincrypt_module && p_CryptAcquireContextA &&
- p_CryptGenRandom && p_CryptReleaseContext &&
- p_CryptAcquireContextA(&crypt_provider, NULL, NULL, PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT)) {
- toret = p_CryptGenRandom(crypt_provider, wanted, buf);
- p_CryptReleaseContext(crypt_provider, 0);
- }
-
- return toret;
-}
-
-/*
- * This function is called once, at PuTTY startup.
- */
-
-void noise_get_heavy(void (*func) (void *, int))
-{
- HANDLE srch;
- WIN32_FIND_DATA finddata;
- DWORD pid;
- char winpath[MAX_PATH + 3];
- BYTE buf[32];
-
- GetWindowsDirectory(winpath, sizeof(winpath));
- strcat(winpath, "\\*");
- srch = FindFirstFile(winpath, &finddata);
- if (srch != INVALID_HANDLE_VALUE) {
- do {
- func(&finddata, sizeof(finddata));
- } while (FindNextFile(srch, &finddata));
- FindClose(srch);
- }
-
- pid = GetCurrentProcessId();
- func(&pid, sizeof(pid));
-
- if (win_read_random(buf, sizeof(buf))) {
- func(buf, sizeof(buf));
- smemclr(buf, sizeof(buf));
- }
-
- read_random_seed(func);
-}
-
-/*
- * This function is called on a timer, and it will monitor
- * frequently changing quantities such as the state of physical and
- * virtual memory, the state of the process's message queue, which
- * window is in the foreground, which owns the clipboard, etc.
- */
-void noise_regular(void)
-{
- HWND w;
- DWORD z;
- POINT pt;
- MEMORYSTATUS memstat;
- FILETIME times[4];
-
- w = GetForegroundWindow();
- random_add_noise(NOISE_SOURCE_FGWINDOW, &w, sizeof(w));
- w = GetCapture();
- random_add_noise(NOISE_SOURCE_CAPTURE, &w, sizeof(w));
- w = GetClipboardOwner();
- random_add_noise(NOISE_SOURCE_CLIPBOARD, &w, sizeof(w));
- z = GetQueueStatus(QS_ALLEVENTS);
- random_add_noise(NOISE_SOURCE_QUEUE, &z, sizeof(z));
-
- GetCursorPos(&pt);
- random_add_noise(NOISE_SOURCE_CURSORPOS, &pt, sizeof(pt));
-
- GlobalMemoryStatus(&memstat);
- random_add_noise(NOISE_SOURCE_MEMINFO, &memstat, sizeof(memstat));
-
- GetThreadTimes(GetCurrentThread(), times, times + 1, times + 2,
- times + 3);
- random_add_noise(NOISE_SOURCE_THREADTIME, &times, sizeof(times));
- GetProcessTimes(GetCurrentProcess(), times, times + 1, times + 2,
- times + 3);
- random_add_noise(NOISE_SOURCE_PROCTIME, &times, sizeof(times));
-}
-
-/*
- * This function is called on every keypress or mouse move, and
- * will add the current Windows time and performance monitor
- * counter to the noise pool. It gets the scan code or mouse
- * position passed in.
- */
-void noise_ultralight(NoiseSourceId id, unsigned long data)
-{
- DWORD wintime;
- LARGE_INTEGER perftime;
-
- random_add_noise(id, &data, sizeof(DWORD));
-
- wintime = GetTickCount();
- random_add_noise(NOISE_SOURCE_TIME, &wintime, sizeof(DWORD));
-
- if (QueryPerformanceCounter(&perftime))
- random_add_noise(NOISE_SOURCE_PERFCOUNT, &perftime, sizeof(perftime));
-}
-
-uint64_t prng_reseed_time_ms(void)
-{
- FILETIME ft;
- GetSystemTimeAsFileTime(&ft);
- uint64_t value = ft.dwHighDateTime;
- value = (value << 32) + ft.dwLowDateTime;
- return value / 10000; /* 1 millisecond / 100ns */
-}
diff --git a/WINDOWS/WINNOJMP.C b/WINDOWS/WINNOJMP.C
deleted file mode 100644
index dd61dc69..00000000
--- a/WINDOWS/WINNOJMP.C
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * winnojmp.c: stub jump list functions for Windows executables that
- * don't update the jump list.
- */
-
-void add_session_to_jumplist(const char * const sessionname) {}
-void remove_session_from_jumplist(const char * const sessionname) {}
-void clear_jumplist(void) {}
diff --git a/WINDOWS/WINPGEN.C b/WINDOWS/WINPGEN.C
deleted file mode 100644
index 56c6a8db..00000000
--- a/WINDOWS/WINPGEN.C
+++ /dev/null
@@ -1,2026 +0,0 @@
-/*
- * PuTTY key generation front end (Windows).
- */
-
-#include <time.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#include "putty.h"
-#include "ssh.h"
-#include "sshkeygen.h"
-#include "licence.h"
-#include "winsecur.h"
-#include "puttygen-rc.h"
-
-#include <commctrl.h>
-
-#ifdef MSVC4
-#define ICON_BIG 1
-#endif
-
-#define WM_DONEKEY (WM_APP + 1)
-
-#define DEFAULT_KEY_BITS 2048
-#define DEFAULT_ECCURVE_INDEX 0
-#define DEFAULT_EDCURVE_INDEX 0
-
-static char *cmdline_keyfile = NULL;
-
-/*
- * Print a modal (Really Bad) message box and perform a fatal exit.
- */
-void modalfatalbox(const char *fmt, ...)
-{
- va_list ap;
- char *stuff;
-
- va_start(ap, fmt);
- stuff = dupvprintf(fmt, ap);
- va_end(ap);
- MessageBox(NULL, stuff, "PuTTYgen Fatal Error",
- MB_SYSTEMMODAL | MB_ICONERROR | MB_OK);
- sfree(stuff);
- exit(1);
-}
-
-/*
- * Print a non-fatal message box and do not exit.
- */
-void nonfatal(const char *fmt, ...)
-{
- va_list ap;
- char *stuff;
-
- va_start(ap, fmt);
- stuff = dupvprintf(fmt, ap);
- va_end(ap);
- MessageBox(NULL, stuff, "PuTTYgen Error",
- MB_SYSTEMMODAL | MB_ICONERROR | MB_OK);
- sfree(stuff);
-}
-
-/* ----------------------------------------------------------------------
- * ProgressReceiver implementation.
- */
-
-#define PROGRESSRANGE 65535
-
-struct progressphase {
- double startpoint, total;
- /* For exponential phases */
- double exp_probability, exp_current_value;
-};
-
-struct progress {
- size_t nphases, phasessize;
- struct progressphase *phases, *currphase;
-
- double scale;
- HWND progbar;
-
- ProgressReceiver rec;
-};
-
-static ProgressPhase win_progress_add_linear(
- ProgressReceiver *prog, double overall_cost) {
- struct progress *p = container_of(prog, struct progress, rec);
-
- sgrowarray(p->phases, p->phasessize, p->nphases);
- int phase = p->nphases++;
-
- p->phases[phase].total = overall_cost;
-
- ProgressPhase ph = { .n = phase };
- return ph;
-}
-
-static ProgressPhase win_progress_add_probabilistic(
- ProgressReceiver *prog, double cost_per_attempt, double probability) {
- struct progress *p = container_of(prog, struct progress, rec);
-
- sgrowarray(p->phases, p->phasessize, p->nphases);
- int phase = p->nphases++;
-
- p->phases[phase].exp_probability = 1.0 - probability;
- p->phases[phase].exp_current_value = 1.0;
- /* Expected number of attempts = 1 / probability of attempt succeeding */
- p->phases[phase].total = cost_per_attempt / probability;
-
- ProgressPhase ph = { .n = phase };
- return ph;
-}
-
-static void win_progress_ready(ProgressReceiver *prog)
-{
- struct progress *p = container_of(prog, struct progress, rec);
-
- double total = 0;
- for (int i = 0; i < p->nphases; i++) {
- p->phases[i].startpoint = total;
- total += p->phases[i].total;
- }
- p->scale = PROGRESSRANGE / total;
-
- SendMessage(p->progbar, PBM_SETRANGE, 0, MAKELPARAM(0, PROGRESSRANGE));
-}
-
-static void win_progress_start_phase(ProgressReceiver *prog,
- ProgressPhase phase)
-{
- struct progress *p = container_of(prog, struct progress, rec);
-
- assert(phase.n < p->nphases);
- p->currphase = &p->phases[phase.n];
-}
-
-static void win_progress_update(struct progress *p, double phasepos)
-{
- double position = (p->currphase->startpoint +
- p->currphase->total * phasepos);
- position *= p->scale;
- if (position < 0)
- position = 0;
- if (position > PROGRESSRANGE)
- position = PROGRESSRANGE;
-
- SendMessage(p->progbar, PBM_SETPOS, (WPARAM)position, 0);
-}
-
-static void win_progress_report(ProgressReceiver *prog, double progress)
-{
- struct progress *p = container_of(prog, struct progress, rec);
-
- win_progress_update(p, progress);
-}
-
-static void win_progress_report_attempt(ProgressReceiver *prog)
-{
- struct progress *p = container_of(prog, struct progress, rec);
-
- p->currphase->exp_current_value *= p->currphase->exp_probability;
- win_progress_update(p, 1.0 - p->currphase->exp_current_value);
-}
-
-static void win_progress_report_phase_complete(ProgressReceiver *prog)
-{
- struct progress *p = container_of(prog, struct progress, rec);
-
- win_progress_update(p, 1.0);
-}
-
-static const ProgressReceiverVtable win_progress_vt = {
- .add_linear = win_progress_add_linear,
- .add_probabilistic = win_progress_add_probabilistic,
- .ready = win_progress_ready,
- .start_phase = win_progress_start_phase,
- .report = win_progress_report,
- .report_attempt = win_progress_report_attempt,
- .report_phase_complete = win_progress_report_phase_complete,
-};
-
-static void win_progress_initialise(struct progress *p)
-{
- p->nphases = p->phasessize = 0;
- p->phases = p->currphase = NULL;
- p->rec.vt = &win_progress_vt;
-}
-
-static void win_progress_cleanup(struct progress *p)
-{
- sfree(p->phases);
-}
-
-struct PassphraseProcStruct {
- char **passphrase;
- char *comment;
-};
-
-/*
- * Dialog-box function for the passphrase box.
- */
-static INT_PTR CALLBACK PassphraseProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- static char **passphrase = NULL;
- struct PassphraseProcStruct *p;
-
- switch (msg) {
- case WM_INITDIALOG:
- SetForegroundWindow(hwnd);
- SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
- SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
-
- /*
- * Centre the window.
- */
- { /* centre the window */
- RECT rs, rd;
- HWND hw;
-
- hw = GetDesktopWindow();
- if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
- MoveWindow(hwnd,
- (rs.right + rs.left + rd.left - rd.right) / 2,
- (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
- rd.right - rd.left, rd.bottom - rd.top, true);
- }
-
- p = (struct PassphraseProcStruct *) lParam;
- passphrase = p->passphrase;
- if (p->comment)
- SetDlgItemText(hwnd, 101, p->comment);
- burnstr(*passphrase);
- *passphrase = dupstr("");
- SetDlgItemText(hwnd, 102, *passphrase);
- return 0;
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- if (*passphrase)
- EndDialog(hwnd, 1);
- else
- MessageBeep(0);
- return 0;
- case IDCANCEL:
- EndDialog(hwnd, 0);
- return 0;
- case 102: /* edit box */
- if ((HIWORD(wParam) == EN_CHANGE) && passphrase) {
- burnstr(*passphrase);
- *passphrase = GetDlgItemText_alloc(hwnd, 102);
- }
- return 0;
- }
- return 0;
- case WM_CLOSE:
- EndDialog(hwnd, 0);
- return 0;
- }
- return 0;
-}
-
-static void try_get_dlg_item_uint32(HWND hwnd, int id, uint32_t *out)
-{
- char buf[128];
- if (!GetDlgItemText(hwnd, id, buf, sizeof(buf)))
- return;
-
- if (!*buf)
- return;
-
- char *end;
- unsigned long val = strtoul(buf, &end, 10);
- if (*end)
- return;
-
- if ((val >> 16) >> 16)
- return;
-
- *out = val;
-}
-
-static ppk_save_parameters save_params;
-
-struct PPKParams {
- ppk_save_parameters params;
- uint32_t time_passes, time_ms;
-};
-
-/*
- * Dialog-box function for the passphrase box.
- */
-static INT_PTR CALLBACK PPKParamsProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- struct PPKParams *pp;
- char *buf;
-
- if (msg == WM_INITDIALOG) {
- pp = (struct PPKParams *)lParam;
- SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pp);
- } else {
- pp = (struct PPKParams *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
- }
-
- switch (msg) {
- case WM_INITDIALOG:
- SetForegroundWindow(hwnd);
- SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
- SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
-
- if (has_help())
- SetWindowLongPtr(hwnd, GWL_EXSTYLE,
- GetWindowLongPtr(hwnd, GWL_EXSTYLE) |
- WS_EX_CONTEXTHELP);
-
- /*
- * Centre the window.
- */
- { /* centre the window */
- RECT rs, rd;
- HWND hw;
-
- hw = GetDesktopWindow();
- if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
- MoveWindow(hwnd,
- (rs.right + rs.left + rd.left - rd.right) / 2,
- (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
- rd.right - rd.left, rd.bottom - rd.top, true);
- }
-
- CheckRadioButton(hwnd, IDC_PPKVER_2, IDC_PPKVER_3,
- IDC_PPKVER_2 + (pp->params.fmt_version - 2));
-
- CheckRadioButton(
- hwnd, IDC_KDF_ARGON2ID, IDC_KDF_ARGON2D,
- (pp->params.argon2_flavour == Argon2id ? IDC_KDF_ARGON2ID :
- pp->params.argon2_flavour == Argon2i ? IDC_KDF_ARGON2I :
- /* pp->params.argon2_flavour == Argon2d ? */ IDC_KDF_ARGON2D));
-
- buf = dupprintf("%"PRIu32, pp->params.argon2_mem);
- SetDlgItemText(hwnd, IDC_ARGON2_MEM, buf);
- sfree(buf);
-
- if (pp->params.argon2_passes_auto) {
- CheckRadioButton(hwnd, IDC_PPK_AUTO_YES, IDC_PPK_AUTO_NO,
- IDC_PPK_AUTO_YES);
- buf = dupprintf("%"PRIu32, pp->time_ms);
- SetDlgItemText(hwnd, IDC_ARGON2_TIME, buf);
- sfree(buf);
- } else {
- CheckRadioButton(hwnd, IDC_PPK_AUTO_YES, IDC_PPK_AUTO_NO,
- IDC_PPK_AUTO_NO);
- buf = dupprintf("%"PRIu32, pp->time_passes);
- SetDlgItemText(hwnd, IDC_ARGON2_TIME, buf);
- sfree(buf);
- }
-
- buf = dupprintf("%"PRIu32, pp->params.argon2_parallelism);
- SetDlgItemText(hwnd, IDC_ARGON2_PARALLEL, buf);
- sfree(buf);
-
- return 0;
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- EndDialog(hwnd, 1);
- return 0;
- case IDCANCEL:
- EndDialog(hwnd, 0);
- return 0;
- case IDC_PPKVER_2:
- pp->params.fmt_version = 2;
- return 0;
- case IDC_PPKVER_3:
- pp->params.fmt_version = 3;
- return 0;
- case IDC_KDF_ARGON2ID:
- pp->params.argon2_flavour = Argon2id;
- return 0;
- case IDC_KDF_ARGON2I:
- pp->params.argon2_flavour = Argon2i;
- return 0;
- case IDC_KDF_ARGON2D:
- pp->params.argon2_flavour = Argon2d;
- return 0;
- case IDC_ARGON2_MEM:
- try_get_dlg_item_uint32(hwnd, IDC_ARGON2_MEM,
- &pp->params.argon2_mem);
- return 0;
- case IDC_PPK_AUTO_YES:
- pp->params.argon2_passes_auto = true;
- buf = dupprintf("%"PRIu32, pp->time_ms);
- SetDlgItemText(hwnd, IDC_ARGON2_TIME, buf);
- sfree(buf);
- return 0;
- case IDC_PPK_AUTO_NO:
- pp->params.argon2_passes_auto = false;
- buf = dupprintf("%"PRIu32, pp->time_passes);
- SetDlgItemText(hwnd, IDC_ARGON2_TIME, buf);
- sfree(buf);
- return 0;
- case IDC_ARGON2_TIME:
- try_get_dlg_item_uint32(hwnd, IDC_ARGON2_TIME,
- pp->params.argon2_passes_auto ?
- &pp->time_ms : &pp->time_passes);
- return 0;
- case IDC_ARGON2_PARALLEL:
- try_get_dlg_item_uint32(hwnd, IDC_ARGON2_PARALLEL,
- &pp->params.argon2_parallelism);
- return 0;
- }
- return 0;
- case WM_HELP: {
- int id = ((LPHELPINFO)lParam)->iCtrlId;
- const char *topic = NULL;
- switch (id) {
- case IDC_PPKVER_STATIC:
- case IDC_PPKVER_2:
- case IDC_PPKVER_3:
- topic = WINHELP_CTX_puttygen_ppkver; break;
- case IDC_KDF_STATIC:
- case IDC_KDF_ARGON2ID:
- case IDC_KDF_ARGON2I:
- case IDC_KDF_ARGON2D:
- case IDC_ARGON2_MEM_STATIC:
- case IDC_ARGON2_MEM:
- case IDC_ARGON2_MEM_STATIC2:
- case IDC_ARGON2_TIME_STATIC:
- case IDC_ARGON2_TIME:
- case IDC_PPK_AUTO_YES:
- case IDC_PPK_AUTO_NO:
- case IDC_ARGON2_PARALLEL_STATIC:
- case IDC_ARGON2_PARALLEL:
- topic = WINHELP_CTX_puttygen_kdfparam; break;
- }
- if (topic) {
- launch_help(hwnd, topic);
- } else {
- MessageBeep(0);
- }
- break;
- }
- case WM_CLOSE:
- EndDialog(hwnd, 0);
- return 0;
- }
- return 0;
-}
-
-/*
- * Prompt for a key file. Assumes the filename buffer is of size
- * FILENAME_MAX.
- */
-static bool prompt_keyfile(HWND hwnd, char *dlgtitle,
- char *filename, bool save, bool ppk)
-{
- OPENFILENAME of;
- memset(&of, 0, sizeof(of));
- of.hwndOwner = hwnd;
- if (ppk) {
- of.lpstrFilter = "PuTTY Private Key Files (*.ppk)\0*.ppk\0"
- "All Files (*.*)\0*\0\0\0";
- of.lpstrDefExt = ".ppk";
- } else {
- of.lpstrFilter = "All Files (*.*)\0*\0\0\0";
- }
- of.lpstrCustomFilter = NULL;
- of.nFilterIndex = 1;
- of.lpstrFile = filename;
- *filename = '\0';
- of.nMaxFile = FILENAME_MAX;
- of.lpstrFileTitle = NULL;
- of.lpstrTitle = dlgtitle;
- of.Flags = 0;
- return request_file(NULL, &of, false, save);
-}
-
-/*
- * Dialog-box function for the Licence box.
- */
-static INT_PTR CALLBACK LicenceProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- switch (msg) {
- case WM_INITDIALOG: {
- /*
- * Centre the window.
- */
- RECT rs, rd;
- HWND hw;
-
- hw = GetDesktopWindow();
- if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
- MoveWindow(hwnd,
- (rs.right + rs.left + rd.left - rd.right) / 2,
- (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
- rd.right - rd.left, rd.bottom - rd.top, true);
-
- SetDlgItemText(hwnd, 1000, LICENCE_TEXT("\r\n\r\n"));
- return 1;
- }
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- case IDCANCEL:
- EndDialog(hwnd, 1);
- return 0;
- }
- return 0;
- case WM_CLOSE:
- EndDialog(hwnd, 1);
- return 0;
- }
- return 0;
-}
-
-/*
- * Dialog-box function for the About box.
- */
-static INT_PTR CALLBACK AboutProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- switch (msg) {
- case WM_INITDIALOG:
- /*
- * Centre the window.
- */
- { /* centre the window */
- RECT rs, rd;
- HWND hw;
-
- hw = GetDesktopWindow();
- if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
- MoveWindow(hwnd,
- (rs.right + rs.left + rd.left - rd.right) / 2,
- (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
- rd.right - rd.left, rd.bottom - rd.top, true);
- }
-
- {
- char *buildinfo_text = buildinfo("\r\n");
- char *text = dupprintf
- ("PuTTYgen\r\n\r\n%s\r\n\r\n%s\r\n\r\n%s",
- ver, buildinfo_text,
- "\251 " SHORT_COPYRIGHT_DETAILS ". All rights reserved.");
- sfree(buildinfo_text);
- SetDlgItemText(hwnd, 1000, text);
- MakeDlgItemBorderless(hwnd, 1000);
- sfree(text);
- }
- return 1;
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- case IDCANCEL:
- EndDialog(hwnd, 1);
- return 0;
- case 101:
- EnableWindow(hwnd, 0);
- DialogBox(hinst, MAKEINTRESOURCE(214), hwnd, LicenceProc);
- EnableWindow(hwnd, 1);
- SetActiveWindow(hwnd);
- return 0;
- case 102:
- /* Load web browser */
- ShellExecute(hwnd, "open",
- "https://www.chiark.greenend.org.uk/~sgtatham/putty/",
- 0, 0, SW_SHOWDEFAULT);
- return 0;
- }
- return 0;
- case WM_CLOSE:
- EndDialog(hwnd, 1);
- return 0;
- }
- return 0;
-}
-
-typedef enum {RSA, DSA, ECDSA, EDDSA} keytype;
-
-/*
- * Thread to generate a key.
- */
-struct rsa_key_thread_params {
- HWND progressbar; /* notify this with progress */
- HWND dialog; /* notify this on completion */
- int key_bits; /* bits in key modulus (RSA, DSA) */
- int curve_bits; /* bits in elliptic curve (ECDSA) */
- keytype keytype;
- const PrimeGenerationPolicy *primepolicy;
- bool rsa_strong;
- union {
- RSAKey *key;
- struct dss_key *dsskey;
- struct ecdsa_key *eckey;
- struct eddsa_key *edkey;
- };
-};
-static DWORD WINAPI generate_key_thread(void *param)
-{
- struct rsa_key_thread_params *params =
- (struct rsa_key_thread_params *) param;
- struct progress prog;
- prog.progbar = params->progressbar;
-
- win_progress_initialise(&prog);
-
- PrimeGenerationContext *pgc = primegen_new_context(params->primepolicy);
-
- if (params->keytype == DSA)
- dsa_generate(params->dsskey, params->key_bits, pgc, &prog.rec);
- else if (params->keytype == ECDSA)
- ecdsa_generate(params->eckey, params->curve_bits);
- else if (params->keytype == EDDSA)
- eddsa_generate(params->edkey, params->curve_bits);
- else
- rsa_generate(params->key, params->key_bits, params->rsa_strong,
- pgc, &prog.rec);
-
- primegen_free_context(pgc);
-
- PostMessage(params->dialog, WM_DONEKEY, 0, 0);
-
- win_progress_cleanup(&prog);
-
- sfree(params);
- return 0;
-}
-
-struct MainDlgState {
- bool collecting_entropy;
- bool generation_thread_exists;
- bool key_exists;
- int entropy_got, entropy_required, entropy_size;
- int key_bits, curve_bits;
- bool ssh2;
- keytype keytype;
- const PrimeGenerationPolicy *primepolicy;
- bool rsa_strong;
- FingerprintType fptype;
- char **commentptr; /* points to key.comment or ssh2key.comment */
- ssh2_userkey ssh2key;
- unsigned *entropy;
- union {
- RSAKey key;
- struct dss_key dsskey;
- struct ecdsa_key eckey;
- struct eddsa_key edkey;
- };
- HMENU filemenu, keymenu, cvtmenu;
-};
-
-static void hidemany(HWND hwnd, const int *ids, bool hideit)
-{
- while (*ids) {
- ShowWindow(GetDlgItem(hwnd, *ids++), (hideit ? SW_HIDE : SW_SHOW));
- }
-}
-
-static void setupbigedit1(HWND hwnd, int id, int idstatic, RSAKey *key)
-{
- char *buffer = ssh1_pubkey_str(key);
- SetDlgItemText(hwnd, id, buffer);
- SetDlgItemText(hwnd, idstatic,
- "&Public key for pasting into authorized_keys file:");
- sfree(buffer);
-}
-
-static void setupbigedit2(HWND hwnd, int id, int idstatic,
- ssh2_userkey *key)
-{
- char *buffer = ssh2_pubkey_openssh_str(key);
- SetDlgItemText(hwnd, id, buffer);
- SetDlgItemText(hwnd, idstatic, "&Public key for pasting into "
- "OpenSSH authorized_keys file:");
- sfree(buffer);
-}
-
-/*
- * Warn about the obsolescent key file format.
- */
-void old_keyfile_warning(void)
-{
- static const char mbtitle[] = "PuTTY Key File Warning";
- static const char message[] =
- "You are loading an SSH-2 private key which has an\n"
- "old version of the file format. This means your key\n"
- "file is not fully tamperproof. Future versions of\n"
- "PuTTY may stop supporting this private key format,\n"
- "so we recommend you convert your key to the new\n"
- "format.\n"
- "\n"
- "Once the key is loaded into PuTTYgen, you can perform\n"
- "this conversion simply by saving it again.";
-
- MessageBox(NULL, message, mbtitle, MB_OK);
-}
-
-enum {
- controlidstart = 100,
- IDC_QUIT,
- IDC_TITLE,
- IDC_BOX_KEY,
- IDC_NOKEY,
- IDC_GENERATING,
- IDC_PROGRESS,
- IDC_PKSTATIC, IDC_KEYDISPLAY,
- IDC_FPSTATIC, IDC_FINGERPRINT,
- IDC_COMMENTSTATIC, IDC_COMMENTEDIT,
- IDC_PASSPHRASE1STATIC, IDC_PASSPHRASE1EDIT,
- IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT,
- IDC_BOX_ACTIONS,
- IDC_GENSTATIC, IDC_GENERATE,
- IDC_LOADSTATIC, IDC_LOAD,
- IDC_SAVESTATIC, IDC_SAVE, IDC_SAVEPUB,
- IDC_BOX_PARAMS,
- IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA, IDC_KEYSSH2DSA,
- IDC_KEYSSH2ECDSA, IDC_KEYSSH2EDDSA,
- IDC_PRIMEGEN_PROB, IDC_PRIMEGEN_MAURER_SIMPLE, IDC_PRIMEGEN_MAURER_COMPLEX,
- IDC_RSA_STRONG,
- IDC_FPTYPE_SHA256, IDC_FPTYPE_MD5,
- IDC_PPK_PARAMS,
- IDC_BITSSTATIC, IDC_BITS,
- IDC_ECCURVESTATIC, IDC_ECCURVE,
- IDC_EDCURVESTATIC, IDC_EDCURVE,
- IDC_NOTHINGSTATIC,
- IDC_ABOUT,
- IDC_GIVEHELP,
- IDC_IMPORT,
- IDC_EXPORT_OPENSSH_AUTO, IDC_EXPORT_OPENSSH_NEW,
- IDC_EXPORT_SSHCOM
-};
-
-static const int nokey_ids[] = { IDC_NOKEY, 0 };
-static const int generating_ids[] = { IDC_GENERATING, IDC_PROGRESS, 0 };
-static const int gotkey_ids[] = {
- IDC_PKSTATIC, IDC_KEYDISPLAY,
- IDC_FPSTATIC, IDC_FINGERPRINT,
- IDC_COMMENTSTATIC, IDC_COMMENTEDIT,
- IDC_PASSPHRASE1STATIC, IDC_PASSPHRASE1EDIT,
- IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT, 0
-};
-
-/*
- * Small UI helper function to switch the state of the main dialog
- * by enabling and disabling controls and menu items.
- */
-void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
-{
- int type;
-
- switch (status) {
- case 0: /* no key */
- hidemany(hwnd, nokey_ids, false);
- hidemany(hwnd, generating_ids, true);
- hidemany(hwnd, gotkey_ids, true);
- EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1);
- EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1);
- EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0);
- EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0);
- EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1);
- EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
- EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1);
- EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 1);
- EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2EDDSA), 1);
- EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
- EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->filemenu, IDC_SAVEPUB, MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_GENERATE, MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA, MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
- MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_KEYSSH2EDDSA,
- MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_AUTO,
- MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_NEW,
- MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->cvtmenu, IDC_EXPORT_SSHCOM,
- MF_GRAYED|MF_BYCOMMAND);
- break;
- case 1: /* generating key */
- hidemany(hwnd, nokey_ids, true);
- hidemany(hwnd, generating_ids, false);
- hidemany(hwnd, gotkey_ids, true);
- EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 0);
- EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 0);
- EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0);
- EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0);
- EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 0);
- EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 0);
- EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 0);
- EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 0);
- EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2EDDSA), 0);
- EnableWindow(GetDlgItem(hwnd, IDC_BITS), 0);
- EnableMenuItem(state->filemenu, IDC_LOAD, MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->filemenu, IDC_SAVEPUB, MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_GENERATE, MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA, MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
- MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_KEYSSH2EDDSA,
- MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_AUTO,
- MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_NEW,
- MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->cvtmenu, IDC_EXPORT_SSHCOM,
- MF_GRAYED|MF_BYCOMMAND);
- break;
- case 2:
- hidemany(hwnd, nokey_ids, true);
- hidemany(hwnd, generating_ids, true);
- hidemany(hwnd, gotkey_ids, false);
- EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1);
- EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1);
- EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 1);
- EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 1);
- EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1);
- EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
- EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1);
- EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 1);
- EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2EDDSA), 1);
- EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
- EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->filemenu, IDC_SAVE, MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->filemenu, IDC_SAVEPUB, MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_GENERATE, MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA,MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA,MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
- MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->keymenu, IDC_KEYSSH2EDDSA,
- MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND);
- /*
- * Enable export menu items if and only if the key type
- * supports this kind of export.
- */
- type = state->ssh2 ? SSH_KEYTYPE_SSH2 : SSH_KEYTYPE_SSH1;
-#define do_export_menuitem(x,y) \
- EnableMenuItem(state->cvtmenu, x, MF_BYCOMMAND | \
- (import_target_type(y)==type?MF_ENABLED:MF_GRAYED))
- do_export_menuitem(IDC_EXPORT_OPENSSH_AUTO, SSH_KEYTYPE_OPENSSH_AUTO);
- do_export_menuitem(IDC_EXPORT_OPENSSH_NEW, SSH_KEYTYPE_OPENSSH_NEW);
- do_export_menuitem(IDC_EXPORT_SSHCOM, SSH_KEYTYPE_SSHCOM);
-#undef do_export_menuitem
- break;
- }
-}
-
-/*
- * Helper functions to set the key type, taking care of keeping the
- * menu and radio button selections in sync and also showing/hiding
- * the appropriate size/curve control for the current key type.
- */
-void ui_update_key_type_ctrls(HWND hwnd)
-{
- enum { BITS, ECCURVE, EDCURVE, NOTHING } which;
- static const int bits_ids[] = {
- IDC_BITSSTATIC, IDC_BITS, 0
- };
- static const int eccurve_ids[] = {
- IDC_ECCURVESTATIC, IDC_ECCURVE, 0
- };
- static const int edcurve_ids[] = {
- IDC_EDCURVESTATIC, IDC_EDCURVE, 0
- };
- static const int nothing_ids[] = {
- IDC_NOTHINGSTATIC, 0
- };
-
- if (IsDlgButtonChecked(hwnd, IDC_KEYSSH1) ||
- IsDlgButtonChecked(hwnd, IDC_KEYSSH2RSA) ||
- IsDlgButtonChecked(hwnd, IDC_KEYSSH2DSA)) {
- which = BITS;
- } else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2ECDSA)) {
- which = ECCURVE;
- } else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2EDDSA)) {
- which = EDCURVE;
- } else {
- /* Currently not used since Ed25519 stopped being the only
- * thing in its class, but I'll keep it here in case it comes
- * in useful again */
- which = NOTHING;
- }
-
- hidemany(hwnd, bits_ids, which != BITS);
- hidemany(hwnd, eccurve_ids, which != ECCURVE);
- hidemany(hwnd, edcurve_ids, which != EDCURVE);
- hidemany(hwnd, nothing_ids, which != NOTHING);
-}
-void ui_set_key_type(HWND hwnd, struct MainDlgState *state, int button)
-{
- CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2EDDSA, button);
- CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, IDC_KEYSSH2EDDSA,
- button, MF_BYCOMMAND);
- ui_update_key_type_ctrls(hwnd);
-}
-void ui_set_primepolicy(HWND hwnd, struct MainDlgState *state, int option)
-{
- CheckMenuRadioItem(state->keymenu, IDC_PRIMEGEN_PROB,
- IDC_PRIMEGEN_MAURER_COMPLEX, option, MF_BYCOMMAND);
- switch (option) {
- case IDC_PRIMEGEN_PROB:
- state->primepolicy = &primegen_probabilistic;
- break;
- case IDC_PRIMEGEN_MAURER_SIMPLE:
- state->primepolicy = &primegen_provable_maurer_simple;
- break;
- case IDC_PRIMEGEN_MAURER_COMPLEX:
- state->primepolicy = &primegen_provable_maurer_complex;
- break;
- }
-}
-void ui_set_rsa_strong(HWND hwnd, struct MainDlgState *state, bool enable)
-{
- state->rsa_strong = enable;
- CheckMenuItem(state->keymenu, IDC_RSA_STRONG,
- (enable ? MF_CHECKED : 0) | MF_BYCOMMAND);
-}
-static FingerprintType idc_to_fptype(int option)
-{
- switch (option) {
- case IDC_FPTYPE_SHA256:
- return SSH_FPTYPE_SHA256;
- case IDC_FPTYPE_MD5:
- return SSH_FPTYPE_MD5;
- default:
- unreachable("bad control id in idc_to_fptype");
- }
-}
-static int fptype_to_idc(FingerprintType fptype)
-{
- switch (fptype) {
- case SSH_FPTYPE_SHA256:
- return IDC_FPTYPE_SHA256;
- case SSH_FPTYPE_MD5:
- return IDC_FPTYPE_MD5;
- default:
- unreachable("bad fptype in fptype_to_idc");
- }
-}
-void ui_set_fptype(HWND hwnd, struct MainDlgState *state, int option)
-{
- CheckMenuRadioItem(state->keymenu, IDC_FPTYPE_SHA256,
- IDC_FPTYPE_MD5, option, MF_BYCOMMAND);
-
- state->fptype = idc_to_fptype(option);
-
- if (state->key_exists && state->ssh2) {
- char *fp = ssh2_fingerprint(state->ssh2key.key, state->fptype);
- SetDlgItemText(hwnd, IDC_FINGERPRINT, fp);
- sfree(fp);
- }
-}
-
-void load_key_file(HWND hwnd, struct MainDlgState *state,
- Filename *filename, bool was_import_cmd)
-{
- char *passphrase;
- bool needs_pass;
- int type, realtype;
- int ret;
- const char *errmsg = NULL;
- char *comment;
- RSAKey newkey1;
- ssh2_userkey *newkey2 = NULL;
-
- type = realtype = key_type(filename);
- if (type != SSH_KEYTYPE_SSH1 &&
- type != SSH_KEYTYPE_SSH2 &&
- !import_possible(type)) {
- char *msg = dupprintf("Couldn't load private key (%s)",
- key_type_to_str(type));
- message_box(hwnd, msg, "PuTTYgen Error", MB_OK | MB_ICONERROR,
- HELPCTXID(errors_cantloadkey));
- sfree(msg);
- return;
- }
-
- if (type != SSH_KEYTYPE_SSH1 &&
- type != SSH_KEYTYPE_SSH2) {
- realtype = type;
- type = import_target_type(type);
- }
-
- comment = NULL;
- passphrase = NULL;
- if (realtype == SSH_KEYTYPE_SSH1)
- needs_pass = rsa1_encrypted_f(filename, &comment);
- else if (realtype == SSH_KEYTYPE_SSH2)
- needs_pass = ppk_encrypted_f(filename, &comment);
- else
- needs_pass = import_encrypted(filename, realtype, &comment);
- do {
- burnstr(passphrase);
- passphrase = NULL;
-
- if (needs_pass) {
- int dlgret;
- struct PassphraseProcStruct pps;
- pps.passphrase = &passphrase;
- pps.comment = comment;
- dlgret = DialogBoxParam(hinst,
- MAKEINTRESOURCE(210),
- NULL, PassphraseProc,
- (LPARAM) &pps);
- if (!dlgret) {
- ret = -2;
- break;
- }
- assert(passphrase != NULL);
- } else
- passphrase = dupstr("");
- if (type == SSH_KEYTYPE_SSH1) {
- if (realtype == type)
- ret = rsa1_load_f(filename, &newkey1, passphrase, &errmsg);
- else
- ret = import_ssh1(filename, realtype, &newkey1,
- passphrase, &errmsg);
- } else {
- if (realtype == type)
- newkey2 = ppk_load_f(filename, passphrase, &errmsg);
- else
- newkey2 = import_ssh2(filename, realtype, passphrase, &errmsg);
- if (newkey2 == SSH2_WRONG_PASSPHRASE)
- ret = -1;
- else if (!newkey2)
- ret = 0;
- else
- ret = 1;
- }
- } while (ret == -1);
- if (comment)
- sfree(comment);
- if (ret == 0) {
- char *msg = dupprintf("Couldn't load private key (%s)", errmsg);
- message_box(hwnd, msg, "PuTTYgen Error", MB_OK | MB_ICONERROR,
- HELPCTXID(errors_cantloadkey));
- sfree(msg);
- } else if (ret == 1) {
- /*
- * Now update the key controls with all the
- * key data.
- */
- {
- 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
- * using the Load command, let them know.
- * If they've used the Import command, be
- * silent.
- */
- if (realtype != type && !was_import_cmd) {
- char msg[512];
- sprintf(msg, "Successfully imported foreign key\n"
- "(%s).\n"
- "To use this key with PuTTY, you need to\n"
- "use the \"Save private key\" command to\n"
- "save it in PuTTY's own format.",
- key_type_to_str(realtype));
- MessageBox(NULL, msg, "PuTTYgen Notice",
- MB_OK | MB_ICONINFORMATION);
- }
- }
- burnstr(passphrase);
-}
-
-static void start_generating_key(HWND hwnd, struct MainDlgState *state)
-{
- static const char generating_msg[] =
- "Please wait while a key is generated...";
-
- struct rsa_key_thread_params *params;
- DWORD threadid;
-
- SetDlgItemText(hwnd, IDC_GENERATING, generating_msg);
- SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
- MAKELPARAM(0, PROGRESSRANGE));
- SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0);
-
- params = snew(struct rsa_key_thread_params);
- params->progressbar = GetDlgItem(hwnd, IDC_PROGRESS);
- params->dialog = hwnd;
- params->key_bits = state->key_bits;
- params->curve_bits = state->curve_bits;
- params->keytype = state->keytype;
- params->primepolicy = state->primepolicy;
- params->rsa_strong = state->rsa_strong;
- params->key = &state->key;
- params->dsskey = &state->dsskey;
-
- HANDLE hThread = CreateThread(NULL, 0, generate_key_thread,
- params, 0, &threadid);
- if (!hThread) {
- MessageBox(hwnd, "Out of thread resources",
- "Key generation error",
- MB_OK | MB_ICONERROR);
- sfree(params);
- } else {
- CloseHandle(hThread); /* we don't need the thread handle */
- state->generation_thread_exists = true;
- }
-}
-
-/*
- * Dialog-box function for the main PuTTYgen dialog box.
- */
-static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- static const char entropy_msg[] =
- "Please generate some randomness by moving the mouse over the blank area.";
- struct MainDlgState *state;
-
- switch (msg) {
- case WM_INITDIALOG:
- if (has_help())
- SetWindowLongPtr(hwnd, GWL_EXSTYLE,
- GetWindowLongPtr(hwnd, GWL_EXSTYLE) |
- WS_EX_CONTEXTHELP);
- else {
- /*
- * If we add a Help button, this is where we destroy it
- * if the help file isn't present.
- */
- }
- SendMessage(hwnd, WM_SETICON, (WPARAM) ICON_BIG,
- (LPARAM) LoadIcon(hinst, MAKEINTRESOURCE(200)));
-
- state = snew(struct MainDlgState);
- state->generation_thread_exists = false;
- state->collecting_entropy = false;
- state->entropy = NULL;
- state->key_exists = false;
- SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) state);
- {
- HMENU menu, menu1;
-
- menu = CreateMenu();
-
- menu1 = CreateMenu();
- AppendMenu(menu1, MF_ENABLED, IDC_LOAD, "&Load private key");
- AppendMenu(menu1, MF_ENABLED, IDC_SAVEPUB, "Save p&ublic key");
- AppendMenu(menu1, MF_ENABLED, IDC_SAVE, "&Save private key");
- AppendMenu(menu1, MF_SEPARATOR, 0, 0);
- AppendMenu(menu1, MF_ENABLED, IDC_QUIT, "E&xit");
- AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT_PTR) menu1, "&File");
- state->filemenu = menu1;
-
- menu1 = CreateMenu();
- AppendMenu(menu1, MF_ENABLED, IDC_GENERATE, "&Generate key pair");
- AppendMenu(menu1, MF_SEPARATOR, 0, 0);
- AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH1, "SSH-&1 key (RSA)");
- AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2RSA, "SSH-2 &RSA key");
- AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2DSA, "SSH-2 &DSA key");
- AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2ECDSA, "SSH-2 &ECDSA key");
- AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2EDDSA, "SSH-2 EdD&SA key");
- AppendMenu(menu1, MF_SEPARATOR, 0, 0);
- AppendMenu(menu1, MF_ENABLED, IDC_PRIMEGEN_PROB,
- "Use probable primes (fast)");
- AppendMenu(menu1, MF_ENABLED, IDC_PRIMEGEN_MAURER_SIMPLE,
- "Use proven primes (slower)");
- AppendMenu(menu1, MF_ENABLED, IDC_PRIMEGEN_MAURER_COMPLEX,
- "Use proven primes with even distribution (slowest)");
- AppendMenu(menu1, MF_SEPARATOR, 0, 0);
- AppendMenu(menu1, MF_ENABLED, IDC_RSA_STRONG,
- "Use \"strong\" primes as RSA key factors");
- AppendMenu(menu1, MF_SEPARATOR, 0, 0);
- AppendMenu(menu1, MF_ENABLED, IDC_PPK_PARAMS,
- "Parameters for saving key files...");
- AppendMenu(menu1, MF_SEPARATOR, 0, 0);
- AppendMenu(menu1, MF_ENABLED, IDC_FPTYPE_SHA256,
- "Show fingerprint as SHA256");
- AppendMenu(menu1, MF_ENABLED, IDC_FPTYPE_MD5,
- "Show fingerprint as MD5");
- AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT_PTR) menu1, "&Key");
- state->keymenu = menu1;
-
- menu1 = CreateMenu();
- AppendMenu(menu1, MF_ENABLED, IDC_IMPORT, "&Import key");
- AppendMenu(menu1, MF_SEPARATOR, 0, 0);
- AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH_AUTO,
- "Export &OpenSSH key");
- AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH_NEW,
- "Export &OpenSSH key (force new file format)");
- AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_SSHCOM,
- "Export &ssh.com key");
- AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT_PTR) menu1,
- "Con&versions");
- state->cvtmenu = menu1;
-
- menu1 = CreateMenu();
- AppendMenu(menu1, MF_ENABLED, IDC_ABOUT, "&About");
- if (has_help())
- AppendMenu(menu1, MF_ENABLED, IDC_GIVEHELP, "&Help");
- AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT_PTR) menu1, "&Help");
-
- SetMenu(hwnd, menu);
- }
-
- /*
- * Centre the window.
- */
- { /* centre the window */
- RECT rs, rd;
- HWND hw;
-
- hw = GetDesktopWindow();
- if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
- MoveWindow(hwnd,
- (rs.right + rs.left + rd.left - rd.right) / 2,
- (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
- rd.right - rd.left, rd.bottom - rd.top, true);
- }
-
- {
- struct ctlpos cp, cp2;
- int ymax;
-
- /* Accelerators used: acglops1rbvde */
-
- ctlposinit(&cp, hwnd, 4, 4, 4);
- beginbox(&cp, "Key", IDC_BOX_KEY);
- cp2 = cp;
- statictext(&cp2, "No key.", 1, IDC_NOKEY);
- cp2 = cp;
- statictext(&cp2, "", 1, IDC_GENERATING);
- progressbar(&cp2, IDC_PROGRESS);
- bigeditctrl(&cp,
- "&Public key for pasting into authorized_keys file:",
- IDC_PKSTATIC, IDC_KEYDISPLAY, 5);
- SendDlgItemMessage(hwnd, IDC_KEYDISPLAY, EM_SETREADONLY, 1, 0);
- staticedit(&cp, "Key f&ingerprint:", IDC_FPSTATIC,
- IDC_FINGERPRINT, 82);
- SendDlgItemMessage(hwnd, IDC_FINGERPRINT, EM_SETREADONLY, 1,
- 0);
- staticedit(&cp, "Key &comment:", IDC_COMMENTSTATIC,
- IDC_COMMENTEDIT, 82);
- staticpassedit(&cp, "Key p&assphrase:", IDC_PASSPHRASE1STATIC,
- IDC_PASSPHRASE1EDIT, 82);
- staticpassedit(&cp, "C&onfirm passphrase:",
- IDC_PASSPHRASE2STATIC, IDC_PASSPHRASE2EDIT, 82);
- endbox(&cp);
- beginbox(&cp, "Actions", IDC_BOX_ACTIONS);
- staticbtn(&cp, "Generate a public/private key pair",
- IDC_GENSTATIC, "&Generate", IDC_GENERATE);
- staticbtn(&cp, "Load an existing private key file",
- IDC_LOADSTATIC, "&Load", IDC_LOAD);
- static2btn(&cp, "Save the generated key", IDC_SAVESTATIC,
- "Save p&ublic key", IDC_SAVEPUB,
- "&Save private key", IDC_SAVE);
- endbox(&cp);
- beginbox(&cp, "Parameters", IDC_BOX_PARAMS);
- radioline(&cp, "Type of key to generate:", IDC_TYPESTATIC, 5,
- "&RSA", IDC_KEYSSH2RSA,
- "&DSA", IDC_KEYSSH2DSA,
- "&ECDSA", IDC_KEYSSH2ECDSA,
- "EdD&SA", IDC_KEYSSH2EDDSA,
- "SSH-&1 (RSA)", IDC_KEYSSH1,
- NULL);
- cp2 = cp;
- staticedit(&cp2, "Number of &bits in a generated key:",
- IDC_BITSSTATIC, IDC_BITS, 20);
- ymax = cp2.ypos;
- cp2 = cp;
- staticddl(&cp2, "Cur&ve to use for generating this key:",
- IDC_ECCURVESTATIC, IDC_ECCURVE, 30);
- SendDlgItemMessage(hwnd, IDC_ECCURVE, CB_RESETCONTENT, 0, 0);
- {
- int i, bits;
- const struct ec_curve *curve;
- const ssh_keyalg *alg;
-
- for (i = 0; i < n_ec_nist_curve_lengths; i++) {
- bits = ec_nist_curve_lengths[i];
- ec_nist_alg_and_curve_by_bits(bits, &curve, &alg);
- SendDlgItemMessage(hwnd, IDC_ECCURVE, CB_ADDSTRING, 0,
- (LPARAM)curve->textname);
- }
- }
- ymax = ymax > cp2.ypos ? ymax : cp2.ypos;
- cp2 = cp;
- staticddl(&cp2, "Cur&ve to use for generating this key:",
- IDC_EDCURVESTATIC, IDC_EDCURVE, 30);
- SendDlgItemMessage(hwnd, IDC_EDCURVE, CB_RESETCONTENT, 0, 0);
- {
- int i, bits;
- const struct ec_curve *curve;
- const ssh_keyalg *alg;
-
- for (i = 0; i < n_ec_ed_curve_lengths; i++) {
- bits = ec_ed_curve_lengths[i];
- ec_ed_alg_and_curve_by_bits(bits, &curve, &alg);
- char *desc = dupprintf("%s (%d bits)",
- curve->textname, bits);
- SendDlgItemMessage(hwnd, IDC_EDCURVE, CB_ADDSTRING, 0,
- (LPARAM)desc);
- sfree(desc);
- }
- }
- ymax = ymax > cp2.ypos ? ymax : cp2.ypos;
- cp2 = cp;
- statictext(&cp2, "(nothing to configure for this key type)",
- 1, IDC_NOTHINGSTATIC);
- ymax = ymax > cp2.ypos ? ymax : cp2.ypos;
- cp.ypos = ymax;
- endbox(&cp);
- }
- ui_set_key_type(hwnd, state, IDC_KEYSSH2RSA);
- ui_set_primepolicy(hwnd, state, IDC_PRIMEGEN_PROB);
- ui_set_rsa_strong(hwnd, state, false);
- ui_set_fptype(hwnd, state, fptype_to_idc(SSH_FPTYPE_DEFAULT));
- SetDlgItemInt(hwnd, IDC_BITS, DEFAULT_KEY_BITS, false);
- SendDlgItemMessage(hwnd, IDC_ECCURVE, CB_SETCURSEL,
- DEFAULT_ECCURVE_INDEX, 0);
- SendDlgItemMessage(hwnd, IDC_EDCURVE, CB_SETCURSEL,
- DEFAULT_EDCURVE_INDEX, 0);
-
- /*
- * Initially, hide the progress bar and the key display,
- * and show the no-key display. Also disable the Save
- * buttons, because with no key we obviously can't save
- * anything.
- */
- ui_set_state(hwnd, state, 0);
-
- /*
- * Load a key file if one was provided on the command line.
- */
- if (cmdline_keyfile) {
- Filename *fn = filename_from_str(cmdline_keyfile);
- load_key_file(hwnd, state, fn, false);
- filename_free(fn);
- }
-
- return 1;
- case WM_MOUSEMOVE:
- state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
- if (state->collecting_entropy &&
- state->entropy && state->entropy_got < state->entropy_required) {
- state->entropy[state->entropy_got++] = lParam;
- state->entropy[state->entropy_got++] = GetMessageTime();
- SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS,
- state->entropy_got, 0);
- if (state->entropy_got >= state->entropy_required) {
- /*
- * Seed the entropy pool
- */
- random_reseed(
- make_ptrlen(state->entropy, state->entropy_size));
- smemclr(state->entropy, state->entropy_size);
- sfree(state->entropy);
- state->collecting_entropy = false;
-
- start_generating_key(hwnd, state);
- }
- }
- break;
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDC_KEYSSH1:
- case IDC_KEYSSH2RSA:
- case IDC_KEYSSH2DSA:
- case IDC_KEYSSH2ECDSA:
- case IDC_KEYSSH2EDDSA: {
- state = (struct MainDlgState *)
- GetWindowLongPtr(hwnd, GWLP_USERDATA);
- ui_set_key_type(hwnd, state, LOWORD(wParam));
- break;
- }
- case IDC_PRIMEGEN_PROB:
- case IDC_PRIMEGEN_MAURER_SIMPLE:
- case IDC_PRIMEGEN_MAURER_COMPLEX: {
- state = (struct MainDlgState *)
- GetWindowLongPtr(hwnd, GWLP_USERDATA);
- ui_set_primepolicy(hwnd, state, LOWORD(wParam));
- break;
- }
- case IDC_FPTYPE_SHA256:
- case IDC_FPTYPE_MD5: {
- state = (struct MainDlgState *)
- GetWindowLongPtr(hwnd, GWLP_USERDATA);
- ui_set_fptype(hwnd, state, LOWORD(wParam));
- break;
- }
- case IDC_RSA_STRONG: {
- state = (struct MainDlgState *)
- GetWindowLongPtr(hwnd, GWLP_USERDATA);
- ui_set_rsa_strong(hwnd, state, !state->rsa_strong);
- break;
- }
- case IDC_PPK_PARAMS: {
- struct PPKParams pp[1];
- pp->params = save_params;
- if (pp->params.argon2_passes_auto) {
- pp->time_ms = pp->params.argon2_milliseconds;
- pp->time_passes = 13;
- } else {
- pp->time_ms = 100;
- pp->time_passes = pp->params.argon2_passes;
- }
- int dlgret = DialogBoxParam(hinst, MAKEINTRESOURCE(215),
- NULL, PPKParamsProc, (LPARAM)pp);
- if (dlgret) {
- if (pp->params.argon2_passes_auto) {
- pp->params.argon2_milliseconds = pp->time_ms;
- } else {
- pp->params.argon2_passes = pp->time_passes;
- }
- save_params = pp->params;
- }
- break;
- }
- case IDC_QUIT:
- PostMessage(hwnd, WM_CLOSE, 0, 0);
- break;
- case IDC_COMMENTEDIT:
- if (HIWORD(wParam) == EN_CHANGE) {
- state = (struct MainDlgState *)
- GetWindowLongPtr(hwnd, GWLP_USERDATA);
- if (state->key_exists) {
- HWND editctl = GetDlgItem(hwnd, IDC_COMMENTEDIT);
- int len = GetWindowTextLength(editctl);
- if (*state->commentptr)
- sfree(*state->commentptr);
- *state->commentptr = snewn(len + 1, char);
- GetWindowText(editctl, *state->commentptr, len + 1);
- if (state->ssh2) {
- setupbigedit2(hwnd, IDC_KEYDISPLAY, IDC_PKSTATIC,
- &state->ssh2key);
- } else {
- setupbigedit1(hwnd, IDC_KEYDISPLAY, IDC_PKSTATIC,
- &state->key);
- }
- }
- }
- break;
- case IDC_ABOUT:
- EnableWindow(hwnd, 0);
- DialogBox(hinst, MAKEINTRESOURCE(213), hwnd, AboutProc);
- EnableWindow(hwnd, 1);
- SetActiveWindow(hwnd);
- return 0;
- case IDC_GIVEHELP:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- launch_help(hwnd, WINHELP_CTX_puttygen_general);
- }
- return 0;
- case IDC_GENERATE:
- if (HIWORD(wParam) != BN_CLICKED &&
- HIWORD(wParam) != BN_DOUBLECLICKED)
- break;
- state =
- (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
- if (!state->generation_thread_exists) {
- unsigned raw_entropy_required;
- unsigned char *raw_entropy_buf;
- BOOL ok;
-
- state->key_bits = GetDlgItemInt(hwnd, IDC_BITS, &ok, false);
- if (!ok)
- state->key_bits = DEFAULT_KEY_BITS;
- state->ssh2 = true;
-
- if (IsDlgButtonChecked(hwnd, IDC_KEYSSH1)) {
- state->ssh2 = false;
- state->keytype = RSA;
- } else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2RSA)) {
- state->keytype = RSA;
- } else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2DSA)) {
- state->keytype = DSA;
- } else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2ECDSA)) {
- state->keytype = ECDSA;
- int curveindex = SendDlgItemMessage(hwnd, IDC_ECCURVE,
- CB_GETCURSEL, 0, 0);
- assert(curveindex >= 0);
- assert(curveindex < n_ec_nist_curve_lengths);
- state->curve_bits = ec_nist_curve_lengths[curveindex];
- } else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2EDDSA)) {
- state->keytype = EDDSA;
- int curveindex = SendDlgItemMessage(hwnd, IDC_EDCURVE,
- CB_GETCURSEL, 0, 0);
- assert(curveindex >= 0);
- assert(curveindex < n_ec_ed_curve_lengths);
- state->curve_bits = ec_ed_curve_lengths[curveindex];
- } else {
- /* Somehow, no button was checked */
- break;
- }
-
- if ((state->keytype == RSA || state->keytype == DSA) &&
- state->key_bits < 256) {
- char *message = dupprintf
- ("PuTTYgen will not generate a key smaller than 256"
- " bits.\nKey length reset to default %d. Continue?",
- DEFAULT_KEY_BITS);
- int ret = MessageBox(hwnd, message, "PuTTYgen Warning",
- MB_ICONWARNING | MB_OKCANCEL);
- sfree(message);
- if (ret != IDOK)
- break;
- state->key_bits = DEFAULT_KEY_BITS;
- SetDlgItemInt(hwnd, IDC_BITS, DEFAULT_KEY_BITS, false);
- } else if ((state->keytype == RSA || state->keytype == DSA) &&
- state->key_bits < DEFAULT_KEY_BITS) {
- char *message = dupprintf
- ("Keys shorter than %d bits are not recommended. "
- "Really generate this key?", DEFAULT_KEY_BITS);
- int ret = MessageBox(hwnd, message, "PuTTYgen Warning",
- MB_ICONWARNING | MB_OKCANCEL);
- sfree(message);
- if (ret != IDOK)
- break;
- }
-
- if (state->keytype == RSA || state->keytype == DSA)
- raw_entropy_required = (state->key_bits / 2) * 2;
- else if (state->keytype == ECDSA || state->keytype == EDDSA)
- raw_entropy_required = (state->curve_bits / 2) * 2;
- else
- unreachable("we must have initialised keytype by now");
-
- /* Bound the entropy collection above by the amount of
- * data we can actually fit into the PRNG. Any more
- * than that and it's doing no more good. */
- if (raw_entropy_required > random_seed_bits())
- raw_entropy_required = random_seed_bits();
-
- raw_entropy_buf = snewn(raw_entropy_required, unsigned char);
- if (win_read_random(raw_entropy_buf, raw_entropy_required)) {
- /*
- * If we can get entropy from CryptGenRandom, use
- * it. But CryptGenRandom isn't a kernel-level
- * CPRNG (according to Wikipedia), and papers have
- * been published cryptanalysing it. So we'll
- * still do manual entropy collection; we'll just
- * do it _as well_ as this.
- */
- random_reseed(
- make_ptrlen(raw_entropy_buf, raw_entropy_required));
- }
-
- /*
- * Manual entropy input, by making the user wave the
- * mouse over the window a lot.
- *
- * My brief statistical tests on mouse movements
- * suggest that there are about 2.5 bits of randomness
- * in the x position, 2.5 in the y position, and 1.7
- * in the message time, making 5.7 bits of
- * unpredictability per mouse movement. However, other
- * people have told me it's far less than that, so I'm
- * going to be stupidly cautious and knock that down
- * to a nice round 2. With this method, we require two
- * words per mouse movement, so with 2 bits per mouse
- * movement we expect 2 bits every 2 words, i.e. the
- * number of _words_ of mouse data we want to collect
- * is just the same as the number of _bits_ of entropy
- * we want.
- */
- state->entropy_required = raw_entropy_required;
-
- ui_set_state(hwnd, state, 1);
- SetDlgItemText(hwnd, IDC_GENERATING, entropy_msg);
- state->key_exists = false;
- state->collecting_entropy = true;
-
- state->entropy_got = 0;
- state->entropy_size = (state->entropy_required *
- sizeof(unsigned));
- state->entropy = snewn(state->entropy_required, unsigned);
-
- SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
- MAKELPARAM(0, state->entropy_required));
- SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0);
-
- smemclr(raw_entropy_buf, raw_entropy_required);
- sfree(raw_entropy_buf);
- }
- break;
- case IDC_SAVE:
- case IDC_EXPORT_OPENSSH_AUTO:
- case IDC_EXPORT_OPENSSH_NEW:
- case IDC_EXPORT_SSHCOM:
- if (HIWORD(wParam) != BN_CLICKED)
- break;
- state =
- (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
- if (state->key_exists) {
- char filename[FILENAME_MAX];
- char *passphrase, *passphrase2;
- int type, realtype;
-
- if (state->ssh2)
- realtype = SSH_KEYTYPE_SSH2;
- else
- realtype = SSH_KEYTYPE_SSH1;
-
- if (LOWORD(wParam) == IDC_EXPORT_OPENSSH_AUTO)
- type = SSH_KEYTYPE_OPENSSH_AUTO;
- else if (LOWORD(wParam) == IDC_EXPORT_OPENSSH_NEW)
- type = SSH_KEYTYPE_OPENSSH_NEW;
- else if (LOWORD(wParam) == IDC_EXPORT_SSHCOM)
- type = SSH_KEYTYPE_SSHCOM;
- else
- type = realtype;
-
- if (type != realtype &&
- import_target_type(type) != realtype) {
- char msg[256];
- sprintf(msg, "Cannot export an SSH-%d key in an SSH-%d"
- " format", (state->ssh2 ? 2 : 1),
- (state->ssh2 ? 1 : 2));
- MessageBox(hwnd, msg,
- "PuTTYgen Error", MB_OK | MB_ICONERROR);
- break;
- }
-
- passphrase = GetDlgItemText_alloc(hwnd, IDC_PASSPHRASE1EDIT);
- passphrase2 = GetDlgItemText_alloc(hwnd, IDC_PASSPHRASE2EDIT);
- if (strcmp(passphrase, passphrase2)) {
- MessageBox(hwnd,
- "The two passphrases given do not match.",
- "PuTTYgen Error", MB_OK | MB_ICONERROR);
- burnstr(passphrase);
- burnstr(passphrase2);
- break;
- }
- burnstr(passphrase2);
- if (!*passphrase) {
- int ret;
- ret = MessageBox(hwnd,
- "Are you sure you want to save this key\n"
- "without a passphrase to protect it?",
- "PuTTYgen Warning",
- MB_YESNO | MB_ICONWARNING);
- if (ret != IDYES) {
- burnstr(passphrase);
- break;
- }
- }
- if (prompt_keyfile(hwnd, "Save private key as:",
- filename, true, (type == realtype))) {
- int ret;
- FILE *fp = fopen(filename, "r");
- if (fp) {
- char *buffer;
- fclose(fp);
- buffer = dupprintf("Overwrite existing file\n%s?",
- filename);
- ret = MessageBox(hwnd, buffer, "PuTTYgen Warning",
- MB_YESNO | MB_ICONWARNING);
- sfree(buffer);
- if (ret != IDYES) {
- burnstr(passphrase);
- break;
- }
- }
-
- if (state->ssh2) {
- Filename *fn = filename_from_str(filename);
- if (type != realtype)
- ret = export_ssh2(fn, type, &state->ssh2key,
- *passphrase ? passphrase : NULL);
- else
- ret = ppk_save_f(fn, &state->ssh2key,
- *passphrase ? passphrase : NULL,
- &save_params);
- filename_free(fn);
- } else {
- Filename *fn = filename_from_str(filename);
- if (type != realtype)
- ret = export_ssh1(fn, type, &state->key,
- *passphrase ? passphrase : NULL);
- else
- ret = rsa1_save_f(fn, &state->key,
- *passphrase ? passphrase : NULL);
- filename_free(fn);
- }
- if (ret <= 0) {
- MessageBox(hwnd, "Unable to save key file",
- "PuTTYgen Error", MB_OK | MB_ICONERROR);
- }
- }
- burnstr(passphrase);
- }
- break;
- case IDC_SAVEPUB:
- if (HIWORD(wParam) != BN_CLICKED)
- break;
- state =
- (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
- if (state->key_exists) {
- char filename[FILENAME_MAX];
- if (prompt_keyfile(hwnd, "Save public key as:",
- filename, true, false)) {
- int ret;
- FILE *fp = fopen(filename, "r");
- if (fp) {
- char *buffer;
- fclose(fp);
- buffer = dupprintf("Overwrite existing file\n%s?",
- filename);
- ret = MessageBox(hwnd, buffer, "PuTTYgen Warning",
- MB_YESNO | MB_ICONWARNING);
- sfree(buffer);
- if (ret != IDYES)
- break;
- }
- fp = fopen(filename, "w");
- if (!fp) {
- MessageBox(hwnd, "Unable to open key file",
- "PuTTYgen Error", MB_OK | MB_ICONERROR);
- } else {
- if (state->ssh2) {
- strbuf *blob = strbuf_new();
- ssh_key_public_blob(
- state->ssh2key.key, BinarySink_UPCAST(blob));
- ssh2_write_pubkey(fp, state->ssh2key.comment,
- blob->u, blob->len,
- SSH_KEYTYPE_SSH2_PUBLIC_RFC4716);
- strbuf_free(blob);
- } else {
- ssh1_write_pubkey(fp, &state->key);
- }
- if (fclose(fp) < 0) {
- MessageBox(hwnd, "Unable to save key file",
- "PuTTYgen Error", MB_OK | MB_ICONERROR);
- }
- }
- }
- }
- break;
- case IDC_LOAD:
- case IDC_IMPORT:
- if (HIWORD(wParam) != BN_CLICKED)
- break;
- state =
- (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
- if (!state->generation_thread_exists) {
- char filename[FILENAME_MAX];
- if (prompt_keyfile(hwnd, "Load private key:", filename, false,
- LOWORD(wParam) == IDC_LOAD)) {
- Filename *fn = filename_from_str(filename);
- load_key_file(hwnd, state, fn, LOWORD(wParam) != IDC_LOAD);
- filename_free(fn);
- }
- }
- break;
- }
- return 0;
- case WM_DONEKEY:
- state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
- state->generation_thread_exists = false;
- state->key_exists = true;
- SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
- MAKELPARAM(0, PROGRESSRANGE));
- SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, PROGRESSRANGE, 0);
- if (state->ssh2) {
- if (state->keytype == DSA) {
- state->ssh2key.key = &state->dsskey.sshk;
- } else if (state->keytype == ECDSA) {
- state->ssh2key.key = &state->eckey.sshk;
- } else if (state->keytype == EDDSA) {
- state->ssh2key.key = &state->edkey.sshk;
- } else {
- state->ssh2key.key = &state->key.sshk;
- }
- state->commentptr = &state->ssh2key.comment;
- } else {
- state->commentptr = &state->key.comment;
- }
- /*
- * Invent a comment for the key. We'll do this by including
- * the date in it. This will be so horrifyingly ugly that
- * the user will immediately want to change it, which is
- * what we want :-)
- */
- *state->commentptr = snewn(30, char);
- {
- struct tm tm;
- tm = ltime();
- if (state->keytype == DSA)
- strftime(*state->commentptr, 30, "dsa-key-%Y%m%d", &tm);
- else if (state->keytype == ECDSA)
- strftime(*state->commentptr, 30, "ecdsa-key-%Y%m%d", &tm);
- else if (state->keytype == EDDSA)
- strftime(*state->commentptr, 30, "eddsa-key-%Y%m%d", &tm);
- else
- strftime(*state->commentptr, 30, "rsa-key-%Y%m%d", &tm);
- }
-
- /*
- * Now update the key controls with all the key data.
- */
- {
- char *fp, *savecomment;
- /*
- * Blank passphrase, initially. This isn't dangerous,
- * because we will warn (Are You Sure?) before allowing
- * the user to save an unprotected private key.
- */
- SetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT, "");
- SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT, "");
- /*
- * Set the comment.
- */
- SetDlgItemText(hwnd, IDC_COMMENTEDIT, *state->commentptr);
- /*
- * Set the key fingerprint.
- */
- savecomment = *state->commentptr;
- *state->commentptr = NULL;
- if (state->ssh2)
- fp = ssh2_fingerprint(state->ssh2key.key, state->fptype);
- else
- fp = rsa_ssh1_fingerprint(&state->key);
- SetDlgItemText(hwnd, IDC_FINGERPRINT, fp);
- sfree(fp);
- *state->commentptr = savecomment;
- /*
- * Construct a decimal representation of the key, for
- * pasting into .ssh/authorized_keys or
- * .ssh/authorized_keys2 on a Unix box.
- */
- if (state->ssh2) {
- setupbigedit2(hwnd, IDC_KEYDISPLAY,
- IDC_PKSTATIC, &state->ssh2key);
- } else {
- setupbigedit1(hwnd, IDC_KEYDISPLAY,
- IDC_PKSTATIC, &state->key);
- }
- }
- /*
- * Finally, hide the progress bar and show the key data.
- */
- ui_set_state(hwnd, state, 2);
- break;
- case WM_HELP: {
- int id = ((LPHELPINFO)lParam)->iCtrlId;
- const char *topic = NULL;
- switch (id) {
- case IDC_GENERATING:
- case IDC_PROGRESS:
- case IDC_GENSTATIC:
- case IDC_GENERATE:
- topic = WINHELP_CTX_puttygen_generate; break;
- case IDC_PKSTATIC:
- case IDC_KEYDISPLAY:
- topic = WINHELP_CTX_puttygen_pastekey; break;
- case IDC_FPSTATIC:
- case IDC_FINGERPRINT:
- topic = WINHELP_CTX_puttygen_fingerprint; break;
- case IDC_COMMENTSTATIC:
- case IDC_COMMENTEDIT:
- topic = WINHELP_CTX_puttygen_comment; break;
- case IDC_PASSPHRASE1STATIC:
- case IDC_PASSPHRASE1EDIT:
- case IDC_PASSPHRASE2STATIC:
- case IDC_PASSPHRASE2EDIT:
- topic = WINHELP_CTX_puttygen_passphrase; break;
- case IDC_LOADSTATIC:
- case IDC_LOAD:
- topic = WINHELP_CTX_puttygen_load; break;
- case IDC_SAVESTATIC:
- case IDC_SAVE:
- topic = WINHELP_CTX_puttygen_savepriv; break;
- case IDC_SAVEPUB:
- topic = WINHELP_CTX_puttygen_savepub; break;
- case IDC_TYPESTATIC:
- case IDC_KEYSSH1:
- case IDC_KEYSSH2RSA:
- case IDC_KEYSSH2DSA:
- case IDC_KEYSSH2ECDSA:
- case IDC_KEYSSH2EDDSA:
- topic = WINHELP_CTX_puttygen_keytype; break;
- case IDC_BITSSTATIC:
- case IDC_BITS:
- topic = WINHELP_CTX_puttygen_bits; break;
- case IDC_IMPORT:
- case IDC_EXPORT_OPENSSH_AUTO:
- case IDC_EXPORT_OPENSSH_NEW:
- case IDC_EXPORT_SSHCOM:
- topic = WINHELP_CTX_puttygen_conversions; break;
- }
- if (topic) {
- launch_help(hwnd, topic);
- } else {
- MessageBeep(0);
- }
- break;
- }
- case WM_CLOSE:
- state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
- sfree(state);
- quit_help(hwnd);
- EndDialog(hwnd, 1);
- return 0;
- }
- return 0;
-}
-
-void cleanup_exit(int code)
-{
- shutdown_help();
- exit(code);
-}
-
-HINSTANCE hinst;
-
-int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
-{
- int argc, i;
- char **argv;
- int ret;
-
- dll_hijacking_protection();
-
- init_common_controls();
- hinst = inst;
-
- /*
- * See if we can find our Help file.
- */
- init_help();
-
- split_into_argv(cmdline, &argc, &argv, NULL);
-
- for (i = 0; i < argc; i++) {
- if (!strcmp(argv[i], "-pgpfp")) {
- pgp_fingerprints_msgbox(NULL);
- return 1;
- } else if (!strcmp(argv[i], "-restrict-acl") ||
- !strcmp(argv[i], "-restrict_acl") ||
- !strcmp(argv[i], "-restrictacl")) {
- restrict_process_acl();
- } else {
- /*
- * Assume the first argument to be a private key file, and
- * attempt to load it.
- */
- cmdline_keyfile = argv[i];
- break;
- }
- }
-
- save_params = ppk_save_default_parameters;
-
- random_setup_special();
- ret = DialogBox(hinst, MAKEINTRESOURCE(201), NULL, MainDlgProc) != IDOK;
-
- cleanup_exit(ret);
- return ret; /* just in case optimiser complains */
-}
diff --git a/WINDOWS/WINPGNT.C b/WINDOWS/WINPGNT.C
deleted file mode 100644
index d6e960b6..00000000
--- a/WINDOWS/WINPGNT.C
+++ /dev/null
@@ -1,1723 +0,0 @@
-/*
- * Pageant: the PuTTY Authentication Agent.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <ctype.h>
-#include <assert.h>
-#include <tchar.h>
-
-#include "putty.h"
-#include "ssh.h"
-#include "misc.h"
-#include "tree234.h"
-#include "winsecur.h"
-#include "wincapi.h"
-#include "pageant.h"
-#include "licence.h"
-#include "pageant-rc.h"
-
-#include <shellapi.h>
-
-#ifndef NO_SECURITY
-#include <aclapi.h>
-#ifdef DEBUG_IPC
-#define _WIN32_WINNT 0x0500 /* for ConvertSidToStringSid */
-#include <sddl.h>
-#endif
-#endif
-
-#define WM_SYSTRAY (WM_APP + 6)
-#define WM_SYSTRAY2 (WM_APP + 7)
-
-#define AGENT_COPYDATA_ID 0x804e50ba /* random goop */
-
-#define APPNAME "Pageant"
-
-/* Titles and class names for invisible windows. IPCWINTITLE and
- * IPCCLASSNAME are critical to backwards compatibility: WM_COPYDATA
- * based Pageant clients will call FindWindow with those parameters
- * and expect to find the Pageant IPC receiver. */
-#define TRAYWINTITLE "Pageant"
-#define TRAYCLASSNAME "PageantSysTray"
-#define IPCWINTITLE "Pageant"
-#define IPCCLASSNAME "Pageant"
-
-static HWND traywindow;
-static HWND keylist;
-static HWND aboutbox;
-static HMENU systray_menu, session_menu;
-static bool already_running;
-static FingerprintType fptype = SSH_FPTYPE_DEFAULT;
-
-static char *putty_path;
-static bool restrict_putty_acl = false;
-
-/* CWD for "add key" file requester. */
-static filereq *keypath = NULL;
-
-/* From MSDN: In the WM_SYSCOMMAND message, the four low-order bits of
- * wParam are used by Windows, and should be masked off, so we shouldn't
- * attempt to store information in them. Hence all these identifiers have
- * the low 4 bits clear. Also, identifiers should < 0xF000. */
-
-#define IDM_CLOSE 0x0010
-#define IDM_VIEWKEYS 0x0020
-#define IDM_ADDKEY 0x0030
-#define IDM_ADDKEY_ENCRYPTED 0x0040
-#define IDM_REMOVE_ALL 0x0050
-#define IDM_REENCRYPT_ALL 0x0060
-#define IDM_HELP 0x0070
-#define IDM_ABOUT 0x0080
-#define IDM_PUTTY 0x0090
-#define IDM_SESSIONS_BASE 0x1000
-#define IDM_SESSIONS_MAX 0x2000
-#define PUTTY_REGKEY "Software\\SimonTatham\\PuTTY\\Sessions"
-#define PUTTY_DEFAULT "Default%20Settings"
-static int initial_menuitems_count;
-
-/*
- * Print a modal (Really Bad) message box and perform a fatal exit.
- */
-void modalfatalbox(const char *fmt, ...)
-{
- va_list ap;
- char *buf;
-
- va_start(ap, fmt);
- buf = dupvprintf(fmt, ap);
- va_end(ap);
- MessageBox(traywindow, buf, "Pageant Fatal Error",
- MB_SYSTEMMODAL | MB_ICONERROR | MB_OK);
- sfree(buf);
- exit(1);
-}
-
-static bool has_security;
-
-struct PassphraseProcStruct {
- bool modal;
- const char *help_topic;
- PageantClientDialogId *dlgid;
- char *passphrase;
- const char *comment;
-};
-
-/*
- * Dialog-box function for the Licence box.
- */
-static INT_PTR CALLBACK LicenceProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- switch (msg) {
- case WM_INITDIALOG:
- SetDlgItemText(hwnd, IDC_LICENCE_TEXTBOX, LICENCE_TEXT("\r\n\r\n"));
- return 1;
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- case IDCANCEL:
- EndDialog(hwnd, 1);
- return 0;
- }
- return 0;
- case WM_CLOSE:
- EndDialog(hwnd, 1);
- return 0;
- }
- return 0;
-}
-
-/*
- * Dialog-box function for the About box.
- */
-static INT_PTR CALLBACK AboutProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- switch (msg) {
- case WM_INITDIALOG: {
- char *buildinfo_text = buildinfo("\r\n");
- char *text = dupprintf
- ("Pageant\r\n\r\n%s\r\n\r\n%s\r\n\r\n%s",
- ver, buildinfo_text,
- "\251 " SHORT_COPYRIGHT_DETAILS ". All rights reserved.");
- sfree(buildinfo_text);
- SetDlgItemText(hwnd, IDC_ABOUT_TEXTBOX, text);
- MakeDlgItemBorderless(hwnd, IDC_ABOUT_TEXTBOX);
- sfree(text);
- return 1;
- }
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- case IDCANCEL:
- aboutbox = NULL;
- DestroyWindow(hwnd);
- return 0;
- case IDC_ABOUT_LICENCE:
- EnableWindow(hwnd, 0);
- DialogBox(hinst, MAKEINTRESOURCE(IDD_LICENCE), hwnd, LicenceProc);
- EnableWindow(hwnd, 1);
- SetActiveWindow(hwnd);
- return 0;
- case IDC_ABOUT_WEBSITE:
- /* Load web browser */
- ShellExecute(hwnd, "open",
- "https://www.chiark.greenend.org.uk/~sgtatham/putty/",
- 0, 0, SW_SHOWDEFAULT);
- return 0;
- }
- return 0;
- case WM_CLOSE:
- aboutbox = NULL;
- DestroyWindow(hwnd);
- return 0;
- }
- return 0;
-}
-
-static HWND modal_passphrase_hwnd = NULL;
-static HWND nonmodal_passphrase_hwnd = NULL;
-
-static void end_passphrase_dialog(HWND hwnd, INT_PTR result)
-{
- struct PassphraseProcStruct *p = (struct PassphraseProcStruct *)
- GetWindowLongPtr(hwnd, GWLP_USERDATA);
-
- if (p->modal) {
- EndDialog(hwnd, result);
- } else {
- /*
- * Destroy this passphrase dialog box before passing the
- * results back to pageant.c, to avoid re-entrancy issues.
- *
- * If we successfully got a passphrase from the user, but it
- * was _wrong_, then pageant_passphrase_request_success will
- * respond by calling back - synchronously - to our
- * ask_passphrase() implementation, which will expect the
- * previous value of nonmodal_passphrase_hwnd to have already
- * been cleaned up.
- */
- SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) NULL);
- DestroyWindow(hwnd);
- nonmodal_passphrase_hwnd = NULL;
-
- if (result)
- pageant_passphrase_request_success(
- p->dlgid, ptrlen_from_asciz(p->passphrase));
- else
- pageant_passphrase_request_refused(p->dlgid);
-
- burnstr(p->passphrase);
- sfree(p);
- }
-}
-
-/*
- * Dialog-box function for the passphrase box.
- */
-static INT_PTR CALLBACK PassphraseProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- struct PassphraseProcStruct *p;
-
- if (msg == WM_INITDIALOG) {
- p = (struct PassphraseProcStruct *) lParam;
- SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) p);
- } else {
- p = (struct PassphraseProcStruct *)
- GetWindowLongPtr(hwnd, GWLP_USERDATA);
- }
-
- switch (msg) {
- case WM_INITDIALOG: {
- if (p->modal)
- modal_passphrase_hwnd = hwnd;
-
- /*
- * Centre the window.
- */
- RECT rs, rd;
- HWND hw;
-
- hw = GetDesktopWindow();
- if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
- MoveWindow(hwnd,
- (rs.right + rs.left + rd.left - rd.right) / 2,
- (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
- rd.right - rd.left, rd.bottom - rd.top, true);
-
- SetForegroundWindow(hwnd);
- SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
- SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
- if (!p->modal)
- SetActiveWindow(hwnd); /* this won't have happened automatically */
- if (p->comment)
- SetDlgItemText(hwnd, IDC_PASSPHRASE_FINGERPRINT, p->comment);
- burnstr(p->passphrase);
- p->passphrase = dupstr("");
- SetDlgItemText(hwnd, IDC_PASSPHRASE_EDITBOX, p->passphrase);
- if (!p->help_topic || !has_help()) {
- HWND item = GetDlgItem(hwnd, IDHELP);
- if (item)
- DestroyWindow(item);
- }
- return 0;
- }
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- if (p->passphrase)
- end_passphrase_dialog(hwnd, 1);
- else
- MessageBeep(0);
- return 0;
- case IDCANCEL:
- end_passphrase_dialog(hwnd, 0);
- return 0;
- case IDHELP:
- if (p->help_topic)
- launch_help(hwnd, p->help_topic);
- return 0;
- case IDC_PASSPHRASE_EDITBOX:
- if ((HIWORD(wParam) == EN_CHANGE) && p->passphrase) {
- burnstr(p->passphrase);
- p->passphrase = GetDlgItemText_alloc(
- hwnd, IDC_PASSPHRASE_EDITBOX);
- }
- return 0;
- }
- return 0;
- case WM_CLOSE:
- end_passphrase_dialog(hwnd, 0);
- return 0;
- }
- return 0;
-}
-
-/*
- * Warn about the obsolescent key file format.
- */
-void old_keyfile_warning(void)
-{
- static const char mbtitle[] = "PuTTY Key File Warning";
- static const char message[] =
- "You are loading an SSH-2 private key which has an\n"
- "old version of the file format. This means your key\n"
- "file is not fully tamperproof. Future versions of\n"
- "PuTTY may stop supporting this private key format,\n"
- "so we recommend you convert your key to the new\n"
- "format.\n"
- "\n"
- "You can perform this conversion by loading the key\n"
- "into PuTTYgen and then saving it again.";
-
- MessageBox(NULL, message, mbtitle, MB_OK);
-}
-
-struct keylist_update_ctx {
- bool enable_remove_controls;
- bool enable_reencrypt_controls;
-};
-
-static void keylist_update_callback(
- void *vctx, char **fingerprints, const char *comment, uint32_t ext_flags,
- struct pageant_pubkey *key)
-{
- struct keylist_update_ctx *ctx = (struct keylist_update_ctx *)vctx;
- FingerprintType this_type = ssh2_pick_fingerprint(fingerprints, fptype);
- const char *fingerprint = fingerprints[this_type];
- strbuf *listentry = strbuf_new();
-
- /* There is at least one key, so the controls for removing keys
- * should be enabled */
- ctx->enable_remove_controls = true;
-
- switch (key->ssh_version) {
- case 1: {
- strbuf_catf(listentry, "ssh1\t%s\t%s", fingerprint, comment);
-
- /*
- * Replace the space in the fingerprint (between bit count and
- * hash) with a tab, for nice alignment in the box.
- */
- char *p = strchr(listentry->s, ' ');
- if (p)
- *p = '\t';
- break;
- }
-
- case 2: {
- /*
- * For nice alignment in the list box, we would ideally want
- * every entry to align to the tab stop settings, and have a
- * column for algorithm name, one for bit count, one for hex
- * fingerprint, and one for key comment.
- *
- * Unfortunately, some of the algorithm names are so long that
- * they overflow into the bit-count field. Fortunately, at the
- * moment, those are _precisely_ the algorithm names that
- * don't need a bit count displayed anyway (because for
- * NIST-style ECDSA the bit count is mentioned in the
- * algorithm name, and for ssh-ed25519 there is only one
- * possible value anyway). So we fudge this by simply omitting
- * the bit count field in that situation.
- *
- * This is fragile not only in the face of further key types
- * that don't follow this pattern, but also in the face of
- * font metrics changes - the Windows semantics for list box
- * tab stops is that \t aligns to the next one you haven't
- * already exceeded, so I have to guess when the key type will
- * overflow past the bit-count tab stop and leave out a tab
- * character. Urgh.
- */
- BinarySource src[1];
- BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(key->blob));
- ptrlen algname = get_string(src);
- const ssh_keyalg *alg = find_pubkey_alg_len(algname);
-
- bool include_bit_count = (alg == &ssh_dss || alg == &ssh_rsa);
-
- int wordnumber = 0;
- for (const char *p = fingerprint; *p; p++) {
- char c = *p;
- if (c == ' ') {
- if (wordnumber < 2)
- c = '\t';
- wordnumber++;
- }
- if (include_bit_count || wordnumber != 1)
- put_byte(listentry, c);
- }
-
- strbuf_catf(listentry, "\t%s", comment);
- break;
- }
- }
-
- if (ext_flags & LIST_EXTENDED_FLAG_HAS_NO_CLEARTEXT_KEY) {
- strbuf_catf(listentry, "\t(encrypted)");
- } else if (ext_flags & LIST_EXTENDED_FLAG_HAS_ENCRYPTED_KEY_FILE) {
- strbuf_catf(listentry, "\t(re-encryptable)");
-
- /* At least one key can be re-encrypted */
- ctx->enable_reencrypt_controls = true;
- }
-
- SendDlgItemMessage(keylist, IDC_KEYLIST_LISTBOX,
- LB_ADDSTRING, 0, (LPARAM)listentry->s);
- strbuf_free(listentry);
-}
-
-/*
- * Update the visible key list.
- */
-void keylist_update(void)
-{
- if (keylist) {
- SendDlgItemMessage(keylist, IDC_KEYLIST_LISTBOX,
- LB_RESETCONTENT, 0, 0);
-
- char *errmsg;
- struct keylist_update_ctx ctx[1];
- ctx->enable_remove_controls = false;
- ctx->enable_reencrypt_controls = false;
- int status = pageant_enum_keys(keylist_update_callback, ctx, &errmsg);
- assert(status == PAGEANT_ACTION_OK);
- assert(!errmsg);
-
- SendDlgItemMessage(keylist, IDC_KEYLIST_LISTBOX,
- LB_SETCURSEL, (WPARAM) - 1, 0);
-
- EnableWindow(GetDlgItem(keylist, IDC_KEYLIST_REMOVE),
- ctx->enable_remove_controls);
- EnableWindow(GetDlgItem(keylist, IDC_KEYLIST_REENCRYPT),
- ctx->enable_reencrypt_controls);
- }
-}
-
-static void win_add_keyfile(Filename *filename, bool encrypted)
-{
- char *err;
- int ret;
-
- /*
- * Try loading the key without a passphrase. (Or rather, without a
- * _new_ passphrase; pageant_add_keyfile will take care of trying
- * all the passphrases we've already stored.)
- */
- ret = pageant_add_keyfile(filename, NULL, &err, encrypted);
- if (ret == PAGEANT_ACTION_OK) {
- goto done;
- } else if (ret == PAGEANT_ACTION_FAILURE) {
- goto error;
- }
-
- /*
- * OK, a passphrase is needed, and we've been given the key
- * comment to use in the passphrase prompt.
- */
- while (1) {
- INT_PTR dlgret;
- struct PassphraseProcStruct pps;
- pps.modal = true;
- pps.help_topic = NULL; /* this dialog has no help button */
- pps.dlgid = NULL;
- pps.passphrase = NULL;
- pps.comment = err;
- dlgret = DialogBoxParam(
- hinst, MAKEINTRESOURCE(IDD_LOAD_PASSPHRASE),
- NULL, PassphraseProc, (LPARAM) &pps);
- modal_passphrase_hwnd = NULL;
-
- if (!dlgret) {
- burnstr(pps.passphrase);
- goto done; /* operation cancelled */
- }
-
- sfree(err);
-
- assert(pps.passphrase != NULL);
-
- ret = pageant_add_keyfile(filename, pps.passphrase, &err, false);
- burnstr(pps.passphrase);
-
- if (ret == PAGEANT_ACTION_OK) {
- goto done;
- } else if (ret == PAGEANT_ACTION_FAILURE) {
- goto error;
- }
- }
-
- error:
- message_box(traywindow, err, APPNAME, MB_OK | MB_ICONERROR,
- HELPCTXID(errors_cantloadkey));
- done:
- sfree(err);
- return;
-}
-
-/*
- * Prompt for a key file to add, and add it.
- */
-static void prompt_add_keyfile(bool encrypted)
-{
- OPENFILENAME of;
- char *filelist = snewn(8192, char);
-
- if (!keypath) keypath = filereq_new();
- memset(&of, 0, sizeof(of));
- of.hwndOwner = traywindow;
- of.lpstrFilter = FILTER_KEY_FILES;
- of.lpstrCustomFilter = NULL;
- of.nFilterIndex = 1;
- of.lpstrFile = filelist;
- *filelist = '\0';
- of.nMaxFile = 8192;
- of.lpstrFileTitle = NULL;
- of.lpstrTitle = "Select Private Key File";
- of.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER;
- if (request_file(keypath, &of, true, false)) {
- if(strlen(filelist) > of.nFileOffset) {
- /* Only one filename returned? */
- Filename *fn = filename_from_str(filelist);
- win_add_keyfile(fn, encrypted);
- filename_free(fn);
- } else {
- /* we are returned a bunch of strings, end to
- * end. first string is the directory, the
- * rest the filenames. terminated with an
- * empty string.
- */
- char *dir = filelist;
- char *filewalker = filelist + strlen(dir) + 1;
- while (*filewalker != '\0') {
- char *filename = dupcat(dir, "\\", filewalker);
- Filename *fn = filename_from_str(filename);
- win_add_keyfile(fn, encrypted);
- filename_free(fn);
- sfree(filename);
- filewalker += strlen(filewalker) + 1;
- }
- }
-
- keylist_update();
- pageant_forget_passphrases();
- }
- sfree(filelist);
-}
-
-/*
- * Dialog-box function for the key list box.
- */
-static INT_PTR CALLBACK KeyListProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- static const struct {
- const char *name;
- FingerprintType value;
- } fptypes[] = {
- {"SHA256", SSH_FPTYPE_SHA256},
- {"MD5", SSH_FPTYPE_MD5},
- };
-
- switch (msg) {
- case WM_INITDIALOG: {
- /*
- * Centre the window.
- */
- RECT rs, rd;
- HWND hw;
-
- hw = GetDesktopWindow();
- if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
- MoveWindow(hwnd,
- (rs.right + rs.left + rd.left - rd.right) / 2,
- (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
- rd.right - rd.left, rd.bottom - rd.top, true);
-
- if (has_help())
- SetWindowLongPtr(hwnd, GWL_EXSTYLE,
- GetWindowLongPtr(hwnd, GWL_EXSTYLE) |
- WS_EX_CONTEXTHELP);
- else {
- HWND item = GetDlgItem(hwnd, IDC_KEYLIST_HELP);
- if (item)
- DestroyWindow(item);
- }
-
- keylist = hwnd;
- {
- static int tabs[] = { 35, 75, 300 };
- SendDlgItemMessage(hwnd, IDC_KEYLIST_LISTBOX, LB_SETTABSTOPS,
- sizeof(tabs) / sizeof(*tabs),
- (LPARAM) tabs);
- }
-
- int selection = 0;
- for (size_t i = 0; i < lenof(fptypes); i++) {
- SendDlgItemMessage(hwnd, IDC_KEYLIST_FPTYPE, CB_ADDSTRING,
- 0, (LPARAM)fptypes[i].name);
- if (fptype == fptypes[i].value)
- selection = (int)i;
- }
- SendDlgItemMessage(hwnd, IDC_KEYLIST_FPTYPE,
- CB_SETCURSEL, 0, selection);
-
- keylist_update();
- return 0;
- }
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- case IDCANCEL:
- keylist = NULL;
- DestroyWindow(hwnd);
- return 0;
- case IDC_KEYLIST_ADDKEY:
- case IDC_KEYLIST_ADDKEY_ENC:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- if (modal_passphrase_hwnd) {
- MessageBeep(MB_ICONERROR);
- SetForegroundWindow(modal_passphrase_hwnd);
- break;
- }
- prompt_add_keyfile(LOWORD(wParam) == IDC_KEYLIST_ADDKEY_ENC);
- }
- return 0;
- case IDC_KEYLIST_REMOVE:
- case IDC_KEYLIST_REENCRYPT:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- int i;
- int rCount, sCount;
- int *selectedArray;
-
- /* our counter within the array of selected items */
- int itemNum;
-
- /* get the number of items selected in the list */
- int numSelected = SendDlgItemMessage(
- hwnd, IDC_KEYLIST_LISTBOX, LB_GETSELCOUNT, 0, 0);
-
- /* none selected? that was silly */
- if (numSelected == 0) {
- MessageBeep(0);
- break;
- }
-
- /* get item indices in an array */
- selectedArray = snewn(numSelected, int);
- SendDlgItemMessage(hwnd, IDC_KEYLIST_LISTBOX, LB_GETSELITEMS,
- numSelected, (WPARAM)selectedArray);
-
- itemNum = numSelected - 1;
- rCount = pageant_count_ssh1_keys();
- sCount = pageant_count_ssh2_keys();
-
- /* go through the non-rsakeys until we've covered them all,
- * and/or we're out of selected items to check. note that
- * we go *backwards*, to avoid complications from deleting
- * things hence altering the offset of subsequent items
- */
- for (i = sCount - 1; (itemNum >= 0) && (i >= 0); i--) {
- if (selectedArray[itemNum] == rCount + i) {
- switch (LOWORD(wParam)) {
- case IDC_KEYLIST_REMOVE:
- pageant_delete_nth_ssh2_key(i);
- break;
- case IDC_KEYLIST_REENCRYPT:
- pageant_reencrypt_nth_ssh2_key(i);
- break;
- }
- itemNum--;
- }
- }
-
- /* do the same for the rsa keys */
- for (i = rCount - 1; (itemNum >= 0) && (i >= 0); i--) {
- if(selectedArray[itemNum] == i) {
- switch (LOWORD(wParam)) {
- case IDC_KEYLIST_REMOVE:
- pageant_delete_nth_ssh1_key(i);
- break;
- case IDC_KEYLIST_REENCRYPT:
- /* SSH-1 keys can't be re-encrypted */
- break;
- }
- itemNum--;
- }
- }
-
- sfree(selectedArray);
- keylist_update();
- }
- return 0;
- case IDC_KEYLIST_HELP:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- launch_help(hwnd, WINHELP_CTX_pageant_general);
- }
- return 0;
- case IDC_KEYLIST_FPTYPE:
- if (HIWORD(wParam) == CBN_SELCHANGE) {
- int selection = SendDlgItemMessage(
- hwnd, IDC_KEYLIST_FPTYPE, CB_GETCURSEL, 0, 0);
- if (selection >= 0 && (size_t)selection < lenof(fptypes)) {
- fptype = fptypes[selection].value;
- keylist_update();
- }
- }
- return 0;
- }
- return 0;
- case WM_HELP: {
- int id = ((LPHELPINFO)lParam)->iCtrlId;
- const char *topic = NULL;
- switch (id) {
- case IDC_KEYLIST_LISTBOX:
- case IDC_KEYLIST_FPTYPE:
- case IDC_KEYLIST_FPTYPE_STATIC:
- topic = WINHELP_CTX_pageant_keylist; break;
- case IDC_KEYLIST_ADDKEY: topic = WINHELP_CTX_pageant_addkey; break;
- case IDC_KEYLIST_REMOVE: topic = WINHELP_CTX_pageant_remkey; break;
- case IDC_KEYLIST_ADDKEY_ENC:
- case IDC_KEYLIST_REENCRYPT:
- topic = WINHELP_CTX_pageant_deferred; break;
- }
- if (topic) {
- launch_help(hwnd, topic);
- } else {
- MessageBeep(0);
- }
- break;
- }
- case WM_CLOSE:
- keylist = NULL;
- DestroyWindow(hwnd);
- return 0;
- }
- return 0;
-}
-
-/* Set up a system tray icon */
-static BOOL AddTrayIcon(HWND hwnd)
-{
- BOOL res;
- NOTIFYICONDATA tnid;
- HICON hicon;
-
-#ifdef NIM_SETVERSION
- tnid.uVersion = 0;
- res = Shell_NotifyIcon(NIM_SETVERSION, &tnid);
-#endif
-
- tnid.cbSize = sizeof(NOTIFYICONDATA);
- tnid.hWnd = hwnd;
- tnid.uID = 1; /* unique within this systray use */
- tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
- tnid.uCallbackMessage = WM_SYSTRAY;
- tnid.hIcon = hicon = LoadIcon(hinst, MAKEINTRESOURCE(201));
- strcpy(tnid.szTip, "Pageant (PuTTY authentication agent)");
-
- res = Shell_NotifyIcon(NIM_ADD, &tnid);
-
- if (hicon) DestroyIcon(hicon);
-
- return res;
-}
-
-/* Update the saved-sessions menu. */
-static void update_sessions(void)
-{
- int num_entries;
- HKEY hkey;
- TCHAR buf[MAX_PATH + 1];
- MENUITEMINFO mii;
- strbuf *sb;
-
- int index_key, index_menu;
-
- if (!putty_path)
- return;
-
- if(ERROR_SUCCESS != RegOpenKey(HKEY_CURRENT_USER, PUTTY_REGKEY, &hkey))
- return;
-
- for(num_entries = GetMenuItemCount(session_menu);
- num_entries > initial_menuitems_count;
- num_entries--)
- RemoveMenu(session_menu, 0, MF_BYPOSITION);
-
- index_key = 0;
- index_menu = 0;
-
- sb = strbuf_new();
- while(ERROR_SUCCESS == RegEnumKey(hkey, index_key, buf, MAX_PATH)) {
- if(strcmp(buf, PUTTY_DEFAULT) != 0) {
- strbuf_clear(sb);
- unescape_registry_key(buf, sb);
-
- memset(&mii, 0, sizeof(mii));
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID;
- mii.fType = MFT_STRING;
- mii.fState = MFS_ENABLED;
- mii.wID = (index_menu * 16) + IDM_SESSIONS_BASE;
- mii.dwTypeData = sb->s;
- InsertMenuItem(session_menu, index_menu, true, &mii);
- index_menu++;
- }
- index_key++;
- }
- strbuf_free(sb);
-
- RegCloseKey(hkey);
-
- if(index_menu == 0) {
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_TYPE | MIIM_STATE;
- mii.fType = MFT_STRING;
- mii.fState = MFS_GRAYED;
- mii.dwTypeData = _T("(No sessions)");
- InsertMenuItem(session_menu, index_menu, true, &mii);
- }
-}
-
-#ifndef NO_SECURITY
-/*
- * Versions of Pageant prior to 0.61 expected this SID on incoming
- * communications. For backwards compatibility, and more particularly
- * for compatibility with derived works of PuTTY still using the old
- * Pageant client code, we accept it as an alternative to the one
- * returned from get_user_sid() in winpgntc.c.
- */
-PSID get_default_sid(void)
-{
- HANDLE proc = NULL;
- DWORD sidlen;
- PSECURITY_DESCRIPTOR psd = NULL;
- PSID sid = NULL, copy = NULL, ret = NULL;
-
- if ((proc = OpenProcess(MAXIMUM_ALLOWED, false,
- GetCurrentProcessId())) == NULL)
- goto cleanup;
-
- if (p_GetSecurityInfo(proc, SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION,
- &sid, NULL, NULL, NULL, &psd) != ERROR_SUCCESS)
- goto cleanup;
-
- sidlen = GetLengthSid(sid);
-
- copy = (PSID)smalloc(sidlen);
-
- if (!CopySid(sidlen, copy, sid))
- goto cleanup;
-
- /* Success. Move sid into the return value slot, and null it out
- * to stop the cleanup code freeing it. */
- ret = copy;
- copy = NULL;
-
- cleanup:
- if (proc != NULL)
- CloseHandle(proc);
- if (psd != NULL)
- LocalFree(psd);
- if (copy != NULL)
- sfree(copy);
-
- return ret;
-}
-#endif
-
-struct WmCopydataTransaction {
- char *length, *body;
- size_t bodysize, bodylen;
- HANDLE ev_msg_ready, ev_reply_ready;
-} wmct;
-
-static struct PageantClient wmcpc;
-
-static void wm_copydata_got_msg(void *vctx)
-{
- pageant_handle_msg(&wmcpc, NULL, make_ptrlen(wmct.body, wmct.bodylen));
-}
-
-static void wm_copydata_got_response(
- PageantClient *pc, PageantClientRequestId *reqid, ptrlen response)
-{
- if (response.len > wmct.bodysize) {
- /* Output would overflow message buffer. Replace with a
- * failure message. */
- static const unsigned char failure[] = { SSH_AGENT_FAILURE };
- response = make_ptrlen(failure, lenof(failure));
- assert(response.len <= wmct.bodysize);
- }
-
- PUT_32BIT_MSB_FIRST(wmct.length, response.len);
- memcpy(wmct.body, response.ptr, response.len);
-
- SetEvent(wmct.ev_reply_ready);
-}
-
-static bool ask_passphrase_common(PageantClientDialogId *dlgid,
- const char *comment)
-{
- /* Pageant core should be serialising requests, so we never expect
- * a passphrase prompt to exist already at this point */
- assert(!nonmodal_passphrase_hwnd);
-
- struct PassphraseProcStruct *pps = snew(struct PassphraseProcStruct);
- pps->modal = false;
- pps->help_topic = WINHELP_CTX_pageant_deferred;
- pps->dlgid = dlgid;
- pps->passphrase = NULL;
- pps->comment = comment;
-
- nonmodal_passphrase_hwnd = CreateDialogParam(
- hinst, MAKEINTRESOURCE(IDD_ONDEMAND_PASSPHRASE),
- NULL, PassphraseProc, (LPARAM)pps);
-
- /*
- * Try to put this passphrase prompt into the foreground.
- *
- * This will probably not succeed in giving it the actual keyboard
- * focus, because Windows is quite opposed to applications being
- * able to suddenly steal the focus on their own initiative.
- *
- * That makes sense in a lot of situations, as a defensive
- * measure. If you were about to type a password or other secret
- * data into the window you already had focused, and some
- * malicious app stole the focus, it might manage to trick you
- * into typing your secrets into _it_ instead.
- *
- * In this case it's possible to regard the same defensive measure
- * as counterproductive, because the effect if we _do_ steal focus
- * is that you type something into our passphrase prompt that
- * isn't the passphrase, and we fail to decrypt the key, and no
- * harm is done. Whereas the effect of the user wrongly _assuming_
- * the new passphrase prompt has the focus is much worse: now you
- * type your highly secret passphrase into some other window you
- * didn't mean to trust with that information - such as the
- * agent-forwarded PuTTY in which you just ran an ssh command,
- * which the _whole point_ was to avoid telling your passphrase to!
- *
- * On the other hand, I'm sure _every_ application author can come
- * up with an argument for why they think _they_ should be allowed
- * to steal the focus. Probably most of them include the claim
- * that no harm is done if their application receives data
- * intended for something else, and of course that's not always
- * true!
- *
- * In any case, I don't know of anything I can do about it, or
- * anything I _should_ do about it if I could. If anyone thinks
- * they can improve on all this, patches are welcome.
- */
- SetForegroundWindow(nonmodal_passphrase_hwnd);
-
- return true;
-}
-
-static bool wm_copydata_ask_passphrase(
- PageantClient *pc, PageantClientDialogId *dlgid, const char *comment)
-{
- return ask_passphrase_common(dlgid, comment);
-}
-
-static const PageantClientVtable wmcpc_vtable = {
- .log = NULL, /* no logging in this client */
- .got_response = wm_copydata_got_response,
- .ask_passphrase = wm_copydata_ask_passphrase,
-};
-
-static char *answer_filemapping_message(const char *mapname)
-{
- HANDLE maphandle = INVALID_HANDLE_VALUE;
- void *mapaddr = NULL;
- char *err = NULL;
- size_t mapsize;
- unsigned msglen;
-
-#ifndef NO_SECURITY
- PSID mapsid = NULL;
- PSID expectedsid = NULL;
- PSID expectedsid_bc = NULL;
- PSECURITY_DESCRIPTOR psd = NULL;
-#endif
-
- wmct.length = wmct.body = NULL;
-
-#ifdef DEBUG_IPC
- debug("mapname = \"%s\"\n", mapname);
-#endif
-
- maphandle = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, mapname);
- if (maphandle == NULL || maphandle == INVALID_HANDLE_VALUE) {
- err = dupprintf("OpenFileMapping(\"%s\"): %s",
- mapname, win_strerror(GetLastError()));
- goto cleanup;
- }
-
-#ifdef DEBUG_IPC
- debug("maphandle = %p\n", maphandle);
-#endif
-
-#ifndef NO_SECURITY
- if (has_security) {
- DWORD retd;
-
- if ((expectedsid = get_user_sid()) == NULL) {
- err = dupstr("unable to get user SID");
- goto cleanup;
- }
-
- if ((expectedsid_bc = get_default_sid()) == NULL) {
- err = dupstr("unable to get default SID");
- goto cleanup;
- }
-
- if ((retd = p_GetSecurityInfo(
- maphandle, SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION,
- &mapsid, NULL, NULL, NULL, &psd) != ERROR_SUCCESS)) {
- err = dupprintf("unable to get owner of file mapping: "
- "GetSecurityInfo returned: %s",
- win_strerror(retd));
- goto cleanup;
- }
-
-#ifdef DEBUG_IPC
- {
- LPTSTR ours, ours2, theirs;
- ConvertSidToStringSid(mapsid, &theirs);
- ConvertSidToStringSid(expectedsid, &ours);
- ConvertSidToStringSid(expectedsid_bc, &ours2);
- debug("got sids:\n oursnew=%s\n oursold=%s\n"
- " theirs=%s\n", ours, ours2, theirs);
- LocalFree(ours);
- LocalFree(ours2);
- LocalFree(theirs);
- }
-#endif
-
- if (!EqualSid(mapsid, expectedsid) &&
- !EqualSid(mapsid, expectedsid_bc)) {
- err = dupstr("wrong owning SID of file mapping");
- goto cleanup;
- }
- } else
-#endif /* NO_SECURITY */
- {
-#ifdef DEBUG_IPC
- debug("security APIs not present\n");
-#endif
- }
-
- mapaddr = MapViewOfFile(maphandle, FILE_MAP_WRITE, 0, 0, 0);
- if (!mapaddr) {
- err = dupprintf("unable to obtain view of file mapping: %s",
- win_strerror(GetLastError()));
- goto cleanup;
- }
-
-#ifdef DEBUG_IPC
- debug("mapped address = %p\n", mapaddr);
-#endif
-
- {
- MEMORY_BASIC_INFORMATION mbi;
- size_t mbiSize = VirtualQuery(mapaddr, &mbi, sizeof(mbi));
- if (mbiSize == 0) {
- err = dupprintf("unable to query view of file mapping: %s",
- win_strerror(GetLastError()));
- goto cleanup;
- }
- if (mbiSize < (offsetof(MEMORY_BASIC_INFORMATION, RegionSize) +
- sizeof(mbi.RegionSize))) {
- err = dupstr("VirtualQuery returned too little data to get "
- "region size");
- goto cleanup;
- }
-
- mapsize = mbi.RegionSize;
- }
-#ifdef DEBUG_IPC
- debug("region size = %"SIZEu"\n", mapsize);
-#endif
- if (mapsize < 5) {
- err = dupstr("mapping smaller than smallest possible request");
- goto cleanup;
- }
-
- wmct.length = (char *)mapaddr;
- msglen = GET_32BIT_MSB_FIRST(wmct.length);
-
-#ifdef DEBUG_IPC
- debug("msg length=%08x, msg type=%02x\n",
- msglen, (unsigned)((unsigned char *) mapaddr)[4]);
-#endif
-
- wmct.body = wmct.length + 4;
- wmct.bodysize = mapsize - 4;
-
- if (msglen > wmct.bodysize) {
- /* Incoming length field is too large. Emit a failure response
- * without even trying to handle the request.
- *
- * (We know this must fit, because we checked mapsize >= 5
- * above.) */
- PUT_32BIT_MSB_FIRST(wmct.length, 1);
- *wmct.body = SSH_AGENT_FAILURE;
- } else {
- wmct.bodylen = msglen;
- SetEvent(wmct.ev_msg_ready);
- WaitForSingleObject(wmct.ev_reply_ready, INFINITE);
- }
-
- cleanup:
- /* expectedsid has the lifetime of the program, so we don't free it */
- sfree(expectedsid_bc);
- if (psd)
- LocalFree(psd);
- if (mapaddr)
- UnmapViewOfFile(mapaddr);
- if (maphandle != NULL && maphandle != INVALID_HANDLE_VALUE)
- CloseHandle(maphandle);
- return err;
-}
-
-static void create_keylist_window(void)
-{
- if (keylist)
- return;
-
- keylist = CreateDialog(hinst, MAKEINTRESOURCE(IDD_KEYLIST),
- NULL, KeyListProc);
- ShowWindow(keylist, SW_SHOWNORMAL);
-}
-
-static LRESULT CALLBACK TrayWndProc(HWND hwnd, UINT message,
- WPARAM wParam, LPARAM lParam)
-{
- static bool menuinprogress;
- static UINT msgTaskbarCreated = 0;
-
- switch (message) {
- case WM_CREATE:
- msgTaskbarCreated = RegisterWindowMessage(_T("TaskbarCreated"));
- break;
- default:
- if (message==msgTaskbarCreated) {
- /*
- * Explorer has been restarted, so the tray icon will
- * have been lost.
- */
- AddTrayIcon(hwnd);
- }
- break;
-
- case WM_SYSTRAY:
- if (lParam == WM_RBUTTONUP) {
- POINT cursorpos;
- GetCursorPos(&cursorpos);
- PostMessage(hwnd, WM_SYSTRAY2, cursorpos.x, cursorpos.y);
- } else if (lParam == WM_LBUTTONDBLCLK) {
- /* Run the default menu item. */
- UINT menuitem = GetMenuDefaultItem(systray_menu, false, 0);
- if (menuitem != -1)
- PostMessage(hwnd, WM_COMMAND, menuitem, 0);
- }
- break;
- case WM_SYSTRAY2:
- if (!menuinprogress) {
- menuinprogress = true;
- update_sessions();
- SetForegroundWindow(hwnd);
- TrackPopupMenu(systray_menu,
- TPM_RIGHTALIGN | TPM_BOTTOMALIGN |
- TPM_RIGHTBUTTON,
- wParam, lParam, 0, hwnd, NULL);
- menuinprogress = false;
- }
- break;
- case WM_COMMAND:
- case WM_SYSCOMMAND: {
- unsigned command = wParam & ~0xF; /* low 4 bits reserved to Windows */
- switch (command) {
- case IDM_PUTTY: {
- TCHAR cmdline[10];
- cmdline[0] = '\0';
- if (restrict_putty_acl)
- strcat(cmdline, "&R");
-
- if((INT_PTR)ShellExecute(hwnd, NULL, putty_path, cmdline,
- _T(""), SW_SHOW) <= 32) {
- MessageBox(NULL, "Unable to execute PuTTY!",
- "Error", MB_OK | MB_ICONERROR);
- }
- break;
- }
- case IDM_CLOSE:
- if (modal_passphrase_hwnd)
- SendMessage(modal_passphrase_hwnd, WM_CLOSE, 0, 0);
- SendMessage(hwnd, WM_CLOSE, 0, 0);
- break;
- case IDM_VIEWKEYS:
- create_keylist_window();
- /*
- * Sometimes the window comes up minimised / hidden for
- * no obvious reason. Prevent this. This also brings it
- * to the front if it's already present (the user
- * selected View Keys because they wanted to _see_ the
- * thing).
- */
- SetForegroundWindow(keylist);
- SetWindowPos(keylist, HWND_TOP, 0, 0, 0, 0,
- SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
- break;
- case IDM_ADDKEY:
- case IDM_ADDKEY_ENCRYPTED:
- if (modal_passphrase_hwnd) {
- MessageBeep(MB_ICONERROR);
- SetForegroundWindow(modal_passphrase_hwnd);
- break;
- }
- prompt_add_keyfile(command == IDM_ADDKEY_ENCRYPTED);
- break;
- case IDM_REMOVE_ALL:
- pageant_delete_all();
- keylist_update();
- break;
- case IDM_REENCRYPT_ALL:
- pageant_reencrypt_all();
- keylist_update();
- break;
- case IDM_ABOUT:
- if (!aboutbox) {
- aboutbox = CreateDialog(hinst, MAKEINTRESOURCE(IDD_ABOUT),
- NULL, AboutProc);
- ShowWindow(aboutbox, SW_SHOWNORMAL);
- /*
- * Sometimes the window comes up minimised / hidden
- * for no obvious reason. Prevent this.
- */
- SetForegroundWindow(aboutbox);
- SetWindowPos(aboutbox, HWND_TOP, 0, 0, 0, 0,
- SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
- }
- break;
- case IDM_HELP:
- launch_help(hwnd, WINHELP_CTX_pageant_general);
- break;
- default: {
- if(wParam >= IDM_SESSIONS_BASE && wParam <= IDM_SESSIONS_MAX) {
- MENUITEMINFO mii;
- TCHAR buf[MAX_PATH + 1];
- TCHAR param[MAX_PATH + 1];
- memset(&mii, 0, sizeof(mii));
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_TYPE;
- mii.cch = MAX_PATH;
- mii.dwTypeData = buf;
- GetMenuItemInfo(session_menu, wParam, false, &mii);
- param[0] = '\0';
- if (restrict_putty_acl)
- strcat(param, "&R");
- strcat(param, "@");
- strcat(param, mii.dwTypeData);
- if((INT_PTR)ShellExecute(hwnd, NULL, putty_path, param,
- _T(""), SW_SHOW) <= 32) {
- MessageBox(NULL, "Unable to execute PuTTY!", "Error",
- MB_OK | MB_ICONERROR);
- }
- }
- break;
- }
- }
- break;
- }
- case WM_DESTROY:
- quit_help(hwnd);
- PostQuitMessage(0);
- return 0;
- }
-
- return DefWindowProc(hwnd, message, wParam, lParam);
-}
-
-static LRESULT CALLBACK wm_copydata_WndProc(HWND hwnd, UINT message,
- WPARAM wParam, LPARAM lParam)
-{
- switch (message) {
- case WM_COPYDATA: {
- COPYDATASTRUCT *cds;
- char *mapname, *err;
-
- cds = (COPYDATASTRUCT *) lParam;
- if (cds->dwData != AGENT_COPYDATA_ID)
- return 0; /* not our message, mate */
- mapname = (char *) cds->lpData;
- if (mapname[cds->cbData - 1] != '\0')
- return 0; /* failure to be ASCIZ! */
- err = answer_filemapping_message(mapname);
- if (err) {
-#ifdef DEBUG_IPC
- debug("IPC failed: %s\n", err);
-#endif
- sfree(err);
- return 0;
- }
- return 1;
- }
- }
-
- return DefWindowProc(hwnd, message, wParam, lParam);
-}
-
-static DWORD WINAPI wm_copydata_threadfunc(void *param)
-{
- HINSTANCE inst = *(HINSTANCE *)param;
-
- HWND ipchwnd = CreateWindow(IPCCLASSNAME, IPCWINTITLE,
- WS_OVERLAPPEDWINDOW | WS_VSCROLL,
- CW_USEDEFAULT, CW_USEDEFAULT,
- 100, 100, NULL, NULL, inst, NULL);
- ShowWindow(ipchwnd, SW_HIDE);
-
- MSG msg;
- while (GetMessage(&msg, NULL, 0, 0) == 1) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
-
- return 0;
-}
-
-/*
- * Fork and Exec the command in cmdline. [DBW]
- */
-void spawn_cmd(const char *cmdline, const char *args, int show)
-{
- if (ShellExecute(NULL, _T("open"), cmdline,
- args, NULL, show) <= (HINSTANCE) 32) {
- char *msg;
- msg = dupprintf("Failed to run \"%s\": %s", cmdline,
- win_strerror(GetLastError()));
- MessageBox(NULL, msg, APPNAME, MB_OK | MB_ICONEXCLAMATION);
- sfree(msg);
- }
-}
-
-void logevent(LogContext *logctx, const char *event)
-{
- unreachable("Pageant can't create a LogContext, so this can't be called");
-}
-
-void noise_ultralight(NoiseSourceId id, unsigned long data)
-{
- /* Pageant doesn't use random numbers, so we ignore this */
-}
-
-void cleanup_exit(int code)
-{
- shutdown_help();
- exit(code);
-}
-
-static bool winpgnt_listener_ask_passphrase(
- PageantListenerClient *plc, PageantClientDialogId *dlgid,
- const char *comment)
-{
- return ask_passphrase_common(dlgid, comment);
-}
-
-struct winpgnt_client {
- PageantListenerClient plc;
-};
-static const PageantListenerClientVtable winpgnt_vtable = {
- .log = NULL, /* no logging */
- .ask_passphrase = winpgnt_listener_ask_passphrase,
-};
-
-static struct winpgnt_client wpc[1];
-
-HINSTANCE hinst;
-
-int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
-{
- MSG msg;
- const char *command = NULL;
- bool added_keys = false;
- bool show_keylist_on_startup = false;
- int argc, i;
- char **argv, **argstart;
-
- dll_hijacking_protection();
-
- hinst = inst;
-
- /*
- * Determine whether we're an NT system (should have security
- * APIs) or a non-NT system (don't do security).
- */
- init_winver();
- has_security = (osPlatformId == VER_PLATFORM_WIN32_NT);
-
- if (has_security) {
-#ifndef NO_SECURITY
- /*
- * Attempt to get the security API we need.
- */
- if (!got_advapi()) {
- MessageBox(NULL,
- "Unable to access security APIs. Pageant will\n"
- "not run, in case it causes a security breach.",
- "Pageant Fatal Error", MB_ICONERROR | MB_OK);
- return 1;
- }
-#else
- MessageBox(NULL,
- "This program has been compiled for Win9X and will\n"
- "not run on NT, in case it causes a security breach.",
- "Pageant Fatal Error", MB_ICONERROR | MB_OK);
- return 1;
-#endif
- }
-
- /*
- * See if we can find our Help file.
- */
- init_help();
-
- /*
- * Look for the PuTTY binary (we will enable the saved session
- * submenu if we find it).
- */
- {
- char b[2048], *p, *q, *r;
- FILE *fp;
- GetModuleFileName(NULL, b, sizeof(b) - 16);
- r = b;
- p = strrchr(b, '\\');
- if (p && p >= r) r = p+1;
- q = strrchr(b, ':');
- if (q && q >= r) r = q+1;
- strcpy(r, "putty.exe");
- if ( (fp = fopen(b, "r")) != NULL) {
- putty_path = dupstr(b);
- fclose(fp);
- } else
- putty_path = NULL;
- }
-
- /*
- * Find out if Pageant is already running.
- */
- already_running = agent_exists();
-
- /*
- * Initialise the cross-platform Pageant code.
- */
- if (!already_running) {
- pageant_init();
- }
-
- /*
- * Process the command line and add keys as listed on it.
- */
- split_into_argv(cmdline, &argc, &argv, &argstart);
- bool doing_opts = true;
- bool add_keys_encrypted = false;
- for (i = 0; i < argc; i++) {
- char *p = argv[i];
- if (*p == '-' && doing_opts) {
- if (!strcmp(p, "-pgpfp")) {
- pgp_fingerprints_msgbox(NULL);
- return 1;
- } else if (!strcmp(p, "-restrict-acl") ||
- !strcmp(p, "-restrict_acl") ||
- !strcmp(p, "-restrictacl")) {
- restrict_process_acl();
- } else if (!strcmp(p, "-restrict-putty-acl") ||
- !strcmp(p, "-restrict_putty_acl")) {
- restrict_putty_acl = true;
- } else if (!strcmp(p, "--no-decrypt") ||
- !strcmp(p, "-no-decrypt") ||
- !strcmp(p, "--no_decrypt") ||
- !strcmp(p, "-no_decrypt") ||
- !strcmp(p, "--nodecrypt") ||
- !strcmp(p, "-nodecrypt") ||
- !strcmp(p, "--encrypted") ||
- !strcmp(p, "-encrypted")) {
- add_keys_encrypted = true;
- } else if (!strcmp(p, "-keylist") || !strcmp(p, "--keylist")) {
- show_keylist_on_startup = true;
- } else if (!strcmp(p, "-c")) {
- /*
- * If we see `-c', then the rest of the
- * command line should be treated as a
- * command to be spawned.
- */
- if (i < argc-1)
- command = argstart[i+1];
- else
- command = "";
- break;
- } else if (!strcmp(p, "--")) {
- doing_opts = false;
- } else {
- char *msg = dupprintf("unrecognised command-line option\n"
- "'%s'", p);
- MessageBox(NULL, msg, "Pageant command-line syntax error",
- MB_ICONERROR | MB_OK);
- exit(1);
- }
- } else {
- Filename *fn = filename_from_str(p);
- win_add_keyfile(fn, add_keys_encrypted);
- filename_free(fn);
- added_keys = true;
- }
- }
-
- /*
- * Forget any passphrase that we retained while going over
- * command line keyfiles.
- */
- pageant_forget_passphrases();
-
- if (command) {
- char *args;
- if (command[0] == '"')
- args = strchr(++command, '"');
- else
- args = strchr(command, ' ');
- if (args) {
- *args++ = 0;
- while(*args && isspace(*args)) args++;
- }
- spawn_cmd(command, args, show);
- }
-
- /*
- * If Pageant was already running, we leave now. If we haven't
- * even taken any auxiliary action (spawned a command or added
- * keys), complain.
- */
- if (already_running) {
- if (!command && !added_keys) {
- MessageBox(NULL, "Pageant is already running", "Pageant Error",
- MB_ICONERROR | MB_OK);
- }
- return 0;
- }
-
-#if !defined NO_SECURITY
-
- /*
- * Set up a named-pipe listener.
- */
- {
- Plug *pl_plug;
- wpc->plc.vt = &winpgnt_vtable;
- wpc->plc.suppress_logging = true;
- struct pageant_listen_state *pl =
- pageant_listener_new(&pl_plug, &wpc->plc);
- char *pipename = agent_named_pipe_name();
- Socket *sock = new_named_pipe_listener(pipename, pl_plug);
- if (sk_socket_error(sock)) {
- char *err = dupprintf("Unable to open named pipe at %s "
- "for SSH agent:\n%s", pipename,
- sk_socket_error(sock));
- MessageBox(NULL, err, "Pageant Error", MB_ICONERROR | MB_OK);
- return 1;
- }
- pageant_listener_got_socket(pl, sock);
- sfree(pipename);
- }
-
-#endif /* !defined NO_SECURITY */
-
- /*
- * Set up window classes for two hidden windows: one that receives
- * all the messages to do with our presence in the system tray,
- * and one that receives the WM_COPYDATA message used by the
- * old-style Pageant IPC system.
- */
-
- if (!prev) {
- WNDCLASS wndclass;
-
- memset(&wndclass, 0, sizeof(wndclass));
- wndclass.lpfnWndProc = TrayWndProc;
- wndclass.hInstance = inst;
- wndclass.hIcon = LoadIcon(inst, MAKEINTRESOURCE(IDI_MAINICON));
- wndclass.lpszClassName = TRAYCLASSNAME;
-
- RegisterClass(&wndclass);
-
- memset(&wndclass, 0, sizeof(wndclass));
- wndclass.lpfnWndProc = wm_copydata_WndProc;
- wndclass.hInstance = inst;
- wndclass.lpszClassName = IPCCLASSNAME;
-
- RegisterClass(&wndclass);
- }
-
- keylist = NULL;
-
- traywindow = CreateWindow(TRAYCLASSNAME, TRAYWINTITLE,
- WS_OVERLAPPEDWINDOW | WS_VSCROLL,
- CW_USEDEFAULT, CW_USEDEFAULT,
- 100, 100, NULL, NULL, inst, NULL);
- winselgui_set_hwnd(traywindow);
-
- /* Set up a system tray icon */
- AddTrayIcon(traywindow);
-
- /* Accelerators used: nsvkxa */
- systray_menu = CreatePopupMenu();
- if (putty_path) {
- session_menu = CreateMenu();
- AppendMenu(systray_menu, MF_ENABLED, IDM_PUTTY, "&New Session");
- AppendMenu(systray_menu, MF_POPUP | MF_ENABLED,
- (UINT_PTR) session_menu, "&Saved Sessions");
- AppendMenu(systray_menu, MF_SEPARATOR, 0, 0);
- }
- AppendMenu(systray_menu, MF_ENABLED, IDM_VIEWKEYS,
- "&View Keys");
- AppendMenu(systray_menu, MF_ENABLED, IDM_ADDKEY, "Add &Key");
- AppendMenu(systray_menu, MF_ENABLED, IDM_ADDKEY_ENCRYPTED,
- "Add key (encrypted)");
- AppendMenu(systray_menu, MF_SEPARATOR, 0, 0);
- AppendMenu(systray_menu, MF_ENABLED, IDM_REMOVE_ALL,
- "Remove All Keys");
- AppendMenu(systray_menu, MF_ENABLED, IDM_REENCRYPT_ALL,
- "Re-encrypt All Keys");
- AppendMenu(systray_menu, MF_SEPARATOR, 0, 0);
- if (has_help())
- AppendMenu(systray_menu, MF_ENABLED, IDM_HELP, "&Help");
- AppendMenu(systray_menu, MF_ENABLED, IDM_ABOUT, "&About");
- AppendMenu(systray_menu, MF_SEPARATOR, 0, 0);
- AppendMenu(systray_menu, MF_ENABLED, IDM_CLOSE, "E&xit");
- initial_menuitems_count = GetMenuItemCount(session_menu);
-
- /* Set the default menu item. */
- SetMenuDefaultItem(systray_menu, IDM_VIEWKEYS, false);
-
- ShowWindow(traywindow, SW_HIDE);
-
- wmcpc.vt = &wmcpc_vtable;
- wmcpc.suppress_logging = true;
- pageant_register_client(&wmcpc);
- DWORD wm_copydata_threadid;
- wmct.ev_msg_ready = CreateEvent(NULL, false, false, NULL);
- wmct.ev_reply_ready = CreateEvent(NULL, false, false, NULL);
- HANDLE hThread = CreateThread(NULL, 0, wm_copydata_threadfunc,
- &inst, 0, &wm_copydata_threadid);
- if (hThread)
- CloseHandle(hThread); /* we don't need the thread handle */
- handle_add_foreign_event(wmct.ev_msg_ready, wm_copydata_got_msg, NULL);
-
- if (show_keylist_on_startup)
- create_keylist_window();
-
- /*
- * Main message loop.
- */
- while (true) {
- HANDLE *handles;
- int nhandles, n;
-
- handles = handle_get_events(&nhandles);
-
- n = MsgWaitForMultipleObjects(nhandles, handles, false,
- INFINITE, QS_ALLINPUT);
-
- if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) {
- handle_got_event(handles[n - WAIT_OBJECT_0]);
- sfree(handles);
- } else
- sfree(handles);
-
- while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
- if (msg.message == WM_QUIT)
- goto finished; /* two-level break */
-
- if (IsWindow(keylist) && IsDialogMessage(keylist, &msg))
- continue;
- if (IsWindow(aboutbox) && IsDialogMessage(aboutbox, &msg))
- continue;
- if (IsWindow(nonmodal_passphrase_hwnd) &&
- IsDialogMessage(nonmodal_passphrase_hwnd, &msg))
- continue;
-
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
-
- run_toplevel_callbacks();
- }
- finished:
-
- /* Clean up the system tray icon */
- {
- NOTIFYICONDATA tnid;
-
- tnid.cbSize = sizeof(NOTIFYICONDATA);
- tnid.hWnd = traywindow;
- tnid.uID = 1;
-
- Shell_NotifyIcon(NIM_DELETE, &tnid);
-
- DestroyMenu(systray_menu);
- }
-
- if (keypath) filereq_free(keypath);
-
- cleanup_exit(msg.wParam);
- return msg.wParam; /* just in case optimiser complains */
-}
diff --git a/WINDOWS/WINPGNTC.C b/WINDOWS/WINPGNTC.C
deleted file mode 100644
index 557dc532..00000000
--- a/WINDOWS/WINPGNTC.C
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * Pageant client code.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#include "putty.h"
-#include "pageant.h" /* for AGENT_MAX_MSGLEN */
-
-#ifndef NO_SECURITY
-#include "winsecur.h"
-#include "wincapi.h"
-#endif
-
-#define AGENT_COPYDATA_ID 0x804e50ba /* random goop */
-
-static bool wm_copydata_agent_exists(void)
-{
- HWND hwnd;
- hwnd = FindWindow("Pageant", "Pageant");
- if (!hwnd)
- return false;
- else
- return true;
-}
-
-static void wm_copydata_agent_query(strbuf *query, void **out, int *outlen)
-{
- HWND hwnd;
- char *mapname;
- HANDLE filemap;
- unsigned char *p, *ret;
- int id, retlen;
- COPYDATASTRUCT cds;
- SECURITY_ATTRIBUTES sa, *psa;
- PSECURITY_DESCRIPTOR psd = NULL;
- PSID usersid = NULL;
-
- *out = NULL;
- *outlen = 0;
-
- if (query->len > AGENT_MAX_MSGLEN)
- return; /* query too large */
-
- hwnd = FindWindow("Pageant", "Pageant");
- if (!hwnd)
- return; /* *out == NULL, so failure */
- mapname = dupprintf("PageantRequest%08x", (unsigned)GetCurrentThreadId());
-
- psa = NULL;
-#ifndef NO_SECURITY
- if (got_advapi()) {
- /*
- * Make the file mapping we create for communication with
- * Pageant owned by the user SID rather than the default. This
- * should make communication between processes with slightly
- * different contexts more reliable: in particular, command
- * prompts launched as administrator should still be able to
- * run PSFTPs which refer back to the owning user's
- * unprivileged Pageant.
- */
- usersid = get_user_sid();
-
- if (usersid) {
- psd = (PSECURITY_DESCRIPTOR)
- LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
- if (psd) {
- if (p_InitializeSecurityDescriptor
- (psd, SECURITY_DESCRIPTOR_REVISION) &&
- p_SetSecurityDescriptorOwner(psd, usersid, false)) {
- sa.nLength = sizeof(sa);
- sa.bInheritHandle = true;
- sa.lpSecurityDescriptor = psd;
- psa = &sa;
- } else {
- LocalFree(psd);
- psd = NULL;
- }
- }
- }
- }
-#endif /* NO_SECURITY */
-
- filemap = CreateFileMapping(INVALID_HANDLE_VALUE, psa, PAGE_READWRITE,
- 0, AGENT_MAX_MSGLEN, mapname);
- if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) {
- sfree(mapname);
- return; /* *out == NULL, so failure */
- }
- p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0);
- strbuf_finalise_agent_query(query);
- memcpy(p, query->s, query->len);
- cds.dwData = AGENT_COPYDATA_ID;
- cds.cbData = 1 + strlen(mapname);
- cds.lpData = mapname;
-
- /*
- * The user either passed a null callback (indicating that the
- * query is required to be synchronous) or CreateThread failed.
- * Either way, we need a synchronous request.
- */
- id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds);
- if (id > 0) {
- uint32_t length_field = GET_32BIT_MSB_FIRST(p);
- if (length_field > 0 && length_field <= AGENT_MAX_MSGLEN - 4) {
- retlen = length_field + 4;
- ret = snewn(retlen, unsigned char);
- memcpy(ret, p, retlen);
- *out = ret;
- *outlen = retlen;
- } else {
- /*
- * If we get here, we received an out-of-range length
- * field, either without space for a message type code or
- * overflowing the FileMapping.
- *
- * Treat this as if Pageant didn't answer at all - which
- * actually means we do nothing, and just don't fill in
- * out and outlen.
- */
- }
- }
- UnmapViewOfFile(p);
- CloseHandle(filemap);
- sfree(mapname);
- if (psd)
- LocalFree(psd);
-}
-
-#ifndef NO_SECURITY
-
-char *agent_named_pipe_name(void)
-{
- char *username, *suffix, *pipename;
- username = get_username();
- suffix = capi_obfuscate_string("Pageant");
- pipename = dupprintf("\\\\.\\pipe\\pageant.%s.%s", username, suffix);
- sfree(username);
- sfree(suffix);
- return pipename;
-}
-
-Socket *agent_connect(Plug *plug)
-{
- char *pipename = agent_named_pipe_name();
- Socket *s = new_named_pipe_client(pipename, plug);
- sfree(pipename);
- return s;
-}
-
-static bool named_pipe_agent_exists(void)
-{
- char *pipename = agent_named_pipe_name();
- WIN32_FIND_DATA data;
- HANDLE ffh = FindFirstFile(pipename, &data);
- sfree(pipename);
- if (ffh == INVALID_HANDLE_VALUE)
- return false;
- FindClose(ffh);
- return true;
-}
-
-bool agent_exists(void)
-{
- return named_pipe_agent_exists() || wm_copydata_agent_exists();
-}
-
-struct agent_pending_query {
- struct handle *handle;
- HANDLE os_handle;
- strbuf *response;
- void (*callback)(void *, void *, int);
- void *callback_ctx;
-};
-
-static int named_pipe_agent_accumulate_response(
- strbuf *sb, const void *data, size_t len)
-{
- put_data(sb, data, len);
- if (sb->len >= 4) {
- uint32_t length_field = GET_32BIT_MSB_FIRST(sb->u);
- if (length_field > AGENT_MAX_MSGLEN)
- return -1; /* badly formatted message */
-
- int overall_length = length_field + 4;
- if (sb->len >= overall_length)
- return overall_length;
- }
-
- return 0; /* not done yet */
-}
-
-static size_t named_pipe_agent_gotdata(
- struct handle *h, const void *data, size_t len, int err)
-{
- agent_pending_query *pq = handle_get_privdata(h);
-
- if (err || len == 0) {
- pq->callback(pq->callback_ctx, NULL, 0);
- agent_cancel_query(pq);
- return 0;
- }
-
- int status = named_pipe_agent_accumulate_response(pq->response, data, len);
- if (status == -1) {
- pq->callback(pq->callback_ctx, NULL, 0);
- agent_cancel_query(pq);
- } else if (status > 0) {
- void *response_buf = strbuf_to_str(pq->response);
- pq->response = NULL;
- pq->callback(pq->callback_ctx, response_buf, status);
- agent_cancel_query(pq);
- }
- return 0;
-}
-
-static agent_pending_query *named_pipe_agent_query(
- strbuf *query, void **out, int *outlen,
- void (*callback)(void *, void *, int), void *callback_ctx)
-{
- agent_pending_query *pq = NULL;
- char *err = NULL, *pipename = NULL;
- strbuf *sb = NULL;
- HANDLE pipehandle;
-
- pipename = agent_named_pipe_name();
- pipehandle = connect_to_named_pipe(pipename, &err);
- if (pipehandle == INVALID_HANDLE_VALUE)
- goto failure;
-
- strbuf_finalise_agent_query(query);
-
- for (DWORD done = 0; done < query->len ;) {
- DWORD nwritten;
- bool ret = WriteFile(pipehandle, query->s + done, query->len - done,
- &nwritten, NULL);
- if (!ret)
- goto failure;
-
- done += nwritten;
- }
-
- if (!callback) {
- int status;
-
- sb = strbuf_new_nm();
- do {
- char buf[1024];
- DWORD nread;
- bool ret = ReadFile(pipehandle, buf, sizeof(buf), &nread, NULL);
- if (!ret)
- goto failure;
- status = named_pipe_agent_accumulate_response(sb, buf, nread);
- } while (status == 0);
-
- if (status == -1)
- goto failure;
-
- *out = strbuf_to_str(sb);
- *outlen = status;
- sb = NULL;
- pq = NULL;
- goto out;
- }
-
- pq = snew(agent_pending_query);
- pq->handle = handle_input_new(pipehandle, named_pipe_agent_gotdata, pq, 0);
- pq->os_handle = pipehandle;
- pipehandle = INVALID_HANDLE_VALUE; /* prevent it being closed below */
- pq->response = strbuf_new_nm();
- pq->callback = callback;
- pq->callback_ctx = callback_ctx;
- goto out;
-
- failure:
- *out = NULL;
- *outlen = 0;
- pq = NULL;
-
- out:
- sfree(err);
- sfree(pipename);
- if (pipehandle != INVALID_HANDLE_VALUE)
- CloseHandle(pipehandle);
- if (sb)
- strbuf_free(sb);
- return pq;
-}
-
-void agent_cancel_query(agent_pending_query *pq)
-{
- handle_free(pq->handle);
- CloseHandle(pq->os_handle);
- if (pq->response)
- strbuf_free(pq->response);
- sfree(pq);
-}
-
-agent_pending_query *agent_query(
- strbuf *query, void **out, int *outlen,
- void (*callback)(void *, void *, int), void *callback_ctx)
-{
- agent_pending_query *pq = named_pipe_agent_query(
- query, out, outlen, callback, callback_ctx);
- if (pq || *out)
- return pq;
-
- wm_copydata_agent_query(query, out, outlen);
- return NULL;
-}
-
-#else /* NO_SECURITY */
-
-Socket *agent_connect(void *vctx, Plug *plug)
-{
- unreachable("no agent_connect_ctx can be constructed on this platform");
-}
-
-agent_connect_ctx *agent_get_connect_ctx(void)
-{
- return NULL;
-}
-
-void agent_free_connect_ctx(agent_connect_ctx *ctx)
-{
-}
-
-bool agent_exists(void)
-{
- return wm_copydata_agent_exists();
-}
-
-agent_pending_query *agent_query(
- strbuf *query, void **out, int *outlen,
- void (*callback)(void *, void *, int), void *callback_ctx)
-{
- wm_copydata_agent_query(query, out, outlen);
- return NULL;
-}
-
-void agent_cancel_query(agent_pending_query *q)
-{
- unreachable("Windows agent queries are never asynchronous!");
-}
-
-#endif /* NO_SECURITY */
diff --git a/WINDOWS/WINPLINK.C b/WINDOWS/WINPLINK.C
deleted file mode 100644
index 58d43e6d..00000000
--- a/WINDOWS/WINPLINK.C
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * PLink - a Windows command-line (stdin/stdout) variant of PuTTY.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <stdarg.h>
-
-#include "putty.h"
-#include "storage.h"
-#include "tree234.h"
-#include "winsecur.h"
-
-void cmdline_error(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- console_print_error_msg_fmt_v("plink", fmt, ap);
- va_end(ap);
- exit(1);
-}
-
-static HANDLE inhandle, outhandle, errhandle;
-static struct handle *stdin_handle, *stdout_handle, *stderr_handle;
-static handle_sink stdout_hs, stderr_hs;
-static StripCtrlChars *stdout_scc, *stderr_scc;
-static BinarySink *stdout_bs, *stderr_bs;
-static DWORD orig_console_mode;
-
-static Backend *backend;
-static LogContext *logctx;
-static Conf *conf;
-
-static void plink_echoedit_update(Seat *seat, bool echo, bool edit)
-{
- /* Update stdin read mode to reflect changes in line discipline. */
- DWORD mode;
-
- mode = ENABLE_PROCESSED_INPUT;
- if (echo)
- mode = mode | ENABLE_ECHO_INPUT;
- else
- mode = mode & ~ENABLE_ECHO_INPUT;
- if (edit)
- mode = mode | ENABLE_LINE_INPUT;
- else
- mode = mode & ~ENABLE_LINE_INPUT;
- SetConsoleMode(inhandle, mode);
-}
-
-static size_t plink_output(
- Seat *seat, bool is_stderr, const void *data, size_t len)
-{
- BinarySink *bs = is_stderr ? stderr_bs : stdout_bs;
- put_data(bs, data, len);
-
- return handle_backlog(stdout_handle) + handle_backlog(stderr_handle);
-}
-
-static bool plink_eof(Seat *seat)
-{
- handle_write_eof(stdout_handle);
- return false; /* do not respond to incoming EOF with outgoing */
-}
-
-static int plink_get_userpass_input(Seat *seat, prompts_t *p, bufchain *input)
-{
- int ret;
- ret = cmdline_get_passwd_input(p);
- if (ret == -1)
- ret = console_get_userpass_input(p);
- return ret;
-}
-
-static bool plink_seat_interactive(Seat *seat)
-{
- return (!*conf_get_str(conf, CONF_remote_cmd) &&
- !*conf_get_str(conf, CONF_remote_cmd2) &&
- !*conf_get_str(conf, CONF_ssh_nc_host));
-}
-
-static const SeatVtable plink_seat_vt = {
- .output = plink_output,
- .eof = plink_eof,
- .get_userpass_input = plink_get_userpass_input,
- .notify_remote_exit = nullseat_notify_remote_exit,
- .connection_fatal = console_connection_fatal,
- .update_specials_menu = nullseat_update_specials_menu,
- .get_ttymode = nullseat_get_ttymode,
- .set_busy_status = nullseat_set_busy_status,
- .verify_ssh_host_key = console_verify_ssh_host_key,
- .confirm_weak_crypto_primitive = console_confirm_weak_crypto_primitive,
- .confirm_weak_cached_hostkey = console_confirm_weak_cached_hostkey,
- .is_utf8 = nullseat_is_never_utf8,
- .echoedit_update = plink_echoedit_update,
- .get_x_display = nullseat_get_x_display,
- .get_windowid = nullseat_get_windowid,
- .get_window_pixel_size = nullseat_get_window_pixel_size,
- .stripctrl_new = console_stripctrl_new,
- .set_trust_status = console_set_trust_status,
- .verbose = cmdline_seat_verbose,
- .interactive = plink_seat_interactive,
- .get_cursor_position = nullseat_get_cursor_position,
-};
-static Seat plink_seat[1] = {{ &plink_seat_vt }};
-
-static DWORD main_thread_id;
-
-/*
- * Short description of parameters.
- */
-static void usage(void)
-{
- printf("Plink: command-line connection utility\n");
- printf("%s\n", ver);
- printf("Usage: plink [options] [user@]host [command]\n");
- printf(" (\"host\" can also be a PuTTY saved session name)\n");
- printf("Options:\n");
- printf(" -V print version information and exit\n");
- printf(" -pgpfp print PGP key fingerprints and exit\n");
- printf(" -v show verbose messages\n");
- printf(" -load sessname Load settings from saved session\n");
- printf(" -ssh -telnet -rlogin -raw -serial\n");
- printf(" force use of a particular protocol\n");
- printf(" -ssh-connection\n");
- printf(" force use of the bare ssh-connection protocol\n");
- printf(" -P port connect to specified port\n");
- printf(" -l user connect with specified username\n");
- printf(" -batch disable all interactive prompts\n");
- printf(" -proxycmd command\n");
- printf(" use 'command' as local proxy\n");
- printf(" -sercfg configuration-string (e.g. 19200,8,n,1,X)\n");
- printf(" Specify the serial configuration (serial only)\n");
- printf("The following options only apply to SSH connections:\n");
- printf(" -pw passw login with specified password\n");
- printf(" -D [listen-IP:]listen-port\n");
- printf(" Dynamic SOCKS-based port forwarding\n");
- printf(" -L [listen-IP:]listen-port:host:port\n");
- printf(" Forward local port to remote address\n");
- printf(" -R [listen-IP:]listen-port:host:port\n");
- printf(" Forward remote port to local address\n");
- printf(" -X -x enable / disable X11 forwarding\n");
- printf(" -A -a enable / disable agent forwarding\n");
- printf(" -t -T enable / disable pty allocation\n");
- printf(" -1 -2 force use of particular SSH protocol version\n");
- printf(" -4 -6 force use of IPv4 or IPv6\n");
- printf(" -C enable compression\n");
- printf(" -i key private key file for user authentication\n");
- printf(" -noagent disable use of Pageant\n");
- printf(" -agent enable use of Pageant\n");
- printf(" -no-trivial-auth\n");
- printf(" disconnect if SSH authentication succeeds trivially\n");
- printf(" -noshare disable use of connection sharing\n");
- printf(" -share enable use of connection sharing\n");
- printf(" -hostkey keyid\n");
- printf(" manually specify a host key (may be repeated)\n");
- printf(" -sanitise-stderr, -sanitise-stdout, "
- "-no-sanitise-stderr, -no-sanitise-stdout\n");
- printf(" do/don't strip control chars from standard "
- "output/error\n");
- printf(" -no-antispoof omit anti-spoofing prompt after "
- "authentication\n");
- printf(" -m file read remote command(s) from file\n");
- printf(" -s remote command is an SSH subsystem (SSH-2 only)\n");
- printf(" -N don't start a shell/command (SSH-2 only)\n");
- printf(" -nc host:port\n");
- printf(" open tunnel in place of session (SSH-2 only)\n");
- printf(" -sshlog file\n");
- printf(" -sshrawlog file\n");
- printf(" log protocol details to a file\n");
- printf(" -logoverwrite\n");
- printf(" -logappend\n");
- printf(" control what happens when a log file already exists\n");
- printf(" -shareexists\n");
- printf(" test whether a connection-sharing upstream exists\n");
- exit(1);
-}
-
-static void version(void)
-{
- char *buildinfo_text = buildinfo("\n");
- printf("plink: %s\n%s\n", ver, buildinfo_text);
- sfree(buildinfo_text);
- exit(0);
-}
-
-size_t stdin_gotdata(struct handle *h, const void *data, size_t len, int err)
-{
- if (err) {
- char buf[4096];
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0,
- buf, lenof(buf), NULL);
- buf[lenof(buf)-1] = '\0';
- if (buf[strlen(buf)-1] == '\n')
- buf[strlen(buf)-1] = '\0';
- fprintf(stderr, "Unable to read from standard input: %s\n", buf);
- cleanup_exit(0);
- }
-
- noise_ultralight(NOISE_SOURCE_IOLEN, len);
- if (backend_connected(backend)) {
- if (len > 0) {
- return backend_send(backend, data, len);
- } else {
- backend_special(backend, SS_EOF, 0);
- return 0;
- }
- } else
- return 0;
-}
-
-void stdouterr_sent(struct handle *h, size_t new_backlog, int err)
-{
- if (err) {
- char buf[4096];
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0,
- buf, lenof(buf), NULL);
- buf[lenof(buf)-1] = '\0';
- if (buf[strlen(buf)-1] == '\n')
- buf[strlen(buf)-1] = '\0';
- fprintf(stderr, "Unable to write to standard %s: %s\n",
- (h == stdout_handle ? "output" : "error"), buf);
- cleanup_exit(0);
- }
-
- if (backend_connected(backend)) {
- backend_unthrottle(backend, (handle_backlog(stdout_handle) +
- handle_backlog(stderr_handle)));
- }
-}
-
-const bool share_can_be_downstream = true;
-const bool share_can_be_upstream = true;
-
-const unsigned cmdline_tooltype =
- TOOLTYPE_HOST_ARG |
- TOOLTYPE_HOST_ARG_CAN_BE_SESSION |
- TOOLTYPE_HOST_ARG_PROTOCOL_PREFIX |
- TOOLTYPE_HOST_ARG_FROM_LAUNCHABLE_LOAD;
-
-static bool sending;
-
-static bool plink_mainloop_pre(void *vctx, const HANDLE **extra_handles,
- size_t *n_extra_handles)
-{
- if (!sending && backend_sendok(backend)) {
- stdin_handle = handle_input_new(inhandle, stdin_gotdata, NULL,
- 0);
- sending = true;
- }
-
- return true;
-}
-
-static bool plink_mainloop_post(void *vctx, size_t extra_handle_index)
-{
- if (sending)
- handle_unthrottle(stdin_handle, backend_sendbuffer(backend));
-
- if (!backend_connected(backend) &&
- handle_backlog(stdout_handle) + handle_backlog(stderr_handle) == 0)
- return false; /* we closed the connection */
-
- return true;
-}
-
-int main(int argc, char **argv)
-{
- int exitcode;
- bool errors;
- bool use_subsystem = false;
- bool just_test_share_exists = false;
- enum TriState sanitise_stdout = AUTO, sanitise_stderr = AUTO;
- const struct BackendVtable *vt;
-
- dll_hijacking_protection();
-
- /*
- * Initialise port and protocol to sensible defaults. (These
- * will be overridden by more or less anything.)
- */
- settings_set_default_protocol(PROT_SSH);
- settings_set_default_port(22);
-
- /*
- * Process the command line.
- */
- conf = conf_new();
- do_defaults(NULL, conf);
- settings_set_default_protocol(conf_get_int(conf, CONF_protocol));
- settings_set_default_port(conf_get_int(conf, CONF_port));
- errors = false;
- {
- /*
- * Override the default protocol if PLINK_PROTOCOL is set.
- */
- char *p = getenv("PLINK_PROTOCOL");
- if (p) {
- const struct BackendVtable *vt = backend_vt_from_name(p);
- if (vt) {
- settings_set_default_protocol(vt->protocol);
- settings_set_default_port(vt->default_port);
- conf_set_int(conf, CONF_protocol, vt->protocol);
- conf_set_int(conf, CONF_port, vt->default_port);
- }
- }
- }
- while (--argc) {
- char *p = *++argv;
- int ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL),
- 1, conf);
- if (ret == -2) {
- fprintf(stderr,
- "plink: option \"%s\" requires an argument\n", p);
- errors = true;
- } else if (ret == 2) {
- --argc, ++argv;
- } else if (ret == 1) {
- continue;
- } else if (!strcmp(p, "-batch")) {
- console_batch_mode = true;
- } else if (!strcmp(p, "-s")) {
- /* Save status to write to conf later. */
- use_subsystem = true;
- } else if (!strcmp(p, "-V") || !strcmp(p, "--version")) {
- version();
- } else if (!strcmp(p, "--help")) {
- usage();
- } else if (!strcmp(p, "-pgpfp")) {
- pgp_fingerprints();
- exit(1);
- } else if (!strcmp(p, "-shareexists")) {
- just_test_share_exists = true;
- } else if (!strcmp(p, "-sanitise-stdout") ||
- !strcmp(p, "-sanitize-stdout")) {
- sanitise_stdout = FORCE_ON;
- } else if (!strcmp(p, "-no-sanitise-stdout") ||
- !strcmp(p, "-no-sanitize-stdout")) {
- sanitise_stdout = FORCE_OFF;
- } else if (!strcmp(p, "-sanitise-stderr") ||
- !strcmp(p, "-sanitize-stderr")) {
- sanitise_stderr = FORCE_ON;
- } else if (!strcmp(p, "-no-sanitise-stderr") ||
- !strcmp(p, "-no-sanitize-stderr")) {
- sanitise_stderr = FORCE_OFF;
- } else if (!strcmp(p, "-no-antispoof")) {
- console_antispoof_prompt = false;
- } else if (*p != '-') {
- strbuf *cmdbuf = strbuf_new();
-
- while (argc > 0) {
- if (cmdbuf->len > 0)
- put_byte(cmdbuf, ' '); /* add space separator */
- put_datapl(cmdbuf, ptrlen_from_asciz(p));
- if (--argc > 0)
- p = *++argv;
- }
-
- conf_set_str(conf, CONF_remote_cmd, cmdbuf->s);
- conf_set_str(conf, CONF_remote_cmd2, "");
- conf_set_bool(conf, CONF_nopty, true); /* command => no tty */
-
- strbuf_free(cmdbuf);
- break; /* done with cmdline */
- } else {
- fprintf(stderr, "plink: unknown option \"%s\"\n", p);
- errors = true;
- }
- }
-
- if (errors)
- return 1;
-
- if (!cmdline_host_ok(conf)) {
- usage();
- }
-
- prepare_session(conf);
-
- /*
- * Perform command-line overrides on session configuration.
- */
- cmdline_run_saved(conf);
-
- /*
- * Apply subsystem status.
- */
- if (use_subsystem)
- conf_set_bool(conf, CONF_ssh_subsys, true);
-
- /*
- * Select protocol. This is farmed out into a table in a
- * separate file to enable an ssh-free variant.
- */
- vt = backend_vt_from_proto(conf_get_int(conf, CONF_protocol));
- if (vt == NULL) {
- fprintf(stderr,
- "Internal fault: Unsupported protocol found\n");
- return 1;
- }
-
- if (vt->flags & BACKEND_NEEDS_TERMINAL) {
- fprintf(stderr,
- "Plink doesn't support %s, which needs terminal emulation\n",
- vt->displayname);
- return 1;
- }
-
- sk_init();
- if (p_WSAEventSelect == NULL) {
- fprintf(stderr, "Plink requires WinSock 2\n");
- return 1;
- }
-
- /*
- * Plink doesn't provide any way to add forwardings after the
- * connection is set up, so if there are none now, we can safely set
- * the "simple" flag.
- */
- if (conf_get_int(conf, CONF_protocol) == PROT_SSH &&
- !conf_get_bool(conf, CONF_x11_forward) &&
- !conf_get_bool(conf, CONF_agentfwd) &&
- !conf_get_str_nthstrkey(conf, CONF_portfwd, 0))
- conf_set_bool(conf, CONF_ssh_simple, true);
-
- logctx = log_init(console_cli_logpolicy, conf);
-
- if (just_test_share_exists) {
- if (!vt->test_for_upstream) {
- fprintf(stderr, "Connection sharing not supported for this "
- "connection type (%s)'\n", vt->displayname);
- return 1;
- }
- if (vt->test_for_upstream(conf_get_str(conf, CONF_host),
- conf_get_int(conf, CONF_port), conf))
- return 0;
- else
- return 1;
- }
-
- if (restricted_acl()) {
- lp_eventlog(console_cli_logpolicy,
- "Running with restricted process ACL");
- }
-
- inhandle = GetStdHandle(STD_INPUT_HANDLE);
- outhandle = GetStdHandle(STD_OUTPUT_HANDLE);
- errhandle = GetStdHandle(STD_ERROR_HANDLE);
-
- /*
- * Turn off ECHO and LINE input modes. We don't care if this
- * call fails, because we know we aren't necessarily running in
- * a console.
- */
- GetConsoleMode(inhandle, &orig_console_mode);
- SetConsoleMode(inhandle, ENABLE_PROCESSED_INPUT);
-
- /*
- * Pass the output handles to the handle-handling subsystem.
- * (The input one we leave until we're through the
- * authentication process.)
- */
- stdout_handle = handle_output_new(outhandle, stdouterr_sent, NULL, 0);
- stderr_handle = handle_output_new(errhandle, stdouterr_sent, NULL, 0);
- handle_sink_init(&stdout_hs, stdout_handle);
- handle_sink_init(&stderr_hs, stderr_handle);
- stdout_bs = BinarySink_UPCAST(&stdout_hs);
- stderr_bs = BinarySink_UPCAST(&stderr_hs);
-
- /*
- * Decide whether to sanitise control sequences out of standard
- * output and standard error.
- *
- * If we weren't given a command-line override, we do this if (a)
- * the fd in question is pointing at a console, and (b) we aren't
- * trying to allocate a terminal as part of the session.
- *
- * (Rationale: the risk of control sequences is that they cause
- * confusion when sent to a local console, so if there isn't one,
- * no problem. Also, if we allocate a remote terminal, then we
- * sent a terminal type, i.e. we told it what kind of escape
- * sequences we _like_, i.e. we were expecting to receive some.)
- */
- if (sanitise_stdout == FORCE_ON ||
- (sanitise_stdout == AUTO && is_console_handle(outhandle) &&
- conf_get_bool(conf, CONF_nopty))) {
- stdout_scc = stripctrl_new(stdout_bs, true, L'\0');
- stdout_bs = BinarySink_UPCAST(stdout_scc);
- }
- if (sanitise_stderr == FORCE_ON ||
- (sanitise_stderr == AUTO && is_console_handle(errhandle) &&
- conf_get_bool(conf, CONF_nopty))) {
- stderr_scc = stripctrl_new(stderr_bs, true, L'\0');
- stderr_bs = BinarySink_UPCAST(stderr_scc);
- }
-
- /*
- * Start up the connection.
- */
- winselcli_setup(); /* ensure event object exists */
- {
- char *error, *realhost;
- /* nodelay is only useful if stdin is a character device (console) */
- bool nodelay = conf_get_bool(conf, CONF_tcp_nodelay) &&
- (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR);
-
- error = backend_init(vt, plink_seat, &backend, logctx, conf,
- conf_get_str(conf, CONF_host),
- conf_get_int(conf, CONF_port),
- &realhost, nodelay,
- conf_get_bool(conf, CONF_tcp_keepalives));
- if (error) {
- fprintf(stderr, "Unable to open connection:\n%s", error);
- sfree(error);
- return 1;
- }
- ldisc_create(conf, NULL, backend, plink_seat);
- sfree(realhost);
- }
-
- main_thread_id = GetCurrentThreadId();
-
- sending = false;
-
- cli_main_loop(plink_mainloop_pre, plink_mainloop_post, NULL);
-
- exitcode = backend_exitcode(backend);
- if (exitcode < 0) {
- fprintf(stderr, "Remote process exit code unavailable\n");
- exitcode = 1; /* this is an error condition */
- }
- cleanup_exit(exitcode);
- return 0; /* placate compiler warning */
-}
diff --git a/WINDOWS/WINPRINT.C b/WINDOWS/WINPRINT.C
deleted file mode 100644
index e6b3531d..00000000
--- a/WINDOWS/WINPRINT.C
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Printing interface for PuTTY.
- */
-
-#include "putty.h"
-#include <winspool.h>
-
-struct printer_enum_tag {
- int nprinters;
- DWORD enum_level;
- union {
- LPPRINTER_INFO_4 i4;
- LPPRINTER_INFO_5 i5;
- } info;
-};
-
-struct printer_job_tag {
- HANDLE hprinter;
-};
-
-DECL_WINDOWS_FUNCTION(static, BOOL, EnumPrinters,
- (DWORD, LPTSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD));
-DECL_WINDOWS_FUNCTION(static, BOOL, OpenPrinter,
- (LPTSTR, LPHANDLE, LPPRINTER_DEFAULTS));
-DECL_WINDOWS_FUNCTION(static, BOOL, ClosePrinter, (HANDLE));
-DECL_WINDOWS_FUNCTION(static, DWORD, StartDocPrinter, (HANDLE, DWORD, LPBYTE));
-DECL_WINDOWS_FUNCTION(static, BOOL, EndDocPrinter, (HANDLE));
-DECL_WINDOWS_FUNCTION(static, BOOL, StartPagePrinter, (HANDLE));
-DECL_WINDOWS_FUNCTION(static, BOOL, EndPagePrinter, (HANDLE));
-DECL_WINDOWS_FUNCTION(static, BOOL, WritePrinter,
- (HANDLE, LPVOID, DWORD, LPDWORD));
-
-static void init_winfuncs(void)
-{
- static bool initialised = false;
- if (initialised)
- return;
- {
- HMODULE winspool_module = load_system32_dll("winspool.drv");
- /* Some MSDN documentation claims that some of the below functions
- * should be loaded from spoolss.dll, but this doesn't seem to
- * be reliable in practice.
- * Nevertheless, we load spoolss.dll ourselves using our safe
- * loading method, against the possibility that winspool.drv
- * later loads it unsafely. */
- (void) load_system32_dll("spoolss.dll");
- GET_WINDOWS_FUNCTION_PP(winspool_module, EnumPrinters);
- GET_WINDOWS_FUNCTION_PP(winspool_module, OpenPrinter);
- GET_WINDOWS_FUNCTION_PP(winspool_module, ClosePrinter);
- GET_WINDOWS_FUNCTION_PP(winspool_module, StartDocPrinter);
- GET_WINDOWS_FUNCTION_PP(winspool_module, EndDocPrinter);
- GET_WINDOWS_FUNCTION_PP(winspool_module, StartPagePrinter);
- GET_WINDOWS_FUNCTION_PP(winspool_module, EndPagePrinter);
- GET_WINDOWS_FUNCTION_PP(winspool_module, WritePrinter);
- }
- initialised = true;
-}
-
-static bool printer_add_enum(int param, DWORD level, char **buffer,
- int offset, int *nprinters_ptr)
-{
- DWORD needed = 0, nprinters = 0;
-
- init_winfuncs();
-
- *buffer = sresize(*buffer, offset+512, char);
-
- /*
- * Exploratory call to EnumPrinters to determine how much space
- * we'll need for the output. Discard the return value since it
- * will almost certainly be a failure due to lack of space.
- */
- p_EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset), 512,
- &needed, &nprinters);
-
- if (needed < 512)
- needed = 512;
-
- *buffer = sresize(*buffer, offset+needed, char);
-
- if (p_EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset),
- needed, &needed, &nprinters) == 0)
- return false;
-
- *nprinters_ptr += nprinters;
-
- return true;
-}
-
-printer_enum *printer_start_enum(int *nprinters_ptr)
-{
- printer_enum *ret = snew(printer_enum);
- char *buffer = NULL;
-
- *nprinters_ptr = 0; /* default return value */
- buffer = snewn(512, char);
-
- /*
- * Determine what enumeration level to use.
- * When enumerating printers, we need to use PRINTER_INFO_4 on
- * NT-class systems to avoid Windows looking too hard for them and
- * slowing things down; and we need to avoid PRINTER_INFO_5 as
- * we've seen network printers not show up.
- * On 9x-class systems, PRINTER_INFO_4 isn't available and
- * PRINTER_INFO_5 is recommended.
- * Bletch.
- */
- if (osPlatformId != VER_PLATFORM_WIN32_NT) {
- ret->enum_level = 5;
- } else {
- ret->enum_level = 4;
- }
-
- if (!printer_add_enum(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
- ret->enum_level, &buffer, 0, nprinters_ptr))
- goto error;
-
- switch (ret->enum_level) {
- case 4:
- ret->info.i4 = (LPPRINTER_INFO_4)buffer;
- break;
- case 5:
- ret->info.i5 = (LPPRINTER_INFO_5)buffer;
- break;
- }
- ret->nprinters = *nprinters_ptr;
-
- return ret;
-
- error:
- sfree(buffer);
- sfree(ret);
- *nprinters_ptr = 0;
- return NULL;
-}
-
-char *printer_get_name(printer_enum *pe, int i)
-{
- if (!pe)
- return NULL;
- if (i < 0 || i >= pe->nprinters)
- return NULL;
- switch (pe->enum_level) {
- case 4:
- return pe->info.i4[i].pPrinterName;
- case 5:
- return pe->info.i5[i].pPrinterName;
- default:
- return NULL;
- }
-}
-
-void printer_finish_enum(printer_enum *pe)
-{
- if (!pe)
- return;
- switch (pe->enum_level) {
- case 4:
- sfree(pe->info.i4);
- break;
- case 5:
- sfree(pe->info.i5);
- break;
- }
- sfree(pe);
-}
-
-printer_job *printer_start_job(char *printer)
-{
- printer_job *ret = snew(printer_job);
- DOC_INFO_1 docinfo;
- bool jobstarted = false, pagestarted = false;
-
- init_winfuncs();
-
- ret->hprinter = NULL;
- if (!p_OpenPrinter(printer, &ret->hprinter, NULL))
- goto error;
-
- docinfo.pDocName = "PuTTY remote printer output";
- docinfo.pOutputFile = NULL;
- docinfo.pDatatype = "RAW";
-
- if (!p_StartDocPrinter(ret->hprinter, 1, (LPBYTE)&docinfo))
- goto error;
- jobstarted = true;
-
- if (!p_StartPagePrinter(ret->hprinter))
- goto error;
- pagestarted = true;
-
- return ret;
-
- error:
- if (pagestarted)
- p_EndPagePrinter(ret->hprinter);
- if (jobstarted)
- p_EndDocPrinter(ret->hprinter);
- if (ret->hprinter)
- p_ClosePrinter(ret->hprinter);
- sfree(ret);
- return NULL;
-}
-
-void printer_job_data(printer_job *pj, const void *data, size_t len)
-{
- DWORD written;
-
- if (!pj)
- return;
-
- p_WritePrinter(pj->hprinter, (void *)data, len, &written);
-}
-
-void printer_finish_job(printer_job *pj)
-{
- if (!pj)
- return;
-
- p_EndPagePrinter(pj->hprinter);
- p_EndDocPrinter(pj->hprinter);
- p_ClosePrinter(pj->hprinter);
- sfree(pj);
-}
diff --git a/WINDOWS/WINPROXY.C b/WINDOWS/WINPROXY.C
deleted file mode 100644
index 94e31fcb..00000000
--- a/WINDOWS/WINPROXY.C
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * winproxy.c: Windows implementation of platform_new_connection(),
- * supporting an OpenSSH-like proxy command via the winhandl.c
- * mechanism.
- */
-
-#include <stdio.h>
-#include <assert.h>
-
-#include "tree234.h"
-#include "putty.h"
-#include "network.h"
-#include "proxy.h"
-
-Socket *platform_new_connection(SockAddr *addr, const char *hostname,
- int port, bool privport,
- bool oobinline, bool nodelay, bool keepalive,
- Plug *plug, Conf *conf)
-{
- char *cmd;
- HANDLE us_to_cmd, cmd_from_us;
- HANDLE us_from_cmd, cmd_to_us;
- HANDLE us_from_cmd_err, cmd_err_to_us;
- SECURITY_ATTRIBUTES sa;
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
-
- if (conf_get_int(conf, CONF_proxy_type) != PROXY_CMD)
- return NULL;
-
- cmd = format_telnet_command(addr, port, conf);
-
- /* We are responsible for this and don't need it any more */
- sk_addr_free(addr);
-
- {
- char *msg = dupprintf("Starting local proxy command: %s", cmd);
- plug_log(plug, PLUGLOG_PROXY_MSG, NULL, 0, msg, 0);
- sfree(msg);
- }
-
- /*
- * Create the pipes to the proxy command, and spawn the proxy
- * command process.
- */
- sa.nLength = sizeof(sa);
- sa.lpSecurityDescriptor = NULL; /* default */
- sa.bInheritHandle = true;
- if (!CreatePipe(&us_from_cmd, &cmd_to_us, &sa, 0)) {
- sfree(cmd);
- return new_error_socket_fmt(
- plug, "Unable to create pipes for proxy command: %s",
- win_strerror(GetLastError()));
- }
-
- if (!CreatePipe(&cmd_from_us, &us_to_cmd, &sa, 0)) {
- sfree(cmd);
- CloseHandle(us_from_cmd);
- CloseHandle(cmd_to_us);
- return new_error_socket_fmt(
- plug, "Unable to create pipes for proxy command: %s",
- win_strerror(GetLastError()));
- }
-
- if (!CreatePipe(&us_from_cmd_err, &cmd_err_to_us, &sa, 0)) {
- sfree(cmd);
- CloseHandle(us_from_cmd);
- CloseHandle(cmd_to_us);
- CloseHandle(us_to_cmd);
- CloseHandle(cmd_from_us);
- return new_error_socket_fmt(
- plug, "Unable to create pipes for proxy command: %s",
- win_strerror(GetLastError()));
- }
-
- SetHandleInformation(us_to_cmd, HANDLE_FLAG_INHERIT, 0);
- SetHandleInformation(us_from_cmd, HANDLE_FLAG_INHERIT, 0);
- if (us_from_cmd_err != NULL)
- SetHandleInformation(us_from_cmd_err, HANDLE_FLAG_INHERIT, 0);
-
- si.cb = sizeof(si);
- si.lpReserved = NULL;
- si.lpDesktop = NULL;
- si.lpTitle = NULL;
- si.dwFlags = STARTF_USESTDHANDLES;
- si.cbReserved2 = 0;
- si.lpReserved2 = NULL;
- si.hStdInput = cmd_from_us;
- si.hStdOutput = cmd_to_us;
- si.hStdError = cmd_err_to_us;
- CreateProcess(NULL, cmd, NULL, NULL, true,
- CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS,
- NULL, NULL, &si, &pi);
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
-
- sfree(cmd);
-
- CloseHandle(cmd_from_us);
- CloseHandle(cmd_to_us);
-
- if (cmd_err_to_us != NULL)
- CloseHandle(cmd_err_to_us);
-
- return make_handle_socket(us_to_cmd, us_from_cmd, us_from_cmd_err,
- plug, false);
-}
diff --git a/WINDOWS/WINSER.C b/WINDOWS/WINSER.C
deleted file mode 100644
index 7f4bcf2e..00000000
--- a/WINDOWS/WINSER.C
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * Serial back end (Windows-specific).
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-
-#include "putty.h"
-
-#define SERIAL_MAX_BACKLOG 4096
-
-typedef struct Serial Serial;
-struct Serial {
- HANDLE port;
- struct handle *out, *in;
- Seat *seat;
- LogContext *logctx;
- int bufsize;
- long clearbreak_time;
- bool break_in_progress;
- Backend backend;
-};
-
-static void serial_terminate(Serial *serial)
-{
- if (serial->out) {
- handle_free(serial->out);
- serial->out = NULL;
- }
- if (serial->in) {
- handle_free(serial->in);
- serial->in = NULL;
- }
- if (serial->port != INVALID_HANDLE_VALUE) {
- if (serial->break_in_progress)
- ClearCommBreak(serial->port);
- CloseHandle(serial->port);
- serial->port = INVALID_HANDLE_VALUE;
- }
-}
-
-static size_t serial_gotdata(
- struct handle *h, const void *data, size_t len, int err)
-{
- Serial *serial = (Serial *)handle_get_privdata(h);
- if (err || len == 0) {
- const char *error_msg;
-
- /*
- * Currently, len==0 should never happen because we're
- * ignoring EOFs. However, it seems not totally impossible
- * that this same back end might be usable to talk to named
- * pipes or some other non-serial device, in which case EOF
- * may become meaningful here.
- */
- if (!err)
- error_msg = "End of file reading from serial device";
- else
- error_msg = "Error reading from serial device";
-
- serial_terminate(serial);
-
- seat_notify_remote_exit(serial->seat);
-
- logevent(serial->logctx, error_msg);
-
- seat_connection_fatal(serial->seat, "%s", error_msg);
-
- return 0;
- } else {
- return seat_stdout(serial->seat, data, len);
- }
-}
-
-static void serial_sentdata(struct handle *h, size_t new_backlog, int err)
-{
- Serial *serial = (Serial *)handle_get_privdata(h);
- if (err) {
- const char *error_msg = "Error writing to serial device";
-
- serial_terminate(serial);
-
- seat_notify_remote_exit(serial->seat);
-
- logevent(serial->logctx, error_msg);
-
- seat_connection_fatal(serial->seat, "%s", error_msg);
- } else {
- serial->bufsize = new_backlog;
- }
-}
-
-static char *serial_configure(Serial *serial, HANDLE serport, Conf *conf)
-{
- DCB dcb;
- COMMTIMEOUTS timeouts;
-
- /*
- * Set up the serial port parameters. If we can't even
- * GetCommState, we ignore the problem on the grounds that the
- * user might have pointed us at some other type of two-way
- * device instead of a serial port.
- */
- if (GetCommState(serport, &dcb)) {
- const char *str;
-
- /*
- * Boilerplate.
- */
- dcb.fBinary = true;
- dcb.fDtrControl = DTR_CONTROL_ENABLE;
- dcb.fDsrSensitivity = false;
- dcb.fTXContinueOnXoff = false;
- dcb.fOutX = false;
- dcb.fInX = false;
- dcb.fErrorChar = false;
- dcb.fNull = false;
- dcb.fRtsControl = RTS_CONTROL_ENABLE;
- dcb.fAbortOnError = false;
- dcb.fOutxCtsFlow = false;
- dcb.fOutxDsrFlow = false;
-
- /*
- * Configurable parameters.
- */
- dcb.BaudRate = conf_get_int(conf, CONF_serspeed);
- logeventf(serial->logctx, "Configuring baud rate %lu",
- (unsigned long)dcb.BaudRate);
-
- dcb.ByteSize = conf_get_int(conf, CONF_serdatabits);
- logeventf(serial->logctx, "Configuring %u data bits",
- (unsigned)dcb.ByteSize);
-
- switch (conf_get_int(conf, CONF_serstopbits)) {
- case 2: dcb.StopBits = ONESTOPBIT; str = "1 stop bit"; break;
- case 3: dcb.StopBits = ONE5STOPBITS; str = "1.5 stop bits"; break;
- case 4: dcb.StopBits = TWOSTOPBITS; str = "2 stop bits"; break;
- default: return dupstr("Invalid number of stop bits "
- "(need 1, 1.5 or 2)");
- }
- logeventf(serial->logctx, "Configuring %s", str);
-
- switch (conf_get_int(conf, CONF_serparity)) {
- case SER_PAR_NONE: dcb.Parity = NOPARITY; str = "no"; break;
- case SER_PAR_ODD: dcb.Parity = ODDPARITY; str = "odd"; break;
- case SER_PAR_EVEN: dcb.Parity = EVENPARITY; str = "even"; break;
- case SER_PAR_MARK: dcb.Parity = MARKPARITY; str = "mark"; break;
- case SER_PAR_SPACE: dcb.Parity = SPACEPARITY; str = "space"; break;
- }
- logeventf(serial->logctx, "Configuring %s parity", str);
-
- switch (conf_get_int(conf, CONF_serflow)) {
- case SER_FLOW_NONE:
- str = "no";
- break;
- case SER_FLOW_XONXOFF:
- dcb.fOutX = dcb.fInX = true;
- str = "XON/XOFF";
- break;
- case SER_FLOW_RTSCTS:
- dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
- dcb.fOutxCtsFlow = true;
- str = "RTS/CTS";
- break;
- case SER_FLOW_DSRDTR:
- dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
- dcb.fOutxDsrFlow = true;
- str = "DSR/DTR";
- break;
- }
- logeventf(serial->logctx, "Configuring %s flow control", str);
-
- if (!SetCommState(serport, &dcb))
- return dupprintf("Configuring serial port: %s",
- win_strerror(GetLastError()));
-
- timeouts.ReadIntervalTimeout = 1;
- timeouts.ReadTotalTimeoutMultiplier = 0;
- timeouts.ReadTotalTimeoutConstant = 0;
- timeouts.WriteTotalTimeoutMultiplier = 0;
- timeouts.WriteTotalTimeoutConstant = 0;
- if (!SetCommTimeouts(serport, &timeouts))
- return dupprintf("Configuring serial timeouts: %s",
- win_strerror(GetLastError()));
- }
-
- return NULL;
-}
-
-/*
- * Called to set up the serial connection.
- *
- * Returns an error message, or NULL on success.
- *
- * Also places the canonical host name into `realhost'. It must be
- * freed by the caller.
- */
-static char *serial_init(const BackendVtable *vt, Seat *seat,
- Backend **backend_handle, LogContext *logctx,
- Conf *conf, const char *host, int port,
- char **realhost, bool nodelay, bool keepalive)
-{
- Serial *serial;
- HANDLE serport;
- char *err;
- char *serline;
-
- /* No local authentication phase in this protocol */
- seat_set_trust_status(seat, false);
-
- serial = snew(Serial);
- serial->port = INVALID_HANDLE_VALUE;
- serial->out = serial->in = NULL;
- serial->bufsize = 0;
- serial->break_in_progress = false;
- serial->backend.vt = vt;
- *backend_handle = &serial->backend;
-
- serial->seat = seat;
- serial->logctx = logctx;
-
- serline = conf_get_str(conf, CONF_serline);
- logeventf(serial->logctx, "Opening serial device %s", serline);
-
- /*
- * Munge the string supplied by the user into a Windows filename.
- *
- * Windows supports opening a few "legacy" devices (including
- * COM1-9) by specifying their names verbatim as a filename to
- * open. (Thus, no files can ever have these names. See
- * <http://msdn2.microsoft.com/en-us/library/aa365247.aspx>
- * ("Naming a File") for the complete list of reserved names.)
- *
- * However, this doesn't let you get at devices COM10 and above.
- * For that, you need to specify a filename like "\\.\COM10".
- * This is also necessary for special serial and serial-like
- * devices such as \\.\WCEUSBSH001. It also works for the "legacy"
- * names, so you can do \\.\COM1 (verified as far back as Win95).
- * See <http://msdn2.microsoft.com/en-us/library/aa363858.aspx>
- * (CreateFile() docs).
- *
- * So, we believe that prepending "\\.\" should always be the
- * Right Thing. However, just in case someone finds something to
- * talk to that doesn't exist under there, if the serial line
- * contains a backslash, we use it verbatim. (This also lets
- * existing configurations using \\.\ continue working.)
- */
- char *serfilename =
- dupprintf("%s%s", strchr(serline, '\\') ? "" : "\\\\.\\", serline);
- serport = CreateFile(serfilename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
- OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
- if (serport == INVALID_HANDLE_VALUE) {
- err = dupprintf("Opening '%s': %s",
- serfilename, win_strerror(GetLastError()));
- sfree(serfilename);
- return err;
- }
-
- sfree(serfilename);
-
- err = serial_configure(serial, serport, conf);
- if (err)
- return err;
-
- serial->port = serport;
- serial->out = handle_output_new(serport, serial_sentdata, serial,
- HANDLE_FLAG_OVERLAPPED);
- serial->in = handle_input_new(serport, serial_gotdata, serial,
- HANDLE_FLAG_OVERLAPPED |
- HANDLE_FLAG_IGNOREEOF |
- HANDLE_FLAG_UNITBUFFER);
-
- *realhost = dupstr(serline);
-
- /*
- * Specials are always available.
- */
- seat_update_specials_menu(serial->seat);
-
- return NULL;
-}
-
-static void serial_free(Backend *be)
-{
- Serial *serial = container_of(be, Serial, backend);
-
- serial_terminate(serial);
- expire_timer_context(serial);
- sfree(serial);
-}
-
-static void serial_reconfig(Backend *be, Conf *conf)
-{
- Serial *serial = container_of(be, Serial, backend);
-
- serial_configure(serial, serial->port, conf);
-
- /*
- * FIXME: what should we do if that call returned a non-NULL error
- * message?
- */
-}
-
-/*
- * Called to send data down the serial connection.
- */
-static size_t serial_send(Backend *be, const char *buf, size_t len)
-{
- Serial *serial = container_of(be, Serial, backend);
-
- if (serial->out == NULL)
- return 0;
-
- serial->bufsize = handle_write(serial->out, buf, len);
- return serial->bufsize;
-}
-
-/*
- * Called to query the current sendability status.
- */
-static size_t serial_sendbuffer(Backend *be)
-{
- Serial *serial = container_of(be, Serial, backend);
- return serial->bufsize;
-}
-
-/*
- * Called to set the size of the window
- */
-static void serial_size(Backend *be, int width, int height)
-{
- /* Do nothing! */
- return;
-}
-
-static void serbreak_timer(void *ctx, unsigned long now)
-{
- Serial *serial = (Serial *)ctx;
-
- if (now == serial->clearbreak_time && serial->port) {
- ClearCommBreak(serial->port);
- serial->break_in_progress = false;
- logevent(serial->logctx, "Finished serial break");
- }
-}
-
-/*
- * Send serial special codes.
- */
-static void serial_special(Backend *be, SessionSpecialCode code, int arg)
-{
- Serial *serial = container_of(be, Serial, backend);
-
- if (serial->port && code == SS_BRK) {
- logevent(serial->logctx, "Starting serial break at user request");
- SetCommBreak(serial->port);
- /*
- * To send a serial break on Windows, we call SetCommBreak
- * to begin the break, then wait a bit, and then call
- * ClearCommBreak to finish it. Hence, I must use timing.c
- * to arrange a callback when it's time to do the latter.
- *
- * SUS says that a default break length must be between 1/4
- * and 1/2 second. FreeBSD apparently goes with 2/5 second,
- * and so will I.
- */
- serial->clearbreak_time =
- schedule_timer(TICKSPERSEC * 2 / 5, serbreak_timer, serial);
- serial->break_in_progress = true;
- }
-
- return;
-}
-
-/*
- * Return a list of the special codes that make sense in this
- * protocol.
- */
-static const SessionSpecial *serial_get_specials(Backend *be)
-{
- static const SessionSpecial specials[] = {
- {"Break", SS_BRK},
- {NULL, SS_EXITMENU}
- };
- return specials;
-}
-
-static bool serial_connected(Backend *be)
-{
- return true; /* always connected */
-}
-
-static bool serial_sendok(Backend *be)
-{
- return true;
-}
-
-static void serial_unthrottle(Backend *be, size_t backlog)
-{
- Serial *serial = container_of(be, Serial, backend);
- if (serial->in)
- handle_unthrottle(serial->in, backlog);
-}
-
-static bool serial_ldisc(Backend *be, int option)
-{
- /*
- * Local editing and local echo are off by default.
- */
- return false;
-}
-
-static void serial_provide_ldisc(Backend *be, Ldisc *ldisc)
-{
- /* This is a stub. */
-}
-
-static int serial_exitcode(Backend *be)
-{
- Serial *serial = container_of(be, Serial, backend);
- if (serial->port != INVALID_HANDLE_VALUE)
- return -1; /* still connected */
- else
- /* Exit codes are a meaningless concept with serial ports */
- return INT_MAX;
-}
-
-/*
- * cfg_info for Serial does nothing at all.
- */
-static int serial_cfg_info(Backend *be)
-{
- return 0;
-}
-
-const BackendVtable serial_backend = {
- .init = serial_init,
- .free = serial_free,
- .reconfig = serial_reconfig,
- .send = serial_send,
- .sendbuffer = serial_sendbuffer,
- .size = serial_size,
- .special = serial_special,
- .get_specials = serial_get_specials,
- .connected = serial_connected,
- .exitcode = serial_exitcode,
- .sendok = serial_sendok,
- .ldisc_option_state = serial_ldisc,
- .provide_ldisc = serial_provide_ldisc,
- .unthrottle = serial_unthrottle,
- .cfg_info = serial_cfg_info,
- .id = "serial",
- .displayname = "Serial",
- .protocol = PROT_SERIAL,
- .serial_parity_mask = ((1 << SER_PAR_NONE) |
- (1 << SER_PAR_ODD) |
- (1 << SER_PAR_EVEN) |
- (1 << SER_PAR_MARK) |
- (1 << SER_PAR_SPACE)),
- .serial_flow_mask = ((1 << SER_FLOW_NONE) |
- (1 << SER_FLOW_XONXOFF) |
- (1 << SER_FLOW_RTSCTS) |
- (1 << SER_FLOW_DSRDTR)),
-};
diff --git a/WINDOWS/WINSFTP.C b/WINDOWS/WINSFTP.C
deleted file mode 100644
index 0c695d2e..00000000
--- a/WINDOWS/WINSFTP.C
+++ /dev/null
@@ -1,650 +0,0 @@
-/*
- * winsftp.c: the Windows-specific parts of PSFTP and PSCP.
- */
-
-#include <winsock2.h> /* need to put this first, for winelib builds */
-#include <assert.h>
-
-#define NEED_DECLARATION_OF_SELECT
-
-#include "putty.h"
-#include "psftp.h"
-#include "ssh.h"
-#include "winsecur.h"
-
-int filexfer_get_userpass_input(Seat *seat, prompts_t *p, bufchain *input)
-{
- int ret;
- ret = cmdline_get_passwd_input(p);
- if (ret == -1)
- ret = console_get_userpass_input(p);
- return ret;
-}
-
-void platform_get_x11_auth(struct X11Display *display, Conf *conf)
-{
- /* Do nothing, therefore no auth. */
-}
-const bool platform_uses_x11_unix_by_default = true;
-
-/* ----------------------------------------------------------------------
- * File access abstraction.
- */
-
-/*
- * Set local current directory. Returns NULL on success, or else an
- * error message which must be freed after printing.
- */
-char *psftp_lcd(char *dir)
-{
- char *ret = NULL;
-
- if (!SetCurrentDirectory(dir)) {
- LPVOID message;
- int i;
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, GetLastError(),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR)&message, 0, NULL);
- i = strcspn((char *)message, "\n");
- ret = dupprintf("%.*s", i, (LPCTSTR)message);
- LocalFree(message);
- }
-
- return ret;
-}
-
-/*
- * Get local current directory. Returns a string which must be
- * freed.
- */
-char *psftp_getcwd(void)
-{
- char *ret = snewn(256, char);
- size_t len = GetCurrentDirectory(256, ret);
- if (len > 256)
- ret = sresize(ret, len, char);
- GetCurrentDirectory(len, ret);
- return ret;
-}
-
-static inline uint64_t uint64_from_words(uint32_t hi, uint32_t lo)
-{
- return (((uint64_t)hi) << 32) | lo;
-}
-
-#define TIME_POSIX_TO_WIN(t, ft) do { \
- ULARGE_INTEGER uli; \
- uli.QuadPart = ((ULONGLONG)(t) + 11644473600ull) * 10000000ull; \
- (ft).dwLowDateTime = uli.LowPart; \
- (ft).dwHighDateTime = uli.HighPart; \
-} while(0)
-#define TIME_WIN_TO_POSIX(ft, t) do { \
- ULARGE_INTEGER uli; \
- uli.LowPart = (ft).dwLowDateTime; \
- uli.HighPart = (ft).dwHighDateTime; \
- uli.QuadPart = uli.QuadPart / 10000000ull - 11644473600ull; \
- (t) = (unsigned long) uli.QuadPart; \
-} while(0)
-
-struct RFile {
- HANDLE h;
-};
-
-RFile *open_existing_file(const char *name, uint64_t *size,
- unsigned long *mtime, unsigned long *atime,
- long *perms)
-{
- HANDLE h;
- RFile *ret;
-
- h = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, NULL,
- OPEN_EXISTING, 0, 0);
- if (h == INVALID_HANDLE_VALUE)
- return NULL;
-
- ret = snew(RFile);
- ret->h = h;
-
- if (size) {
- DWORD lo, hi;
- lo = GetFileSize(h, &hi);
- *size = uint64_from_words(hi, lo);
- }
-
- if (mtime || atime) {
- FILETIME actime, wrtime;
- GetFileTime(h, NULL, &actime, &wrtime);
- if (atime)
- TIME_WIN_TO_POSIX(actime, *atime);
- if (mtime)
- TIME_WIN_TO_POSIX(wrtime, *mtime);
- }
-
- if (perms)
- *perms = -1;
-
- return ret;
-}
-
-int read_from_file(RFile *f, void *buffer, int length)
-{
- DWORD read;
- if (!ReadFile(f->h, buffer, length, &read, NULL))
- return -1; /* error */
- else
- return read;
-}
-
-void close_rfile(RFile *f)
-{
- CloseHandle(f->h);
- sfree(f);
-}
-
-struct WFile {
- HANDLE h;
-};
-
-WFile *open_new_file(const char *name, long perms)
-{
- HANDLE h;
- WFile *ret;
-
- h = CreateFile(name, GENERIC_WRITE, 0, NULL,
- CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
- if (h == INVALID_HANDLE_VALUE)
- return NULL;
-
- ret = snew(WFile);
- ret->h = h;
-
- return ret;
-}
-
-WFile *open_existing_wfile(const char *name, uint64_t *size)
-{
- HANDLE h;
- WFile *ret;
-
- h = CreateFile(name, GENERIC_WRITE, FILE_SHARE_READ, NULL,
- OPEN_EXISTING, 0, 0);
- if (h == INVALID_HANDLE_VALUE)
- return NULL;
-
- ret = snew(WFile);
- ret->h = h;
-
- if (size) {
- DWORD lo, hi;
- lo = GetFileSize(h, &hi);
- *size = uint64_from_words(hi, lo);
- }
-
- return ret;
-}
-
-int write_to_file(WFile *f, void *buffer, int length)
-{
- DWORD written;
- if (!WriteFile(f->h, buffer, length, &written, NULL))
- return -1; /* error */
- else
- return written;
-}
-
-void set_file_times(WFile *f, unsigned long mtime, unsigned long atime)
-{
- FILETIME actime, wrtime;
- TIME_POSIX_TO_WIN(atime, actime);
- TIME_POSIX_TO_WIN(mtime, wrtime);
- SetFileTime(f->h, NULL, &actime, &wrtime);
-}
-
-void close_wfile(WFile *f)
-{
- CloseHandle(f->h);
- sfree(f);
-}
-
-/* Seek offset bytes through file, from whence, where whence is
- FROM_START, FROM_CURRENT, or FROM_END */
-int seek_file(WFile *f, uint64_t offset, int whence)
-{
- DWORD movemethod;
-
- switch (whence) {
- case FROM_START:
- movemethod = FILE_BEGIN;
- break;
- case FROM_CURRENT:
- movemethod = FILE_CURRENT;
- break;
- case FROM_END:
- movemethod = FILE_END;
- break;
- default:
- return -1;
- }
-
- {
- LONG lo = offset & 0xFFFFFFFFU, hi = offset >> 32;
- SetFilePointer(f->h, lo, &hi, movemethod);
- }
-
- if (GetLastError() != NO_ERROR)
- return -1;
- else
- return 0;
-}
-
-uint64_t get_file_posn(WFile *f)
-{
- LONG lo, hi = 0;
-
- lo = SetFilePointer(f->h, 0L, &hi, FILE_CURRENT);
- return uint64_from_words(hi, lo);
-}
-
-int file_type(const char *name)
-{
- DWORD attr;
- attr = GetFileAttributes(name);
- /* We know of no `weird' files under Windows. */
- if (attr == (DWORD)-1)
- return FILE_TYPE_NONEXISTENT;
- else if (attr & FILE_ATTRIBUTE_DIRECTORY)
- return FILE_TYPE_DIRECTORY;
- else
- return FILE_TYPE_FILE;
-}
-
-struct DirHandle {
- HANDLE h;
- char *name;
-};
-
-DirHandle *open_directory(const char *name, const char **errmsg)
-{
- HANDLE h;
- WIN32_FIND_DATA fdat;
- char *findfile;
- DirHandle *ret;
-
- /* Enumerate files in dir `foo'. */
- findfile = dupcat(name, "/*");
- h = FindFirstFile(findfile, &fdat);
- if (h == INVALID_HANDLE_VALUE) {
- *errmsg = win_strerror(GetLastError());
- return NULL;
- }
- sfree(findfile);
-
- ret = snew(DirHandle);
- ret->h = h;
- ret->name = dupstr(fdat.cFileName);
- return ret;
-}
-
-char *read_filename(DirHandle *dir)
-{
- do {
-
- if (!dir->name) {
- WIN32_FIND_DATA fdat;
- if (!FindNextFile(dir->h, &fdat))
- return NULL;
- else
- dir->name = dupstr(fdat.cFileName);
- }
-
- assert(dir->name);
- if (dir->name[0] == '.' &&
- (dir->name[1] == '\0' ||
- (dir->name[1] == '.' && dir->name[2] == '\0'))) {
- sfree(dir->name);
- dir->name = NULL;
- }
-
- } while (!dir->name);
-
- if (dir->name) {
- char *ret = dir->name;
- dir->name = NULL;
- return ret;
- } else
- return NULL;
-}
-
-void close_directory(DirHandle *dir)
-{
- FindClose(dir->h);
- if (dir->name)
- sfree(dir->name);
- sfree(dir);
-}
-
-int test_wildcard(const char *name, bool cmdline)
-{
- HANDLE fh;
- WIN32_FIND_DATA fdat;
-
- /* First see if the exact name exists. */
- if (GetFileAttributes(name) != (DWORD)-1)
- return WCTYPE_FILENAME;
-
- /* Otherwise see if a wildcard match finds anything. */
- fh = FindFirstFile(name, &fdat);
- if (fh == INVALID_HANDLE_VALUE)
- return WCTYPE_NONEXISTENT;
-
- FindClose(fh);
- return WCTYPE_WILDCARD;
-}
-
-struct WildcardMatcher {
- HANDLE h;
- char *name;
- char *srcpath;
-};
-
-char *stripslashes(const char *str, bool local)
-{
- char *p;
-
- /*
- * On Windows, \ / : are all path component separators.
- */
-
- if (local) {
- p = strchr(str, ':');
- if (p) str = p+1;
- }
-
- p = strrchr(str, '/');
- if (p) str = p+1;
-
- if (local) {
- p = strrchr(str, '\\');
- if (p) str = p+1;
- }
-
- return (char *)str;
-}
-
-WildcardMatcher *begin_wildcard_matching(const char *name)
-{
- HANDLE h;
- WIN32_FIND_DATA fdat;
- WildcardMatcher *ret;
- char *last;
-
- h = FindFirstFile(name, &fdat);
- if (h == INVALID_HANDLE_VALUE)
- return NULL;
-
- ret = snew(WildcardMatcher);
- ret->h = h;
- ret->srcpath = dupstr(name);
- last = stripslashes(ret->srcpath, true);
- *last = '\0';
- if (fdat.cFileName[0] == '.' &&
- (fdat.cFileName[1] == '\0' ||
- (fdat.cFileName[1] == '.' && fdat.cFileName[2] == '\0')))
- ret->name = NULL;
- else
- ret->name = dupcat(ret->srcpath, fdat.cFileName);
-
- return ret;
-}
-
-char *wildcard_get_filename(WildcardMatcher *dir)
-{
- while (!dir->name) {
- WIN32_FIND_DATA fdat;
-
- if (!FindNextFile(dir->h, &fdat))
- return NULL;
-
- if (fdat.cFileName[0] == '.' &&
- (fdat.cFileName[1] == '\0' ||
- (fdat.cFileName[1] == '.' && fdat.cFileName[2] == '\0')))
- dir->name = NULL;
- else
- dir->name = dupcat(dir->srcpath, fdat.cFileName);
- }
-
- if (dir->name) {
- char *ret = dir->name;
- dir->name = NULL;
- return ret;
- } else
- return NULL;
-}
-
-void finish_wildcard_matching(WildcardMatcher *dir)
-{
- FindClose(dir->h);
- if (dir->name)
- sfree(dir->name);
- sfree(dir->srcpath);
- sfree(dir);
-}
-
-bool vet_filename(const char *name)
-{
- if (strchr(name, '/') || strchr(name, '\\') || strchr(name, ':'))
- return false;
-
- if (!name[strspn(name, ".")]) /* entirely composed of dots */
- return false;
-
- return true;
-}
-
-bool create_directory(const char *name)
-{
- return CreateDirectory(name, NULL) != 0;
-}
-
-char *dir_file_cat(const char *dir, const char *file)
-{
- ptrlen dir_pl = ptrlen_from_asciz(dir);
- return dupcat(
- dir, (ptrlen_endswith(dir_pl, PTRLEN_LITERAL("\\"), NULL) ||
- ptrlen_endswith(dir_pl, PTRLEN_LITERAL("/"), NULL)) ? "" : "\\",
- file);
-}
-
-/* ----------------------------------------------------------------------
- * Platform-specific network handling.
- */
-struct winsftp_cliloop_ctx {
- HANDLE other_event;
- int toret;
-};
-static bool winsftp_cliloop_pre(void *vctx, const HANDLE **extra_handles,
- size_t *n_extra_handles)
-{
- struct winsftp_cliloop_ctx *ctx = (struct winsftp_cliloop_ctx *)vctx;
-
- if (ctx->other_event != INVALID_HANDLE_VALUE) {
- *extra_handles = &ctx->other_event;
- *n_extra_handles = 1;
- }
-
- return true;
-}
-static bool winsftp_cliloop_post(void *vctx, size_t extra_handle_index)
-{
- struct winsftp_cliloop_ctx *ctx = (struct winsftp_cliloop_ctx *)vctx;
-
- if (ctx->other_event != INVALID_HANDLE_VALUE &&
- extra_handle_index == 0)
- ctx->toret = 1; /* other_event was set */
-
- return false; /* always run only one loop iteration */
-}
-int do_eventsel_loop(HANDLE other_event)
-{
- struct winsftp_cliloop_ctx ctx[1];
- ctx->other_event = other_event;
- ctx->toret = 0;
- cli_main_loop(winsftp_cliloop_pre, winsftp_cliloop_post, ctx);
- return ctx->toret;
-}
-
-/*
- * Wait for some network data and process it.
- *
- * We have two variants of this function. One uses select() so that
- * it's compatible with WinSock 1. The other uses WSAEventSelect
- * and MsgWaitForMultipleObjects, so that we can consistently use
- * WSAEventSelect throughout; this enables us to also implement
- * ssh_sftp_get_cmdline() using a parallel mechanism.
- */
-int ssh_sftp_loop_iteration(void)
-{
- if (p_WSAEventSelect == NULL) {
- fd_set readfds;
- int ret;
- unsigned long now = GETTICKCOUNT(), then;
- SOCKET skt = winselcli_unique_socket();
-
- if (skt == INVALID_SOCKET)
- return -1; /* doom */
-
- if (socket_writable(skt))
- select_result((WPARAM) skt, (LPARAM) FD_WRITE);
-
- do {
- unsigned long next;
- long ticks;
- struct timeval tv, *ptv;
-
- if (run_timers(now, &next)) {
- then = now;
- now = GETTICKCOUNT();
- if (now - then > next - then)
- ticks = 0;
- else
- ticks = next - now;
- tv.tv_sec = ticks / 1000;
- tv.tv_usec = ticks % 1000 * 1000;
- ptv = &tv;
- } else {
- ptv = NULL;
- }
-
- FD_ZERO(&readfds);
- FD_SET(skt, &readfds);
- ret = p_select(1, &readfds, NULL, NULL, ptv);
-
- if (ret < 0)
- return -1; /* doom */
- else if (ret == 0)
- now = next;
- else
- now = GETTICKCOUNT();
-
- } while (ret == 0);
-
- select_result((WPARAM) skt, (LPARAM) FD_READ);
-
- return 0;
- } else {
- return do_eventsel_loop(INVALID_HANDLE_VALUE);
- }
-}
-
-/*
- * Read a command line from standard input.
- *
- * In the presence of WinSock 2, we can use WSAEventSelect to
- * mediate between the socket and stdin, meaning we can send
- * keepalives and respond to server events even while waiting at
- * the PSFTP command prompt. Without WS2, we fall back to a simple
- * fgets.
- */
-struct command_read_ctx {
- HANDLE event;
- char *line;
-};
-
-static DWORD WINAPI command_read_thread(void *param)
-{
- struct command_read_ctx *ctx = (struct command_read_ctx *) param;
-
- ctx->line = fgetline(stdin);
-
- SetEvent(ctx->event);
-
- return 0;
-}
-
-char *ssh_sftp_get_cmdline(const char *prompt, bool no_fds_ok)
-{
- int ret;
- struct command_read_ctx ctx[1];
- DWORD threadid;
- HANDLE hThread;
-
- fputs(prompt, stdout);
- fflush(stdout);
-
- if ((winselcli_unique_socket() == INVALID_SOCKET && no_fds_ok) ||
- p_WSAEventSelect == NULL) {
- return fgetline(stdin); /* very simple */
- }
-
- /*
- * Create a second thread to read from stdin. Process network
- * and timing events until it terminates.
- */
- ctx->event = CreateEvent(NULL, false, false, NULL);
- ctx->line = NULL;
-
- hThread = CreateThread(NULL, 0, command_read_thread, ctx, 0, &threadid);
- if (!hThread) {
- CloseHandle(ctx->event);
- fprintf(stderr, "Unable to create command input thread\n");
- cleanup_exit(1);
- }
-
- do {
- ret = do_eventsel_loop(ctx->event);
-
- /* do_eventsel_loop can't return an error (unlike
- * ssh_sftp_loop_iteration, which can return -1 if select goes
- * wrong or if the socket doesn't exist). */
- assert(ret >= 0);
- } while (ret == 0);
-
- CloseHandle(hThread);
- CloseHandle(ctx->event);
-
- return ctx->line;
-}
-
-void platform_psftp_pre_conn_setup(LogPolicy *lp)
-{
- if (restricted_acl()) {
- lp_eventlog(lp, "Running with restricted process ACL");
- }
-}
-
-/* ----------------------------------------------------------------------
- * Main program. Parse arguments etc.
- */
-int main(int argc, char *argv[])
-{
- int ret;
-
- dll_hijacking_protection();
-
- ret = psftp_main(argc, argv);
-
- return ret;
-}
diff --git a/WINDOWS/WINSTORE.C b/WINDOWS/WINSTORE.C
deleted file mode 100644
index 09e5c028..00000000
--- a/WINDOWS/WINSTORE.C
+++ /dev/null
@@ -1,873 +0,0 @@
-/*
- * winstore.c: Windows-specific implementation of the interface
- * defined in storage.h.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <assert.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 reg_jumplist_key = PUTTY_REG_POS "\\Jumplist";
-static const char *const reg_jumplist_value = "Recent sessions";
-static const char *const puttystr = PUTTY_REG_POS "\\Sessions";
-
-static bool tried_shgetfolderpath = false;
-static HMODULE shell32_module = NULL;
-DECL_WINDOWS_FUNCTION(static, HRESULT, SHGetFolderPathA,
- (HWND, int, HANDLE, DWORD, LPSTR));
-
-struct settings_w {
- HKEY sesskey;
-};
-
-settings_w *open_settings_w(const char *sessionname, char **errmsg)
-{
- HKEY subkey1, sesskey;
- int ret;
- strbuf *sb;
-
- *errmsg = NULL;
-
- if (!sessionname || !*sessionname)
- sessionname = "Default Settings";
-
- sb = strbuf_new();
- escape_registry_key(sessionname, sb);
-
- ret = RegCreateKey(HKEY_CURRENT_USER, puttystr, &subkey1);
- if (ret != ERROR_SUCCESS) {
- strbuf_free(sb);
- *errmsg = dupprintf("Unable to create registry key\n"
- "HKEY_CURRENT_USER\\%s", puttystr);
- return NULL;
- }
- ret = RegCreateKey(subkey1, sb->s, &sesskey);
- RegCloseKey(subkey1);
- if (ret != ERROR_SUCCESS) {
- *errmsg = dupprintf("Unable to create registry key\n"
- "HKEY_CURRENT_USER\\%s\\%s", puttystr, sb->s);
- strbuf_free(sb);
- return NULL;
- }
- strbuf_free(sb);
-
- settings_w *toret = snew(settings_w);
- toret->sesskey = sesskey;
- return toret;
-}
-
-void write_setting_s(settings_w *handle, const char *key, const char *value)
-{
- if (handle)
- RegSetValueEx(handle->sesskey, key, 0, REG_SZ, (CONST BYTE *)value,
- 1 + strlen(value));
-}
-
-void write_setting_i(settings_w *handle, const char *key, int value)
-{
- if (handle)
- RegSetValueEx(handle->sesskey, key, 0, REG_DWORD,
- (CONST BYTE *) &value, sizeof(value));
-}
-
-void close_settings_w(settings_w *handle)
-{
- RegCloseKey(handle->sesskey);
- sfree(handle);
-}
-
-struct settings_r {
- HKEY sesskey;
-};
-
-settings_r *open_settings_r(const char *sessionname)
-{
- HKEY subkey1, sesskey;
- strbuf *sb;
-
- if (!sessionname || !*sessionname)
- sessionname = "Default Settings";
-
- sb = strbuf_new();
- escape_registry_key(sessionname, sb);
-
- if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS) {
- sesskey = NULL;
- } else {
- if (RegOpenKey(subkey1, sb->s, &sesskey) != ERROR_SUCCESS) {
- sesskey = NULL;
- }
- RegCloseKey(subkey1);
- }
-
- strbuf_free(sb);
-
- if (!sesskey)
- return NULL;
-
- settings_r *toret = snew(settings_r);
- toret->sesskey = sesskey;
- return toret;
-}
-
-char *read_setting_s(settings_r *handle, const char *key)
-{
- DWORD type, allocsize, size;
- char *ret;
-
- if (!handle)
- return NULL;
-
- /* Find out the type and size of the data. */
- if (RegQueryValueEx(handle->sesskey, key, 0,
- &type, NULL, &size) != ERROR_SUCCESS ||
- type != REG_SZ)
- return NULL;
-
- allocsize = size+1; /* allow for an extra NUL if needed */
- ret = snewn(allocsize, char);
- if (RegQueryValueEx(handle->sesskey, key, 0,
- &type, (BYTE *)ret, &size) != ERROR_SUCCESS ||
- type != REG_SZ) {
- sfree(ret);
- return NULL;
- }
- assert(size < allocsize);
- ret[size] = '\0'; /* add an extra NUL in case RegQueryValueEx
- * didn't supply one */
-
- return ret;
-}
-
-int read_setting_i(settings_r *handle, const char *key, int defvalue)
-{
- DWORD type, val, size;
- size = sizeof(val);
-
- if (!handle ||
- RegQueryValueEx(handle->sesskey, key, 0, &type,
- (BYTE *) &val, &size) != ERROR_SUCCESS ||
- size != sizeof(val) || type != REG_DWORD)
- return defvalue;
- else
- return val;
-}
-
-FontSpec *read_setting_fontspec(settings_r *handle, const char *name)
-{
- char *settingname;
- char *fontname;
- FontSpec *ret;
- int isbold, height, charset;
-
- fontname = read_setting_s(handle, name);
- if (!fontname)
- return NULL;
-
- settingname = dupcat(name, "IsBold");
- isbold = read_setting_i(handle, settingname, -1);
- sfree(settingname);
- if (isbold == -1) {
- sfree(fontname);
- return NULL;
- }
-
- settingname = dupcat(name, "CharSet");
- charset = read_setting_i(handle, settingname, -1);
- sfree(settingname);
- if (charset == -1) {
- sfree(fontname);
- return NULL;
- }
-
- settingname = dupcat(name, "Height");
- height = read_setting_i(handle, settingname, INT_MIN);
- sfree(settingname);
- if (height == INT_MIN) {
- sfree(fontname);
- return NULL;
- }
-
- ret = fontspec_new(fontname, isbold, height, charset);
- sfree(fontname);
- return ret;
-}
-
-void write_setting_fontspec(settings_w *handle,
- const char *name, FontSpec *font)
-{
- char *settingname;
-
- write_setting_s(handle, name, font->name);
- settingname = dupcat(name, "IsBold");
- write_setting_i(handle, settingname, font->isbold);
- sfree(settingname);
- settingname = dupcat(name, "CharSet");
- write_setting_i(handle, settingname, font->charset);
- sfree(settingname);
- settingname = dupcat(name, "Height");
- write_setting_i(handle, settingname, font->height);
- sfree(settingname);
-}
-
-Filename *read_setting_filename(settings_r *handle, const char *name)
-{
- char *tmp = read_setting_s(handle, name);
- if (tmp) {
- Filename *ret = filename_from_str(tmp);
- sfree(tmp);
- return ret;
- } else
- return NULL;
-}
-
-void write_setting_filename(settings_w *handle,
- const char *name, Filename *result)
-{
- write_setting_s(handle, name, result->path);
-}
-
-void close_settings_r(settings_r *handle)
-{
- if (handle) {
- RegCloseKey(handle->sesskey);
- sfree(handle);
- }
-}
-
-void del_settings(const char *sessionname)
-{
- HKEY subkey1;
- strbuf *sb;
-
- if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS)
- return;
-
- sb = strbuf_new();
- escape_registry_key(sessionname, sb);
- RegDeleteKey(subkey1, sb->s);
- strbuf_free(sb);
-
- RegCloseKey(subkey1);
-
- remove_session_from_jumplist(sessionname);
-}
-
-struct settings_e {
- HKEY key;
- int i;
-};
-
-settings_e *enum_settings_start(void)
-{
- settings_e *ret;
- HKEY key;
-
- if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &key) != ERROR_SUCCESS)
- return NULL;
-
- ret = snew(settings_e);
- if (ret) {
- ret->key = key;
- ret->i = 0;
- }
-
- return ret;
-}
-
-bool enum_settings_next(settings_e *e, strbuf *sb)
-{
- size_t regbuf_size = MAX_PATH + 1;
- char *regbuf = snewn(regbuf_size, char);
- bool success;
-
- while (1) {
- DWORD retd = RegEnumKey(e->key, e->i, regbuf, regbuf_size);
- if (retd != ERROR_MORE_DATA) {
- success = (retd == ERROR_SUCCESS);
- break;
- }
- sgrowarray(regbuf, regbuf_size, regbuf_size);
- }
-
- if (success)
- unescape_registry_key(regbuf, sb);
-
- e->i++;
- sfree(regbuf);
- return success;
-}
-
-void enum_settings_finish(settings_e *e)
-{
- RegCloseKey(e->key);
- sfree(e);
-}
-
-static void hostkey_regname(strbuf *sb, const char *hostname,
- int port, const char *keytype)
-{
- strbuf_catf(sb, "%s@%d:", keytype, port);
- escape_registry_key(hostname, sb);
-}
-
-int verify_host_key(const char *hostname, int port,
- const char *keytype, const char *key)
-{
- char *otherstr;
- strbuf *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.
- */
- regname = strbuf_new();
- hostkey_regname(regname, hostname, port, keytype);
-
- if (RegOpenKey(HKEY_CURRENT_USER, PUTTY_REG_POS "\\SshHostKeys",
- &rkey) != ERROR_SUCCESS) {
- strbuf_free(regname);
- return 1; /* key does not exist in registry */
- }
-
- readlen = len;
- otherstr = snewn(len, char);
- ret = RegQueryValueEx(rkey, regname->s, NULL,
- &type, (BYTE *)otherstr, &readlen);
-
- if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA &&
- !strcmp(keytype, "rsa")) {
- /*
- * Key didn't exist. If the key type is RSA, we'll try
- * another trick, which is to look up the _old_ key format
- * under just the hostname and translate that.
- */
- char *justhost = regname->s + 1 + strcspn(regname->s, ":");
- char *oldstyle = snewn(len + 10, char); /* safety margin */
- readlen = len;
- ret = RegQueryValueEx(rkey, justhost, NULL, &type,
- (BYTE *)oldstyle, &readlen);
-
- if (ret == ERROR_SUCCESS && type == REG_SZ) {
- /*
- * The old format is two old-style bignums separated by
- * a slash. An old-style bignum is made of groups of
- * four hex digits: digits are ordered in sensible
- * (most to least significant) order within each group,
- * but groups are ordered in silly (least to most)
- * order within the bignum. The new format is two
- * ordinary C-format hex numbers (0xABCDEFG...XYZ, with
- * A nonzero except in the special case 0x0, which
- * doesn't appear anyway in RSA keys) separated by a
- * comma. All hex digits are lowercase in both formats.
- */
- char *p = otherstr;
- char *q = oldstyle;
- int i, j;
-
- for (i = 0; i < 2; i++) {
- int ndigits, nwords;
- *p++ = '0';
- *p++ = 'x';
- ndigits = strcspn(q, "/"); /* find / or end of string */
- nwords = ndigits / 4;
- /* now trim ndigits to remove leading zeros */
- while (q[(ndigits - 1) ^ 3] == '0' && ndigits > 1)
- ndigits--;
- /* now move digits over to new string */
- for (j = 0; j < ndigits; j++)
- p[ndigits - 1 - j] = q[j ^ 3];
- p += ndigits;
- q += nwords * 4;
- if (*q) {
- q++; /* eat the slash */
- *p++ = ','; /* add a comma */
- }
- *p = '\0'; /* terminate the string */
- }
-
- /*
- * Now _if_ this key matches, we'll enter it in the new
- * format. If not, we'll assume something odd went
- * wrong, and hyper-cautiously do nothing.
- */
- if (!strcmp(otherstr, key))
- RegSetValueEx(rkey, regname->s, 0, REG_SZ, (BYTE *)otherstr,
- strlen(otherstr) + 1);
- }
-
- sfree(oldstyle);
- }
-
- RegCloseKey(rkey);
-
- compare = strcmp(otherstr, key);
-
- sfree(otherstr);
- strbuf_free(regname);
-
- if (ret == ERROR_MORE_DATA ||
- (ret == ERROR_SUCCESS && type == REG_SZ && compare))
- return 2; /* key is different in registry */
- else if (ret != ERROR_SUCCESS || type != REG_SZ)
- return 1; /* key does not exist in registry */
- else
- return 0; /* key matched OK in registry */
-}
-
-bool have_ssh_host_key(const char *hostname, int port,
- const char *keytype)
-{
- /*
- * If we have a host key, verify_host_key will return 0 or 2.
- * If we don't have one, it'll return 1.
- */
- return verify_host_key(hostname, port, keytype, "") != 1;
-}
-
-void store_host_key(const char *hostname, int port,
- const char *keytype, const char *key)
-{
- strbuf *regname;
- HKEY rkey;
-
- regname = strbuf_new();
- hostkey_regname(regname, hostname, port, keytype);
-
- if (RegCreateKey(HKEY_CURRENT_USER, PUTTY_REG_POS "\\SshHostKeys",
- &rkey) == ERROR_SUCCESS) {
- RegSetValueEx(rkey, regname->s, 0, REG_SZ,
- (BYTE *)key, strlen(key) + 1);
- RegCloseKey(rkey);
- } /* else key does not exist in registry */
-
- strbuf_free(regname);
-}
-
-/*
- * Open (or delete) the random seed file.
- */
-enum { DEL, OPEN_R, OPEN_W };
-static bool try_random_seed(char const *path, int action, HANDLE *ret)
-{
- if (action == DEL) {
- if (!DeleteFile(path) && GetLastError() != ERROR_FILE_NOT_FOUND) {
- nonfatal("Unable to delete '%s': %s", path,
- win_strerror(GetLastError()));
- }
- *ret = INVALID_HANDLE_VALUE;
- return false; /* so we'll do the next ones too */
- }
-
- *ret = CreateFile(path,
- action == OPEN_W ? GENERIC_WRITE : GENERIC_READ,
- action == OPEN_W ? 0 : (FILE_SHARE_READ |
- FILE_SHARE_WRITE),
- NULL,
- action == OPEN_W ? CREATE_ALWAYS : OPEN_EXISTING,
- action == OPEN_W ? FILE_ATTRIBUTE_NORMAL : 0,
- NULL);
-
- return (*ret != INVALID_HANDLE_VALUE);
-}
-
-static bool try_random_seed_and_free(char *path, int action, HANDLE *hout)
-{
- bool retd = try_random_seed(path, action, hout);
- sfree(path);
- return retd;
-}
-
-static HANDLE access_random_seed(int action)
-{
- HKEY rkey;
- HANDLE rethandle;
-
- /*
- * Iterate over a selection of possible random seed paths until
- * we find one that works.
- *
- * We do this iteration separately for reading and writing,
- * meaning that we will automatically migrate random seed files
- * if a better location becomes available (by reading from the
- * best location in which we actually find one, and then
- * writing to the best location in which we can _create_ one).
- */
-
- /*
- * First, try the location specified by the user in the
- * Registry, if any.
- */
- {
- char regpath[MAX_PATH + 1];
- DWORD type, size = sizeof(regpath);
- if (RegOpenKey(HKEY_CURRENT_USER, PUTTY_REG_POS, &rkey) ==
- ERROR_SUCCESS) {
- int ret = RegQueryValueEx(rkey, "RandSeedFile",
- 0, &type, (BYTE *)regpath, &size);
- RegCloseKey(rkey);
- if (ret == ERROR_SUCCESS && type == REG_SZ &&
- try_random_seed(regpath, action, &rethandle))
- return rethandle;
- }
- }
-
- /*
- * Next, try the user's local Application Data directory,
- * followed by their non-local one. This is found using the
- * SHGetFolderPath function, which won't be present on all
- * versions of Windows.
- */
- if (!tried_shgetfolderpath) {
- /* This is likely only to bear fruit on systems with IE5+
- * installed, or WinMe/2K+. There is some faffing with
- * SHFOLDER.DLL we could do to try to find an equivalent
- * on older versions of Windows if we cared enough.
- * However, the invocation below requires IE5+ anyway,
- * so stuff that. */
- shell32_module = load_system32_dll("shell32.dll");
- GET_WINDOWS_FUNCTION(shell32_module, SHGetFolderPathA);
- tried_shgetfolderpath = true;
- }
- if (p_SHGetFolderPathA) {
- char profile[MAX_PATH + 1];
- if (SUCCEEDED(p_SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA,
- NULL, SHGFP_TYPE_CURRENT, profile)) &&
- try_random_seed_and_free(dupcat(profile, "\\PUTTY.RND"),
- action, &rethandle))
- return rethandle;
-
- if (SUCCEEDED(p_SHGetFolderPathA(NULL, CSIDL_APPDATA,
- NULL, SHGFP_TYPE_CURRENT, profile)) &&
- try_random_seed_and_free(dupcat(profile, "\\PUTTY.RND"),
- action, &rethandle))
- return rethandle;
- }
-
- /*
- * Failing that, try %HOMEDRIVE%%HOMEPATH% as a guess at the
- * user's home directory.
- */
- {
- char drv[MAX_PATH], path[MAX_PATH];
-
- DWORD drvlen = GetEnvironmentVariable("HOMEDRIVE", drv, sizeof(drv));
- DWORD pathlen = GetEnvironmentVariable("HOMEPATH", path, sizeof(path));
-
- /* We permit %HOMEDRIVE% to expand to an empty string, but if
- * %HOMEPATH% does that, we abort the attempt. Same if either
- * variable overflows its buffer. */
- if (drvlen == 0)
- drv[0] = '\0';
-
- if (drvlen < lenof(drv) && pathlen < lenof(path) && pathlen > 0 &&
- try_random_seed_and_free(
- dupcat(drv, path, "\\PUTTY.RND"), action, &rethandle))
- return rethandle;
- }
-
- /*
- * And finally, fall back to C:\WINDOWS.
- */
- {
- char windir[MAX_PATH];
- DWORD len = GetWindowsDirectory(windir, sizeof(windir));
- if (len < lenof(windir) &&
- try_random_seed_and_free(
- dupcat(windir, "\\PUTTY.RND"), action, &rethandle))
- return rethandle;
- }
-
- /*
- * If even that failed, give up.
- */
- return INVALID_HANDLE_VALUE;
-}
-
-void read_random_seed(noise_consumer_t consumer)
-{
- HANDLE seedf = access_random_seed(OPEN_R);
-
- if (seedf != INVALID_HANDLE_VALUE) {
- while (1) {
- char buf[1024];
- DWORD len;
-
- if (ReadFile(seedf, buf, sizeof(buf), &len, NULL) && len)
- consumer(buf, len);
- else
- break;
- }
- CloseHandle(seedf);
- }
-}
-
-void write_random_seed(void *data, int len)
-{
- HANDLE seedf = access_random_seed(OPEN_W);
-
- if (seedf != INVALID_HANDLE_VALUE) {
- DWORD lenwritten;
-
- WriteFile(seedf, data, len, &lenwritten, NULL);
- CloseHandle(seedf);
- }
-}
-
-/*
- * Internal function supporting the jump list registry code. All the
- * functions to add, remove and read the list have substantially
- * similar content, so this is a generalisation of all of them which
- * transforms the list in the registry by prepending 'add' (if
- * non-null), removing 'rem' from what's left (if non-null), and
- * returning the resulting concatenated list of strings in 'out' (if
- * non-null).
- */
-static int transform_jumplist_registry
- (const char *add, const char *rem, char **out)
-{
- int ret;
- HKEY pjumplist_key;
- DWORD type;
- DWORD value_length;
- char *old_value, *new_value;
- char *piterator_old, *piterator_new, *piterator_tmp;
-
- ret = RegCreateKeyEx(HKEY_CURRENT_USER, reg_jumplist_key, 0, NULL,
- REG_OPTION_NON_VOLATILE, (KEY_READ | KEY_WRITE), NULL,
- &pjumplist_key, NULL);
- if (ret != ERROR_SUCCESS) {
- return JUMPLISTREG_ERROR_KEYOPENCREATE_FAILURE;
- }
-
- /* Get current list of saved sessions in the registry. */
- value_length = 200;
- old_value = snewn(value_length, char);
- ret = RegQueryValueEx(pjumplist_key, reg_jumplist_value, NULL, &type,
- (BYTE *)old_value, &value_length);
- /* When the passed buffer is too small, ERROR_MORE_DATA is
- * returned and the required size is returned in the length
- * argument. */
- if (ret == ERROR_MORE_DATA) {
- sfree(old_value);
- old_value = snewn(value_length, char);
- ret = RegQueryValueEx(pjumplist_key, reg_jumplist_value, NULL, &type,
- (BYTE *)old_value, &value_length);
- }
-
- if (ret == ERROR_FILE_NOT_FOUND) {
- /* Value doesn't exist yet. Start from an empty value. */
- *old_value = '\0';
- *(old_value + 1) = '\0';
- } else if (ret != ERROR_SUCCESS) {
- /* Some non-recoverable error occurred. */
- sfree(old_value);
- RegCloseKey(pjumplist_key);
- return JUMPLISTREG_ERROR_VALUEREAD_FAILURE;
- } else if (type != REG_MULTI_SZ) {
- /* The value present in the registry has the wrong type: we
- * try to delete it and start from an empty value. */
- ret = RegDeleteValue(pjumplist_key, reg_jumplist_value);
- if (ret != ERROR_SUCCESS) {
- sfree(old_value);
- RegCloseKey(pjumplist_key);
- return JUMPLISTREG_ERROR_VALUEREAD_FAILURE;
- }
-
- *old_value = '\0';
- *(old_value + 1) = '\0';
- }
-
- /* Check validity of registry data: REG_MULTI_SZ value must end
- * with \0\0. */
- piterator_tmp = old_value;
- while (((piterator_tmp - old_value) < (value_length - 1)) &&
- !(*piterator_tmp == '\0' && *(piterator_tmp+1) == '\0')) {
- ++piterator_tmp;
- }
-
- if ((piterator_tmp - old_value) >= (value_length-1)) {
- /* Invalid value. Start from an empty value. */
- *old_value = '\0';
- *(old_value + 1) = '\0';
- }
-
- /*
- * Modify the list, if we're modifying.
- */
- if (add || rem) {
- /* Walk through the existing list and construct the new list of
- * saved sessions. */
- new_value = snewn(value_length + (add ? strlen(add) + 1 : 0), char);
- piterator_new = new_value;
- piterator_old = old_value;
-
- /* First add the new item to the beginning of the list. */
- if (add) {
- strcpy(piterator_new, add);
- piterator_new += strlen(piterator_new) + 1;
- }
- /* Now add the existing list, taking care to leave out the removed
- * item, if it was already in the existing list. */
- while (*piterator_old != '\0') {
- if (!rem || strcmp(piterator_old, rem) != 0) {
- /* Check if this is a valid session, otherwise don't add. */
- settings_r *psettings_tmp = open_settings_r(piterator_old);
- if (psettings_tmp != NULL) {
- close_settings_r(psettings_tmp);
- strcpy(piterator_new, piterator_old);
- piterator_new += strlen(piterator_new) + 1;
- }
- }
- piterator_old += strlen(piterator_old) + 1;
- }
- *piterator_new = '\0';
- ++piterator_new;
-
- /* Save the new list to the registry. */
- ret = RegSetValueEx(pjumplist_key, reg_jumplist_value, 0, REG_MULTI_SZ,
- (BYTE *)new_value, piterator_new - new_value);
-
- sfree(old_value);
- old_value = new_value;
- } else
- ret = ERROR_SUCCESS;
-
- /*
- * Either return or free the result.
- */
- if (out && ret == ERROR_SUCCESS)
- *out = old_value;
- else
- sfree(old_value);
-
- /* Clean up and return. */
- RegCloseKey(pjumplist_key);
-
- if (ret != ERROR_SUCCESS) {
- return JUMPLISTREG_ERROR_VALUEWRITE_FAILURE;
- } else {
- return JUMPLISTREG_OK;
- }
-}
-
-/* Adds a new entry to the jumplist entries in the registry. */
-int add_to_jumplist_registry(const char *item)
-{
- return transform_jumplist_registry(item, item, NULL);
-}
-
-/* Removes an item from the jumplist entries in the registry. */
-int remove_from_jumplist_registry(const char *item)
-{
- return transform_jumplist_registry(NULL, item, NULL);
-}
-
-/* Returns the jumplist entries from the registry. Caller must free
- * the returned pointer. */
-char *get_jumplist_registry_entries (void)
-{
- char *list_value;
-
- if (transform_jumplist_registry(NULL,NULL,&list_value) != JUMPLISTREG_OK) {
- list_value = snewn(2, char);
- *list_value = '\0';
- *(list_value + 1) = '\0';
- }
- return list_value;
-}
-
-/*
- * Recursively delete a registry key and everything under it.
- */
-static void registry_recursive_remove(HKEY key)
-{
- DWORD i;
- char name[MAX_PATH + 1];
- HKEY subkey;
-
- i = 0;
- while (RegEnumKey(key, i, name, sizeof(name)) == ERROR_SUCCESS) {
- if (RegOpenKey(key, name, &subkey) == ERROR_SUCCESS) {
- registry_recursive_remove(subkey);
- RegCloseKey(subkey);
- }
- RegDeleteKey(key, name);
- }
-}
-
-void cleanup_all(void)
-{
- HKEY key;
- int ret;
- char name[MAX_PATH + 1];
-
- /* ------------------------------------------------------------
- * Wipe out the random seed file, in all of its possible
- * locations.
- */
- access_random_seed(DEL);
-
- /* ------------------------------------------------------------
- * Ask Windows to delete any jump list information associated
- * with this installation of PuTTY.
- */
- clear_jumplist();
-
- /* ------------------------------------------------------------
- * Destroy all registry information associated with PuTTY.
- */
-
- /*
- * Open the main PuTTY registry key and remove everything in it.
- */
- if (RegOpenKey(HKEY_CURRENT_USER, PUTTY_REG_POS, &key) ==
- ERROR_SUCCESS) {
- registry_recursive_remove(key);
- RegCloseKey(key);
- }
- /*
- * Now open the parent key and remove the PuTTY main key. Once
- * we've done that, see if the parent key has any other
- * children.
- */
- if (RegOpenKey(HKEY_CURRENT_USER, PUTTY_REG_PARENT,
- &key) == ERROR_SUCCESS) {
- RegDeleteKey(key, PUTTY_REG_PARENT_CHILD);
- ret = RegEnumKey(key, 0, name, sizeof(name));
- RegCloseKey(key);
- /*
- * If the parent key had no other children, we must delete
- * it in its turn. That means opening the _grandparent_
- * key.
- */
- if (ret != ERROR_SUCCESS) {
- if (RegOpenKey(HKEY_CURRENT_USER, PUTTY_REG_GPARENT,
- &key) == ERROR_SUCCESS) {
- RegDeleteKey(key, PUTTY_REG_GPARENT_CHILD);
- RegCloseKey(key);
- }
- }
- }
- /*
- * Now we're done.
- */
-}
diff --git a/WINDOWS/WINSTUFF.H b/WINDOWS/WINSTUFF.H
deleted file mode 100644
index c0df5a31..00000000
--- a/WINDOWS/WINSTUFF.H
+++ /dev/null
@@ -1,704 +0,0 @@
-/*
- * winstuff.h: Windows-specific inter-module stuff.
- */
-
-#ifndef PUTTY_WINSTUFF_H
-#define PUTTY_WINSTUFF_H
-
-#ifndef AUTO_WINSOCK
-#include <winsock2.h>
-#endif
-#include <windows.h>
-#include <stdio.h> /* for FILENAME_MAX */
-
-/* We use uintptr_t for Win32/Win64 portability, so we should in
- * principle include stdint.h, which defines it according to the C
- * standard. But older versions of Visual Studio - including the one
- * used for official PuTTY builds as of 2015-09-28 - don't provide
- * stdint.h at all, but do (non-standardly) define uintptr_t in
- * stddef.h. So here we try to make sure _some_ standard header is
- * included which defines uintptr_t. */
-#include <stddef.h>
-#if !defined _MSC_VER || _MSC_VER >= 1600 || defined __clang__
-#include <stdint.h>
-#endif
-
-#include "defs.h"
-#include "marshal.h"
-
-#include "tree234.h"
-
-#include "winhelp.h"
-
-#if defined _M_IX86 || defined _M_AMD64
-#define BUILDINFO_PLATFORM "x86 Windows"
-#elif defined _M_ARM || defined _M_ARM64
-#define BUILDINFO_PLATFORM "Arm Windows"
-#else
-#define BUILDINFO_PLATFORM "Windows"
-#endif
-
-struct Filename {
- char *path;
-};
-static inline FILE *f_open(const Filename *filename, const char *mode,
- bool isprivate)
-{
- return fopen(filename->path, mode);
-}
-
-struct FontSpec {
- char *name;
- bool isbold;
- int height;
- int charset;
-};
-struct FontSpec *fontspec_new(
- const char *name, bool bold, int height, int charset);
-
-#ifndef CLEARTYPE_QUALITY
-#define CLEARTYPE_QUALITY 5
-#endif
-#define FONT_QUALITY(fq) ( \
- (fq) == FQ_DEFAULT ? DEFAULT_QUALITY : \
- (fq) == FQ_ANTIALIASED ? ANTIALIASED_QUALITY : \
- (fq) == FQ_NONANTIALIASED ? NONANTIALIASED_QUALITY : \
- CLEARTYPE_QUALITY)
-
-#define PLATFORM_IS_UTF16 /* enable UTF-16 processing when exchanging
- * wchar_t strings with environment */
-
-#define PLATFORM_CLIPBOARDS(X) \
- X(CLIP_SYSTEM, "system clipboard") \
- /* end of list */
-
-/*
- * Where we can, we use GetWindowLongPtr and friends because they're
- * more useful on 64-bit platforms, but they're a relatively recent
- * innovation, missing from VC++ 6 and older MinGW. Degrade nicely.
- * (NB that on some systems, some of these things are available but
- * not others...)
- */
-
-#ifndef GCLP_HCURSOR
-/* GetClassLongPtr and friends */
-#undef GetClassLongPtr
-#define GetClassLongPtr GetClassLong
-#undef SetClassLongPtr
-#define SetClassLongPtr SetClassLong
-#define GCLP_HCURSOR GCL_HCURSOR
-/* GetWindowLongPtr and friends */
-#undef GetWindowLongPtr
-#define GetWindowLongPtr GetWindowLong
-#undef SetWindowLongPtr
-#define SetWindowLongPtr SetWindowLong
-#undef GWLP_USERDATA
-#define GWLP_USERDATA GWL_USERDATA
-#undef DWLP_MSGRESULT
-#define DWLP_MSGRESULT DWL_MSGRESULT
-/* Since we've clobbered the above functions, we should clobber the
- * associated type regardless of whether it's defined. */
-#undef LONG_PTR
-#define LONG_PTR LONG
-#endif
-
-#define BOXFLAGS DLGWINDOWEXTRA
-#define BOXRESULT (DLGWINDOWEXTRA + sizeof(LONG_PTR))
-#define DF_END 0x0001
-
-#ifndef __WINE__
-/* Up-to-date Windows headers warn that the unprefixed versions of
- * these names are deprecated. */
-#define stricmp _stricmp
-#define strnicmp _strnicmp
-#else
-/* Compiling with winegcc, _neither_ version of these functions
- * exists. Use the POSIX names. */
-#define stricmp strcasecmp
-#define strnicmp strncasecmp
-#endif
-
-#define BROKEN_PIPE_ERROR_CODE ERROR_BROKEN_PIPE /* used in sshshare.c */
-
-/*
- * Dynamically linked functions. These come in two flavours:
- *
- * - GET_WINDOWS_FUNCTION does not expose "name" to the preprocessor,
- * so will always dynamically link against exactly what is specified
- * in "name". If you're not sure, use this one.
- *
- * - GET_WINDOWS_FUNCTION_PP allows "name" to be redirected via
- * preprocessor definitions like "#define foo bar"; this is principally
- * intended for the ANSI/Unicode DoSomething/DoSomethingA/DoSomethingW.
- * If your function has an argument of type "LPTSTR" or similar, this
- * is the variant to use.
- * (However, it can't always be used, as it trips over more complicated
- * macro trickery such as the WspiapiGetAddrInfo wrapper for getaddrinfo.)
- *
- * (DECL_WINDOWS_FUNCTION works with both these variants.)
- */
-#define DECL_WINDOWS_FUNCTION(linkage, rettype, name, params) \
- typedef rettype (WINAPI *t_##name) params; \
- linkage t_##name p_##name
-/* If you DECL_WINDOWS_FUNCTION as extern in a header file, use this to
- * define the function pointer in a source file */
-#define DEF_WINDOWS_FUNCTION(name) t_##name p_##name
-#define STR1(x) #x
-#define STR(x) STR1(x)
-#define GET_WINDOWS_FUNCTION_PP(module, name) \
- TYPECHECK((t_##name)NULL == name, \
- (p_##name = module ? \
- (t_##name) GetProcAddress(module, STR(name)) : NULL))
-#define GET_WINDOWS_FUNCTION(module, name) \
- TYPECHECK((t_##name)NULL == name, \
- (p_##name = module ? \
- (t_##name) GetProcAddress(module, #name) : NULL))
-#define GET_WINDOWS_FUNCTION_NO_TYPECHECK(module, name) \
- (p_##name = module ? \
- (t_##name) GetProcAddress(module, #name) : NULL)
-
-#define PUTTY_REG_POS "Software\\SimonTatham\\PuTTY"
-#define PUTTY_REG_PARENT "Software\\SimonTatham"
-#define PUTTY_REG_PARENT_CHILD "PuTTY"
-#define PUTTY_REG_GPARENT "Software"
-#define PUTTY_REG_GPARENT_CHILD "SimonTatham"
-
-/* Result values for the jumplist registry functions. */
-#define JUMPLISTREG_OK 0
-#define JUMPLISTREG_ERROR_INVALID_PARAMETER 1
-#define JUMPLISTREG_ERROR_KEYOPENCREATE_FAILURE 2
-#define JUMPLISTREG_ERROR_VALUEREAD_FAILURE 3
-#define JUMPLISTREG_ERROR_VALUEWRITE_FAILURE 4
-#define JUMPLISTREG_ERROR_INVALID_VALUE 5
-
-#define PUTTY_CHM_FILE "putty.chm"
-
-#define GETTICKCOUNT GetTickCount
-#define CURSORBLINK GetCaretBlinkTime()
-#define TICKSPERSEC 1000 /* GetTickCount returns milliseconds */
-
-#define DEFAULT_CODEPAGE CP_ACP
-#define USES_VTLINE_HACK
-
-#ifndef NO_GSSAPI
-/*
- * GSS-API stuff
- */
-#define GSS_CC CALLBACK
-/*
-typedef struct Ssh_gss_buf {
- size_t length;
- char *value;
-} Ssh_gss_buf;
-
-#define SSH_GSS_EMPTY_BUF (Ssh_gss_buf) {0,NULL}
-typedef void *Ssh_gss_name;
-*/
-#endif
-
-/*
- * The all-important instance handle, saved from WinMain in every GUI
- * program and exported for other GUI code to pass back to the Windows
- * API.
- */
-extern HINSTANCE hinst;
-
-/*
- * Help file stuff in winhelp.c.
- */
-void init_help(void);
-void shutdown_help(void);
-bool has_help(void);
-void launch_help(HWND hwnd, const char *topic);
-void quit_help(HWND hwnd);
-int has_embedded_chm(void); /* 1 = yes, 0 = no, -1 = N/A */
-
-/*
- * GUI seat methods in windlg.c, so that the vtable definition in
- * window.c can refer to them.
- */
-int win_seat_verify_ssh_host_key(
- Seat *seat, const char *host, int port, const char *keytype,
- char *keystr, const char *keydisp, char **key_fingerprints,
- void (*callback)(void *ctx, int result), void *ctx);
-int win_seat_confirm_weak_crypto_primitive(
- Seat *seat, const char *algtype, const char *algname,
- void (*callback)(void *ctx, int result), void *ctx);
-int win_seat_confirm_weak_cached_hostkey(
- Seat *seat, const char *algname, const char *betteralgs,
- void (*callback)(void *ctx, int result), void *ctx);
-
-/*
- * Windows-specific clipboard helper function shared with windlg.c,
- * which takes the data string in the system code page instead of
- * Unicode.
- */
-void write_aclip(int clipboard, char *, int, bool);
-
-#define WM_NETEVENT (WM_APP + 5)
-
-/*
- * On Windows, we send MA_2CLK as the only event marking the second
- * press of a mouse button. Compare unix.h.
- */
-#define MULTICLICK_ONLY_EVENT 1
-
-/*
- * On Windows, data written to the clipboard must be NUL-terminated.
- */
-#define SELECTION_NUL_TERMINATED 1
-
-/*
- * On Windows, copying to the clipboard terminates lines with CRLF.
- */
-#define SEL_NL { 13, 10 }
-
-/*
- * sk_getxdmdata() does not exist under Windows (not that I
- * couldn't write it if I wanted to, but I haven't bothered), so
- * it's a macro which always returns NULL. With any luck this will
- * cause the compiler to notice it can optimise away the
- * implementation of XDM-AUTHORIZATION-1 in x11fwd.c :-)
- */
-#define sk_getxdmdata(socket, lenp) (NULL)
-
-/*
- * File-selector filter strings used in the config box. On Windows,
- * these strings are of exactly the type needed to go in
- * `lpstrFilter' in an OPENFILENAME structure.
- */
-#define FILTER_KEY_FILES ("PuTTY Private Key Files (*.ppk)\0*.ppk\0" \
- "All Files (*.*)\0*\0\0\0")
-#define FILTER_WAVE_FILES ("Wave Files (*.wav)\0*.WAV\0" \
- "All Files (*.*)\0*\0\0\0")
-#define FILTER_DYNLIB_FILES ("Dynamic Library Files (*.dll)\0*.dll\0" \
- "All Files (*.*)\0*\0\0\0")
-
-/*
- * Exports from winnet.c.
- */
-/* Report an event notification from WSA*Select */
-void select_result(WPARAM, LPARAM);
-/* Enumerate all currently live OS-level SOCKETs */
-SOCKET first_socket(int *);
-SOCKET next_socket(int *);
-/* Ask winnet.c whether we currently want to try to write to a SOCKET */
-bool socket_writable(SOCKET skt);
-/* Force a refresh of the SOCKET list by re-calling do_select for each one */
-void socket_reselect_all(void);
-/* Make a SockAddr which just holds a named pipe address. */
-SockAddr *sk_namedpipe_addr(const char *pipename);
-/* Turn a WinSock error code into a string. */
-const char *winsock_error_string(int error);
-
-/*
- * winnet.c dynamically loads WinSock 2 or WinSock 1 depending on
- * what it can get, which means any WinSock routines used outside
- * that module must be exported from it as function pointers. So
- * here they are.
- */
-DECL_WINDOWS_FUNCTION(extern, int, WSAAsyncSelect,
- (SOCKET, HWND, u_int, long));
-DECL_WINDOWS_FUNCTION(extern, int, WSAEventSelect,
- (SOCKET, WSAEVENT, long));
-DECL_WINDOWS_FUNCTION(extern, int, WSAGetLastError, (void));
-DECL_WINDOWS_FUNCTION(extern, int, WSAEnumNetworkEvents,
- (SOCKET, WSAEVENT, LPWSANETWORKEVENTS));
-#ifdef NEED_DECLARATION_OF_SELECT
-/* This declaration is protected by an ifdef for the sake of building
- * against winelib, in which you have to include winsock2.h before
- * stdlib.h so that the right fd_set type gets defined. It would be a
- * pain to do that throughout this codebase, so instead I arrange that
- * only a modules actually needing to use (or define, or initialise)
- * this function pointer will see its declaration, and _those_ modules
- * - which will be Windows-specific anyway - can take more care. */
-DECL_WINDOWS_FUNCTION(extern, int, select,
- (int, fd_set FAR *, fd_set FAR *,
- fd_set FAR *, const struct timeval FAR *));
-#endif
-
-/*
- * Implemented differently depending on the client of winnet.c, and
- * called by winnet.c to turn on or off WSA*Select for a given socket.
- */
-const char *do_select(SOCKET skt, bool enable);
-
-/*
- * Exports from winselgui.c and winselcli.c, each of which provides an
- * implementation of do_select.
- */
-void winselgui_set_hwnd(HWND hwnd);
-void winselgui_clear_hwnd(void);
-
-void winselcli_setup(void);
-SOCKET winselcli_unique_socket(void);
-extern HANDLE winselcli_event;
-
-/*
- * Network-subsystem-related functions provided in other Windows modules.
- */
-Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H,
- Plug *plug, bool overlapped); /* winhsock */
-Socket *new_named_pipe_client(const char *pipename, Plug *plug); /* winnpc */
-Socket *new_named_pipe_listener(const char *pipename, Plug *plug); /* winnps */
-
-/* A lower-level function in winnpc.c, which does most of the work of
- * new_named_pipe_client (including checking the ownership of what
- * it's connected to), but returns a plain HANDLE instead of wrapping
- * it into a Socket. */
-HANDLE connect_to_named_pipe(const char *pipename, char **err);
-
-/*
- * Exports from winctrls.c.
- */
-
-struct ctlpos {
- HWND hwnd;
- WPARAM font;
- int dlu4inpix;
- int ypos, width;
- int xoff;
- int boxystart, boxid;
- char *boxtext;
-};
-void init_common_controls(void); /* also does some DLL-loading */
-
-/*
- * Exports from winutils.c.
- */
-typedef struct filereq_tag filereq; /* cwd for file requester */
-bool request_file(filereq *state, OPENFILENAME *of, bool preserve, bool save);
-filereq *filereq_new(void);
-void filereq_free(filereq *state);
-void pgp_fingerprints_msgbox(HWND owner);
-int message_box(HWND owner, LPCTSTR text, LPCTSTR caption,
- DWORD style, DWORD helpctxid);
-void MakeDlgItemBorderless(HWND parent, int id);
-char *GetDlgItemText_alloc(HWND hwnd, int id);
-void split_into_argv(char *, int *, char ***, char ***);
-
-/*
- * Private structure for prefslist state. Only in the header file
- * so that we can delegate allocation to callers.
- */
-struct prefslist {
- int listid, upbid, dnbid;
- int srcitem;
- int dummyitem;
- bool dragging;
-};
-
-/*
- * This structure is passed to event handler functions as the `dlg'
- * parameter, and hence is passed back to winctrls access functions.
- */
-struct dlgparam {
- HWND hwnd; /* the hwnd of the dialog box */
- struct winctrls *controltrees[8]; /* can have several of these */
- int nctrltrees;
- char *wintitle; /* title of actual window */
- char *errtitle; /* title of error sub-messageboxes */
- void *data; /* data to pass in refresh events */
- union control *focused, *lastfocused; /* which ctrl has focus now/before */
- bool shortcuts[128]; /* track which shortcuts in use */
- bool coloursel_wanted; /* has an event handler asked for
- * a colour selector? */
- struct {
- unsigned char r, g, b; /* 0-255 */
- bool ok;
- } coloursel_result;
- tree234 *privdata; /* stores per-control private data */
- bool ended; /* has the dialog been ended? */
- int endresult; /* and if so, what was the result? */
- bool fixed_pitch_fonts; /* are we constrained to fixed fonts? */
-};
-
-/*
- * Exports from winctrls.c.
- */
-void ctlposinit(struct ctlpos *cp, HWND hwnd,
- int leftborder, int rightborder, int topborder);
-HWND doctl(struct ctlpos *cp, RECT r,
- char *wclass, int wstyle, int exstyle, char *wtext, int wid);
-void bartitle(struct ctlpos *cp, char *name, int id);
-void beginbox(struct ctlpos *cp, char *name, int idbox);
-void endbox(struct ctlpos *cp);
-void editboxfw(struct ctlpos *cp, bool password, char *text,
- int staticid, int editid);
-void radioline(struct ctlpos *cp, char *text, int id, int nacross, ...);
-void bareradioline(struct ctlpos *cp, int nacross, ...);
-void radiobig(struct ctlpos *cp, char *text, int id, ...);
-void checkbox(struct ctlpos *cp, char *text, int id);
-void statictext(struct ctlpos *cp, char *text, int lines, int id);
-void staticbtn(struct ctlpos *cp, char *stext, int sid,
- char *btext, int bid);
-void static2btn(struct ctlpos *cp, char *stext, int sid,
- char *btext1, int bid1, char *btext2, int bid2);
-void staticedit(struct ctlpos *cp, char *stext,
- int sid, int eid, int percentedit);
-void staticddl(struct ctlpos *cp, char *stext,
- int sid, int lid, int percentlist);
-void combobox(struct ctlpos *cp, char *text, int staticid, int listid);
-void staticpassedit(struct ctlpos *cp, char *stext,
- int sid, int eid, int percentedit);
-void bigeditctrl(struct ctlpos *cp, char *stext,
- int sid, int eid, int lines);
-void ersatztab(struct ctlpos *cp, char *stext, int sid, int lid, int s2id);
-void editbutton(struct ctlpos *cp, char *stext, int sid,
- int eid, char *btext, int bid);
-void sesssaver(struct ctlpos *cp, char *text,
- int staticid, int editid, int listid, ...);
-void envsetter(struct ctlpos *cp, char *stext, int sid,
- char *e1stext, int e1sid, int e1id,
- char *e2stext, int e2sid, int e2id,
- int listid, char *b1text, int b1id, char *b2text, int b2id);
-void charclass(struct ctlpos *cp, char *stext, int sid, int listid,
- char *btext, int bid, int eid, char *s2text, int s2id);
-void colouredit(struct ctlpos *cp, char *stext, int sid, int listid,
- char *btext, int bid, ...);
-void prefslist(struct prefslist *hdl, struct ctlpos *cp, int lines,
- char *stext, int sid, int listid, int upbid, int dnbid);
-int handle_prefslist(struct prefslist *hdl,
- int *array, int maxmemb,
- bool is_dlmsg, HWND hwnd,
- WPARAM wParam, LPARAM lParam);
-void progressbar(struct ctlpos *cp, int id);
-void fwdsetter(struct ctlpos *cp, int listid, char *stext, int sid,
- char *e1stext, int e1sid, int e1id,
- char *e2stext, int e2sid, int e2id,
- char *btext, int bid,
- char *r1text, int r1id, char *r2text, int r2id);
-
-void dlg_auto_set_fixed_pitch_flag(dlgparam *dlg);
-bool dlg_get_fixed_pitch_flag(dlgparam *dlg);
-void dlg_set_fixed_pitch_flag(dlgparam *dlg, bool flag);
-
-#define MAX_SHORTCUTS_PER_CTRL 16
-
-/*
- * This structure is what's stored for each `union control' in the
- * portable-dialog interface.
- */
-struct winctrl {
- union control *ctrl;
- /*
- * The control may have several components at the Windows
- * level, with different dialog IDs. To avoid needing N
- * separate platformsidectrl structures (which could be stored
- * separately in a tree234 so that lookup by ID worked), we
- * impose the constraint that those IDs must be in a contiguous
- * block.
- */
- int base_id;
- int num_ids;
- /*
- * For vertical alignment, the id of a particular representative
- * control that has the y-extent of the sensible part of the
- * control.
- */
- int align_id;
- /*
- * Remember what keyboard shortcuts were used by this control,
- * so that when we remove it again we can take them out of the
- * list in the dlgparam.
- */
- char shortcuts[MAX_SHORTCUTS_PER_CTRL];
- /*
- * Some controls need a piece of allocated memory in which to
- * store temporary data about the control.
- */
- void *data;
-};
-/*
- * And this structure holds a set of the above, in two separate
- * tree234s so that it can find an item by `union control' or by
- * dialog ID.
- */
-struct winctrls {
- tree234 *byctrl, *byid;
-};
-struct controlset;
-struct controlbox;
-
-void winctrl_init(struct winctrls *);
-void winctrl_cleanup(struct winctrls *);
-void winctrl_add(struct winctrls *, struct winctrl *);
-void winctrl_remove(struct winctrls *, struct winctrl *);
-struct winctrl *winctrl_findbyctrl(struct winctrls *, union control *);
-struct winctrl *winctrl_findbyid(struct winctrls *, int);
-struct winctrl *winctrl_findbyindex(struct winctrls *, int);
-void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
- struct ctlpos *cp, struct controlset *s, int *id);
-bool winctrl_handle_command(struct dlgparam *dp, UINT msg,
- WPARAM wParam, LPARAM lParam);
-void winctrl_rem_shortcuts(struct dlgparam *dp, struct winctrl *c);
-bool winctrl_context_help(struct dlgparam *dp, HWND hwnd, int id);
-
-void dp_init(struct dlgparam *dp);
-void dp_add_tree(struct dlgparam *dp, struct winctrls *tree);
-void dp_cleanup(struct dlgparam *dp);
-
-/*
- * Exports from wincfg.c.
- */
-void win_setup_config_box(struct controlbox *b, HWND *hwndp, bool has_help,
- bool midsession, int protocol);
-
-/*
- * Exports from windlg.c.
- */
-void defuse_showwindow(void);
-bool do_config(Conf *);
-bool do_reconfig(HWND, Conf *, int);
-void showeventlog(HWND);
-void showabout(HWND);
-void force_normal(HWND hwnd);
-void modal_about_box(HWND hwnd);
-void show_help(HWND hwnd);
-HWND event_log_window(void);
-
-/*
- * Exports from winmisc.c.
- */
-extern DWORD osMajorVersion, osMinorVersion, osPlatformId;
-void init_winver(void);
-void dll_hijacking_protection(void);
-HMODULE load_system32_dll(const char *libname);
-const char *win_strerror(int error);
-void restrict_process_acl(void);
-bool restricted_acl(void);
-void escape_registry_key(const char *in, strbuf *out);
-void unescape_registry_key(const char *in, strbuf *out);
-
-bool is_console_handle(HANDLE);
-
-/* A few pieces of up-to-date Windows API definition needed for older
- * compilers. */
-#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32
-#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
-#endif
-#ifndef LOAD_LIBRARY_SEARCH_USER_DIRS
-#define LOAD_LIBRARY_SEARCH_USER_DIRS 0x00000400
-#endif
-#ifndef LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
-#define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 0x00000100
-#endif
-#ifndef DLL_DIRECTORY_COOKIE
-typedef PVOID DLL_DIRECTORY_COOKIE;
-DECLSPEC_IMPORT DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory (PCWSTR NewDirectory);
-#endif
-
-/*
- * Exports from sizetip.c.
- */
-void UpdateSizeTip(HWND src, int cx, int cy);
-void EnableSizeTip(bool bEnable);
-
-/*
- * Exports from unicode.c.
- */
-struct unicode_data;
-void init_ucs(Conf *, struct unicode_data *);
-
-/*
- * Exports from winhandl.c.
- */
-#define HANDLE_FLAG_OVERLAPPED 1
-#define HANDLE_FLAG_IGNOREEOF 2
-#define HANDLE_FLAG_UNITBUFFER 4
-struct handle;
-typedef size_t (*handle_inputfn_t)(
- struct handle *h, const void *data, size_t len, int err);
-typedef void (*handle_outputfn_t)(
- struct handle *h, size_t new_backlog, int err);
-struct handle *handle_input_new(HANDLE handle, handle_inputfn_t gotdata,
- void *privdata, int flags);
-struct handle *handle_output_new(HANDLE handle, handle_outputfn_t sentdata,
- void *privdata, int flags);
-size_t handle_write(struct handle *h, const void *data, size_t len);
-void handle_write_eof(struct handle *h);
-HANDLE *handle_get_events(int *nevents);
-void handle_free(struct handle *h);
-void handle_got_event(HANDLE event);
-void handle_unthrottle(struct handle *h, size_t backlog);
-size_t handle_backlog(struct handle *h);
-void *handle_get_privdata(struct handle *h);
-struct handle *handle_add_foreign_event(HANDLE event,
- void (*callback)(void *), void *ctx);
-/* Analogue of stdio_sink in marshal.h, for a Windows handle */
-struct handle_sink {
- struct handle *h;
- BinarySink_IMPLEMENTATION;
-};
-void handle_sink_init(handle_sink *sink, struct handle *h);
-
-/*
- * Exports from winpgntc.c.
- */
-char *agent_named_pipe_name(void);
-
-/*
- * Exports from winser.c.
- */
-extern const struct BackendVtable serial_backend;
-
-/*
- * Exports from winjump.c.
- */
-#define JUMPLIST_SUPPORTED /* suppress #defines in putty.h */
-void add_session_to_jumplist(const char * const sessionname);
-void remove_session_from_jumplist(const char * const sessionname);
-void clear_jumplist(void);
-bool set_explicit_app_user_model_id(void);
-
-/*
- * Exports from winnoise.c.
- */
-bool win_read_random(void *buf, unsigned wanted); /* returns true on success */
-
-/*
- * Extra functions in winstore.c over and above the interface in
- * storage.h.
- *
- * These functions manipulate the Registry section which mirrors the
- * current Windows 7 jump list. (Because the real jump list storage is
- * write-only, we need to keep another copy of whatever we put in it,
- * so that we can put in a slightly modified version the next time.)
- */
-
-/* Adds a saved session to the registry jump list mirror. 'item' is a
- * string naming a saved session. */
-int add_to_jumplist_registry(const char *item);
-
-/* Removes an item from the registry jump list mirror. */
-int remove_from_jumplist_registry(const char *item);
-
-/* Returns the current jump list entries from the registry. Caller
- * must free the returned pointer, which points to a contiguous
- * sequence of NUL-terminated strings in memory, terminated with an
- * empty one. */
-char *get_jumplist_registry_entries(void);
-
-/*
- * Windows clipboard-UI wording.
- */
-#define CLIPNAME_IMPLICIT "Last selected text"
-#define CLIPNAME_EXPLICIT "System clipboard"
-#define CLIPNAME_EXPLICIT_OBJECT "system clipboard"
-/* These defaults are the ones PuTTY has historically had */
-#define CLIPUI_DEFAULT_AUTOCOPY true
-#define CLIPUI_DEFAULT_MOUSE CLIPUI_EXPLICIT
-#define CLIPUI_DEFAULT_INS CLIPUI_EXPLICIT
-
-/* In winmisc.c */
-char *registry_get_string(HKEY root, const char *path, const char *leaf);
-
-/* In wincliloop.c */
-typedef bool (*cliloop_pre_t)(void *vctx, const HANDLE **extra_handles,
- size_t *n_extra_handles);
-typedef bool (*cliloop_post_t)(void *vctx, size_t extra_handle_index);
-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_post(void *vctx, size_t);
-
-#endif
diff --git a/WINDOWS/WINTIME.C b/WINDOWS/WINTIME.C
deleted file mode 100644
index 5fa3b0de..00000000
--- a/WINDOWS/WINTIME.C
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * wintime.c - Avoid trouble with time() returning (time_t)-1 on Windows.
- */
-
-#include "putty.h"
-#include <time.h>
-
-struct tm ltime(void)
-{
- SYSTEMTIME st;
- struct tm tm;
-
- memset(&tm, 0, sizeof(tm)); /* in case there are any other fields */
-
- GetLocalTime(&st);
- tm.tm_sec=st.wSecond;
- tm.tm_min=st.wMinute;
- tm.tm_hour=st.wHour;
- tm.tm_mday=st.wDay;
- tm.tm_mon=st.wMonth-1;
- tm.tm_year=(st.wYear>=1900?st.wYear-1900:0);
- tm.tm_wday=st.wDayOfWeek;
- tm.tm_yday=-1; /* GetLocalTime doesn't tell us */
- tm.tm_isdst=0; /* GetLocalTime doesn't tell us */
- return tm;
-}
diff --git a/WINDOWS/WINUCS.C b/WINDOWS/WINUCS.C
deleted file mode 100644
index 9ffff5e9..00000000
--- a/WINDOWS/WINUCS.C
+++ /dev/null
@@ -1,1213 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <time.h>
-#include <assert.h>
-
-#include "putty.h"
-#include "terminal.h"
-#include "misc.h"
-
-/* Character conversion arrays; they are usually taken from windows,
- * the xterm one has the four scanlines that have no unicode 2.0
- * equivalents mapped to their unicode 3.0 locations.
- */
-static const WCHAR unitab_xterm_std[32] = {
- 0x2666, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
- 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
- 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
- 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x0020
-};
-
-/*
- * If the codepage is non-zero it's a window codepage, zero means use a
- * local codepage. The name is always converted to the first of any
- * duplicate definitions.
- */
-
-/*
- * Tables for ISO-8859-{1-10,13-16} derived from those downloaded
- * 2001-10-02 from <http://www.unicode.org/Public/MAPPINGS/> -- jtn
- * Table for ISO-8859-11 derived from same on 2002-11-18. -- bjh21
- */
-
-/* XXX: This could be done algorithmically, but I'm not sure it's
- * worth the hassle -- jtn */
-/* ISO/IEC 8859-1:1998 (Latin-1, "Western", "West European") */
-static const wchar_t iso_8859_1[] = {
- 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
- 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
- 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
- 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
- 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
- 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
- 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
- 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
- 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
- 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
- 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
- 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
-};
-
-/* ISO/IEC 8859-2:1999 (Latin-2, "Central European", "East European") */
-static const wchar_t iso_8859_2[] = {
- 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7,
- 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B,
- 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7,
- 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C,
- 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
- 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
- 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
- 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
- 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
- 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
- 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
- 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
-};
-
-/* ISO/IEC 8859-3:1999 (Latin-3, "South European", "Maltese & Esperanto") */
-static const wchar_t iso_8859_3[] = {
- 0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, 0xFFFD, 0x0124, 0x00A7,
- 0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, 0xFFFD, 0x017B,
- 0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7,
- 0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, 0xFFFD, 0x017C,
- 0x00C0, 0x00C1, 0x00C2, 0xFFFD, 0x00C4, 0x010A, 0x0108, 0x00C7,
- 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
- 0xFFFD, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7,
- 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF,
- 0x00E0, 0x00E1, 0x00E2, 0xFFFD, 0x00E4, 0x010B, 0x0109, 0x00E7,
- 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
- 0xFFFD, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7,
- 0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9
-};
-
-/* ISO/IEC 8859-4:1998 (Latin-4, "North European") */
-static const wchar_t iso_8859_4[] = {
- 0x00A0, 0x0104, 0x0138, 0x0156, 0x00A4, 0x0128, 0x013B, 0x00A7,
- 0x00A8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00AD, 0x017D, 0x00AF,
- 0x00B0, 0x0105, 0x02DB, 0x0157, 0x00B4, 0x0129, 0x013C, 0x02C7,
- 0x00B8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014A, 0x017E, 0x014B,
- 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E,
- 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A,
- 0x0110, 0x0145, 0x014C, 0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
- 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x0168, 0x016A, 0x00DF,
- 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F,
- 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x012B,
- 0x0111, 0x0146, 0x014D, 0x0137, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
- 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x0169, 0x016B, 0x02D9
-};
-
-/* ISO/IEC 8859-5:1999 (Latin/Cyrillic) */
-static const wchar_t iso_8859_5[] = {
- 0x00A0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407,
- 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F,
- 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
- 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
- 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
- 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
- 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
- 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
- 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
- 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
- 0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
- 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F
-};
-
-/* ISO/IEC 8859-6:1999 (Latin/Arabic) */
-static const wchar_t iso_8859_6[] = {
- 0x00A0, 0xFFFD, 0xFFFD, 0xFFFD, 0x00A4, 0xFFFD, 0xFFFD, 0xFFFD,
- 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x060C, 0x00AD, 0xFFFD, 0xFFFD,
- 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
- 0xFFFD, 0xFFFD, 0xFFFD, 0x061B, 0xFFFD, 0xFFFD, 0xFFFD, 0x061F,
- 0xFFFD, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
- 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
- 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637,
- 0x0638, 0x0639, 0x063A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
- 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647,
- 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F,
- 0x0650, 0x0651, 0x0652, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
- 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD
-};
-
-/* ISO 8859-7:1987 (Latin/Greek) */
-static const wchar_t iso_8859_7[] = {
- 0x00A0, 0x2018, 0x2019, 0x00A3, 0xFFFD, 0xFFFD, 0x00A6, 0x00A7,
- 0x00A8, 0x00A9, 0xFFFD, 0x00AB, 0x00AC, 0x00AD, 0xFFFD, 0x2015,
- 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x0385, 0x0386, 0x00B7,
- 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F,
- 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
- 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
- 0x03A0, 0x03A1, 0xFFFD, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
- 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
- 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
- 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
- 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
- 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0xFFFD
-};
-
-/* ISO/IEC 8859-8:1999 (Latin/Hebrew) */
-static const wchar_t iso_8859_8[] = {
- 0x00A0, 0xFFFD, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
- 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
- 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
- 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0xFFFD,
- 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
- 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
- 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
- 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x2017,
- 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
- 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
- 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
- 0x05E8, 0x05E9, 0x05EA, 0xFFFD, 0xFFFD, 0x200E, 0x200F, 0xFFFD
-};
-
-/* ISO/IEC 8859-9:1999 (Latin-5, "Turkish") */
-static const wchar_t iso_8859_9[] = {
- 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
- 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
- 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
- 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
- 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
- 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
- 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
- 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF,
- 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
- 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
- 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
- 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF
-};
-
-/* ISO/IEC 8859-10:1998 (Latin-6, "Nordic" [Sami, Inuit, Icelandic]) */
-static const wchar_t iso_8859_10[] = {
- 0x00A0, 0x0104, 0x0112, 0x0122, 0x012A, 0x0128, 0x0136, 0x00A7,
- 0x013B, 0x0110, 0x0160, 0x0166, 0x017D, 0x00AD, 0x016A, 0x014A,
- 0x00B0, 0x0105, 0x0113, 0x0123, 0x012B, 0x0129, 0x0137, 0x00B7,
- 0x013C, 0x0111, 0x0161, 0x0167, 0x017E, 0x2015, 0x016B, 0x014B,
- 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E,
- 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x00CF,
- 0x00D0, 0x0145, 0x014C, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0168,
- 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
- 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F,
- 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x00EF,
- 0x00F0, 0x0146, 0x014D, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0169,
- 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x0138
-};
-
-/* ISO/IEC 8859-11:2001 ("Thai", "TIS620") */
-static const wchar_t iso_8859_11[] = {
- 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07,
- 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F,
- 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17,
- 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F,
- 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
- 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
- 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
- 0x0E38, 0x0E39, 0x0E3A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x0E3F,
- 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47,
- 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F,
- 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57,
- 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD
-};
-
-/* ISO/IEC 8859-13:1998 (Latin-7, "Baltic Rim") */
-static const wchar_t iso_8859_13[] = {
- 0x00A0, 0x201D, 0x00A2, 0x00A3, 0x00A4, 0x201E, 0x00A6, 0x00A7,
- 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6,
- 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x201C, 0x00B5, 0x00B6, 0x00B7,
- 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6,
- 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112,
- 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B,
- 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7,
- 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF,
- 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113,
- 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C,
- 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7,
- 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x2019
-};
-
-/* ISO/IEC 8859-14:1998 (Latin-8, "Celtic", "Gaelic/Welsh") */
-static const wchar_t iso_8859_14[] = {
- 0x00A0, 0x1E02, 0x1E03, 0x00A3, 0x010A, 0x010B, 0x1E0A, 0x00A7,
- 0x1E80, 0x00A9, 0x1E82, 0x1E0B, 0x1EF2, 0x00AD, 0x00AE, 0x0178,
- 0x1E1E, 0x1E1F, 0x0120, 0x0121, 0x1E40, 0x1E41, 0x00B6, 0x1E56,
- 0x1E81, 0x1E57, 0x1E83, 0x1E60, 0x1EF3, 0x1E84, 0x1E85, 0x1E61,
- 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
- 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
- 0x0174, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x1E6A,
- 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x0176, 0x00DF,
- 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
- 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
- 0x0175, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x1E6B,
- 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x0177, 0x00FF
-};
-
-/* ISO/IEC 8859-15:1999 (Latin-9 aka -0, "euro") */
-static const wchar_t iso_8859_15[] = {
- 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0160, 0x00A7,
- 0x0161, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
- 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x017D, 0x00B5, 0x00B6, 0x00B7,
- 0x017E, 0x00B9, 0x00BA, 0x00BB, 0x0152, 0x0153, 0x0178, 0x00BF,
- 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
- 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
- 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
- 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
- 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
- 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
- 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
- 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
-};
-
-/* ISO/IEC 8859-16:2001 (Latin-10, "Balkan") */
-static const wchar_t iso_8859_16[] = {
- 0x00A0, 0x0104, 0x0105, 0x0141, 0x20AC, 0x201E, 0x0160, 0x00A7,
- 0x0161, 0x00A9, 0x0218, 0x00AB, 0x0179, 0x00AD, 0x017A, 0x017B,
- 0x00B0, 0x00B1, 0x010C, 0x0142, 0x017D, 0x201D, 0x00B6, 0x00B7,
- 0x017E, 0x010D, 0x0219, 0x00BB, 0x0152, 0x0153, 0x0178, 0x017C,
- 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0106, 0x00C6, 0x00C7,
- 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
- 0x0110, 0x0143, 0x00D2, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x015A,
- 0x0170, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0118, 0x021A, 0x00DF,
- 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x0107, 0x00E6, 0x00E7,
- 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
- 0x0111, 0x0144, 0x00F2, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x015B,
- 0x0171, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0119, 0x021B, 0x00FF
-};
-
-static const wchar_t roman8[] = {
- 0x00A0, 0x00C0, 0x00C2, 0x00C8, 0x00CA, 0x00CB, 0x00CE, 0x00CF,
- 0x00B4, 0x02CB, 0x02C6, 0x00A8, 0x02DC, 0x00D9, 0x00DB, 0x20A4,
- 0x00AF, 0x00DD, 0x00FD, 0x00B0, 0x00C7, 0x00E7, 0x00D1, 0x00F1,
- 0x00A1, 0x00BF, 0x00A4, 0x00A3, 0x00A5, 0x00A7, 0x0192, 0x00A2,
- 0x00E2, 0x00EA, 0x00F4, 0x00FB, 0x00E1, 0x00E9, 0x00F3, 0x00FA,
- 0x00E0, 0x00E8, 0x00F2, 0x00F9, 0x00E4, 0x00EB, 0x00F6, 0x00FC,
- 0x00C5, 0x00EE, 0x00D8, 0x00C6, 0x00E5, 0x00ED, 0x00F8, 0x00E6,
- 0x00C4, 0x00EC, 0x00D6, 0x00DC, 0x00C9, 0x00EF, 0x00DF, 0x00D4,
- 0x00C1, 0x00C3, 0x00E3, 0x00D0, 0x00F0, 0x00CD, 0x00CC, 0x00D3,
- 0x00D2, 0x00D5, 0x00F5, 0x0160, 0x0161, 0x00DA, 0x0178, 0x00FF,
- 0x00DE, 0x00FE, 0x00B7, 0x00B5, 0x00B6, 0x00BE, 0x2014, 0x00BC,
- 0x00BD, 0x00AA, 0x00BA, 0x00AB, 0x25A0, 0x00BB, 0x00B1, 0xFFFD
-};
-
-static const wchar_t koi8_u[] = {
- 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524,
- 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590,
- 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2022, 0x221A, 0x2248,
- 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7,
- 0x2550, 0x2551, 0x2552, 0x0451, 0x0454, 0x2554, 0x0456, 0x0457,
- 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x0491, 0x255D, 0x255E,
- 0x255F, 0x2560, 0x2561, 0x0401, 0x0404, 0x2563, 0x0406, 0x0407,
- 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x0490, 0x256C, 0x00A9,
- 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
- 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
- 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432,
- 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A,
- 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
- 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
- 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
- 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A
-};
-
-static const wchar_t vscii[] = {
- 0x0000, 0x0001, 0x1EB2, 0x0003, 0x0004, 0x1EB4, 0x1EAA, 0x0007,
- 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
- 0x0010, 0x0011, 0x0012, 0x0013, 0x1EF6, 0x0015, 0x0016, 0x0017,
- 0x0018, 0x1EF8, 0x001a, 0x001b, 0x001c, 0x001d, 0x1EF4, 0x001f,
- 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
- 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
- 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
- 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
- 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
- 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
- 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
- 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
- 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
- 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
- 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
- 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007f,
- 0x1EA0, 0x1EAE, 0x1EB0, 0x1EB6, 0x1EA4, 0x1EA6, 0x1EA8, 0x1EAC,
- 0x1EBC, 0x1EB8, 0x1EBE, 0x1EC0, 0x1EC2, 0x1EC4, 0x1EC6, 0x1ED0,
- 0x1ED2, 0x1ED4, 0x1ED6, 0x1ED8, 0x1EE2, 0x1EDA, 0x1EDC, 0x1EDE,
- 0x1ECA, 0x1ECE, 0x1ECC, 0x1EC8, 0x1EE6, 0x0168, 0x1EE4, 0x1EF2,
- 0x00D5, 0x1EAF, 0x1EB1, 0x1EB7, 0x1EA5, 0x1EA7, 0x1EA8, 0x1EAD,
- 0x1EBD, 0x1EB9, 0x1EBF, 0x1EC1, 0x1EC3, 0x1EC5, 0x1EC7, 0x1ED1,
- 0x1ED3, 0x1ED5, 0x1ED7, 0x1EE0, 0x01A0, 0x1ED9, 0x1EDD, 0x1EDF,
- 0x1ECB, 0x1EF0, 0x1EE8, 0x1EEA, 0x1EEC, 0x01A1, 0x1EDB, 0x01AF,
- 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x1EA2, 0x0102, 0x1EB3, 0x1EB5,
- 0x00C8, 0x00C9, 0x00CA, 0x1EBA, 0x00CC, 0x00CD, 0x0128, 0x1EF3,
- 0x0110, 0x1EE9, 0x00D2, 0x00D3, 0x00D4, 0x1EA1, 0x1EF7, 0x1EEB,
- 0x1EED, 0x00D9, 0x00DA, 0x1EF9, 0x1EF5, 0x00DD, 0x1EE1, 0x01B0,
- 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x1EA3, 0x0103, 0x1EEF, 0x1EAB,
- 0x00E8, 0x00E9, 0x00EA, 0x1EBB, 0x00EC, 0x00ED, 0x0129, 0x1EC9,
- 0x0111, 0x1EF1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x1ECF, 0x1ECD,
- 0x1EE5, 0x00F9, 0x00FA, 0x0169, 0x1EE7, 0x00FD, 0x1EE3, 0x1EEE
-};
-
-static const wchar_t dec_mcs[] = {
- 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0xFFFD, 0x00A5, 0xFFFD, 0x00A7,
- 0x00A4, 0x00A9, 0x00AA, 0x00AB, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
- 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0xFFFD, 0x00B5, 0x00B6, 0x00B7,
- 0xFFFD, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0xFFFD, 0x00BF,
- 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
- 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
- 0xFFFD, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0152,
- 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0178, 0xFFFD, 0x00DF,
- 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
- 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
- 0xFFFD, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0153,
- 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FF, 0xFFFD, 0xFFFD
-};
-
-/* Mazovia (Polish) aka CP620
- * from "Mazowia to Unicode table", 04/24/96, Mikolaj Jedrzejak */
-static const wchar_t mazovia[] = {
- /* Code point 0x9B is "zloty" symbol (z&#0142;), which is not
- * widely used and for which there is no Unicode equivalent.
- * One reference shows 0xA8 as U+00A7 SECTION SIGN, but we're
- * told that's incorrect. */
- 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x0105, 0x00E7,
- 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0107, 0x00C4, 0x0104,
- 0x0118, 0x0119, 0x0142, 0x00F4, 0x00F6, 0x0106, 0x00FB, 0x00F9,
- 0x015a, 0x00D6, 0x00DC, 0xFFFD, 0x0141, 0x00A5, 0x015b, 0x0192,
- 0x0179, 0x017b, 0x00F3, 0x00d3, 0x0144, 0x0143, 0x017a, 0x017c,
- 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
- 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
- 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
- 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
- 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
- 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
- 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
- 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
- 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
- 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
- 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
-};
-
-struct cp_list_item {
- char *name;
- int codepage;
- int cp_size;
- const wchar_t *cp_table;
-};
-
-static const struct cp_list_item cp_list[] = {
- {"UTF-8", CP_UTF8},
-
- {"ISO-8859-1:1998 (Latin-1, West Europe)", 0, 96, iso_8859_1},
- {"ISO-8859-2:1999 (Latin-2, East Europe)", 0, 96, iso_8859_2},
- {"ISO-8859-3:1999 (Latin-3, South Europe)", 0, 96, iso_8859_3},
- {"ISO-8859-4:1998 (Latin-4, North Europe)", 0, 96, iso_8859_4},
- {"ISO-8859-5:1999 (Latin/Cyrillic)", 0, 96, iso_8859_5},
- {"ISO-8859-6:1999 (Latin/Arabic)", 0, 96, iso_8859_6},
- {"ISO-8859-7:1987 (Latin/Greek)", 0, 96, iso_8859_7},
- {"ISO-8859-8:1999 (Latin/Hebrew)", 0, 96, iso_8859_8},
- {"ISO-8859-9:1999 (Latin-5, Turkish)", 0, 96, iso_8859_9},
- {"ISO-8859-10:1998 (Latin-6, Nordic)", 0, 96, iso_8859_10},
- {"ISO-8859-11:2001 (Latin/Thai)", 0, 96, iso_8859_11},
- {"ISO-8859-13:1998 (Latin-7, Baltic)", 0, 96, iso_8859_13},
- {"ISO-8859-14:1998 (Latin-8, Celtic)", 0, 96, iso_8859_14},
- {"ISO-8859-15:1999 (Latin-9, \"euro\")", 0, 96, iso_8859_15},
- {"ISO-8859-16:2001 (Latin-10, Balkan)", 0, 96, iso_8859_16},
-
- {"KOI8-U", 0, 128, koi8_u},
- {"KOI8-R", 20866},
- {"HP-ROMAN8", 0, 96, roman8},
- {"VSCII", 0, 256, vscii},
- {"DEC-MCS", 0, 96, dec_mcs},
-
- {"Win1250 (Central European)", 1250},
- {"Win1251 (Cyrillic)", 1251},
- {"Win1252 (Western)", 1252},
- {"Win1253 (Greek)", 1253},
- {"Win1254 (Turkish)", 1254},
- {"Win1255 (Hebrew)", 1255},
- {"Win1256 (Arabic)", 1256},
- {"Win1257 (Baltic)", 1257},
- {"Win1258 (Vietnamese)", 1258},
-
- {"CP437", 437},
- {"CP620 (Mazovia)", 0, 128, mazovia},
- {"CP819", 28591},
- {"CP852", 852},
- {"CP878", 20866},
-
- {"Use font encoding", -1},
-
- {0, 0}
-};
-
-static void link_font(WCHAR * line_tbl, WCHAR * font_tbl, WCHAR attr);
-
-void init_ucs(Conf *conf, struct unicode_data *ucsdata)
-{
- int i, j;
- bool used_dtf = false;
- int vtmode;
-
- /* Decide on the Line and Font codepages */
- ucsdata->line_codepage = decode_codepage(conf_get_str(conf,
- CONF_line_codepage));
-
- if (ucsdata->font_codepage <= 0) {
- ucsdata->font_codepage=0;
- ucsdata->dbcs_screenfont=false;
- }
-
- vtmode = conf_get_int(conf, CONF_vtmode);
- if (vtmode == VT_OEMONLY) {
- ucsdata->font_codepage = 437;
- ucsdata->dbcs_screenfont = false;
- if (ucsdata->line_codepage <= 0)
- ucsdata->line_codepage = GetACP();
- } else if (ucsdata->line_codepage <= 0)
- ucsdata->line_codepage = ucsdata->font_codepage;
-
- /* Collect screen font ucs table */
- if (ucsdata->dbcs_screenfont || ucsdata->font_codepage == 0) {
- get_unitab(ucsdata->font_codepage, ucsdata->unitab_font, 2);
- for (i = 128; i < 256; i++)
- ucsdata->unitab_font[i] = (WCHAR) (CSET_ACP + i);
- } else {
- get_unitab(ucsdata->font_codepage, ucsdata->unitab_font, 1);
-
- /* CP437 fonts are often broken ... */
- if (ucsdata->font_codepage == 437)
- ucsdata->unitab_font[0] = ucsdata->unitab_font[255] = 0xFFFF;
- }
- if (vtmode == VT_XWINDOWS)
- memcpy(ucsdata->unitab_font + 1, unitab_xterm_std,
- sizeof(unitab_xterm_std));
-
- /* Collect OEMCP ucs table */
- get_unitab(CP_OEMCP, ucsdata->unitab_oemcp, 1);
-
- /* Collect CP437 ucs table for SCO acs */
- if (vtmode == VT_OEMANSI || vtmode == VT_XWINDOWS)
- memcpy(ucsdata->unitab_scoacs, ucsdata->unitab_oemcp,
- sizeof(ucsdata->unitab_scoacs));
- else
- get_unitab(437, ucsdata->unitab_scoacs, 1);
-
- /* Collect line set ucs table */
- if (ucsdata->line_codepage == ucsdata->font_codepage &&
- (ucsdata->dbcs_screenfont ||
- vtmode == VT_POORMAN || ucsdata->font_codepage==0)) {
-
- /* For DBCS and POOR fonts force direct to font */
- used_dtf = true;
- for (i = 0; i < 32; i++)
- ucsdata->unitab_line[i] = (WCHAR) i;
- for (i = 32; i < 256; i++)
- ucsdata->unitab_line[i] = (WCHAR) (CSET_ACP + i);
- ucsdata->unitab_line[127] = (WCHAR) 127;
- } else {
- get_unitab(ucsdata->line_codepage, ucsdata->unitab_line, 0);
- }
-
-#if 0
- debug("Line cp%d, Font cp%d%s\n", ucsdata->line_codepage,
- ucsdata->font_codepage, ucsdata->dbcs_screenfont ? " DBCS" : "");
-
- for (i = 0; i < 256; i += 16) {
- for (j = 0; j < 16; j++) {
- debug("%04x%s", ucsdata->unitab_line[i + j], j == 15 ? "" : ",");
- }
- debug("\n");
- }
-#endif
-
- /* VT100 graphics - NB: Broken for non-ascii CP's */
- memcpy(ucsdata->unitab_xterm, ucsdata->unitab_line,
- sizeof(ucsdata->unitab_xterm));
- memcpy(ucsdata->unitab_xterm + '`', unitab_xterm_std,
- sizeof(unitab_xterm_std));
- ucsdata->unitab_xterm['_'] = ' ';
-
- /* Generate UCS ->line page table. */
- if (ucsdata->uni_tbl) {
- for (i = 0; i < 256; i++)
- if (ucsdata->uni_tbl[i])
- sfree(ucsdata->uni_tbl[i]);
- sfree(ucsdata->uni_tbl);
- ucsdata->uni_tbl = 0;
- }
- if (!used_dtf) {
- for (i = 0; i < 256; i++) {
- if (DIRECT_CHAR(ucsdata->unitab_line[i]))
- continue;
- if (DIRECT_FONT(ucsdata->unitab_line[i]))
- continue;
- if (!ucsdata->uni_tbl) {
- ucsdata->uni_tbl = snewn(256, char *);
- memset(ucsdata->uni_tbl, 0, 256 * sizeof(char *));
- }
- j = ((ucsdata->unitab_line[i] >> 8) & 0xFF);
- if (!ucsdata->uni_tbl[j]) {
- ucsdata->uni_tbl[j] = snewn(256, char);
- memset(ucsdata->uni_tbl[j], 0, 256 * sizeof(char));
- }
- ucsdata->uni_tbl[j][ucsdata->unitab_line[i] & 0xFF] = i;
- }
- }
-
- /* Find the line control characters. */
- for (i = 0; i < 256; i++)
- if (ucsdata->unitab_line[i] < ' '
- || (ucsdata->unitab_line[i] >= 0x7F &&
- ucsdata->unitab_line[i] < 0xA0))
- ucsdata->unitab_ctrl[i] = i;
- else
- ucsdata->unitab_ctrl[i] = 0xFF;
-
- /* Generate line->screen direct conversion links. */
- if (vtmode == VT_OEMANSI || vtmode == VT_XWINDOWS)
- link_font(ucsdata->unitab_scoacs, ucsdata->unitab_oemcp, CSET_OEMCP);
-
- link_font(ucsdata->unitab_line, ucsdata->unitab_font, CSET_ACP);
- link_font(ucsdata->unitab_scoacs, ucsdata->unitab_font, CSET_ACP);
- link_font(ucsdata->unitab_xterm, ucsdata->unitab_font, CSET_ACP);
-
- if (vtmode == VT_OEMANSI || vtmode == VT_XWINDOWS) {
- link_font(ucsdata->unitab_line, ucsdata->unitab_oemcp, CSET_OEMCP);
- link_font(ucsdata->unitab_xterm, ucsdata->unitab_oemcp, CSET_OEMCP);
- }
-
- if (ucsdata->dbcs_screenfont &&
- ucsdata->font_codepage != ucsdata->line_codepage) {
- /* F***ing Microsoft fonts, Japanese and Korean codepage fonts
- * have a currency symbol at 0x5C but their unicode value is
- * still given as U+005C not the correct U+00A5. */
- ucsdata->unitab_line['\\'] = CSET_OEMCP + '\\';
- }
-
- /* Last chance, if !unicode then try poorman links. */
- if (vtmode != VT_UNICODE) {
- static const char poorman_scoacs[] =
- "CueaaaaceeeiiiAAE**ooouuyOUc$YPsaiounNao?++**!<>###||||++||++++++--|-+||++--|-+----++++++++##||#aBTPEsyt******EN=+><++-=... n2* ";
- static const char poorman_latin1[] =
- " !cL.Y|S\"Ca<--R~o+23'u|.,1o>///?AAAAAAACEEEEIIIIDNOOOOOxOUUUUYPBaaaaaaaceeeeiiiionooooo/ouuuuypy";
- static const char poorman_vt100[] = "*#****o~**+++++-----++++|****L.";
-
- for (i = 160; i < 256; i++)
- if (!DIRECT_FONT(ucsdata->unitab_line[i]) &&
- ucsdata->unitab_line[i] >= 160 &&
- ucsdata->unitab_line[i] < 256) {
- ucsdata->unitab_line[i] =
- (WCHAR) (CSET_ACP +
- poorman_latin1[ucsdata->unitab_line[i] - 160]);
- }
- for (i = 96; i < 127; i++)
- if (!DIRECT_FONT(ucsdata->unitab_xterm[i]))
- ucsdata->unitab_xterm[i] =
- (WCHAR) (CSET_ACP + poorman_vt100[i - 96]);
- for(i=128;i<256;i++)
- if (!DIRECT_FONT(ucsdata->unitab_scoacs[i]))
- ucsdata->unitab_scoacs[i] =
- (WCHAR) (CSET_ACP + poorman_scoacs[i - 128]);
- }
-}
-
-static void link_font(WCHAR * line_tbl, WCHAR * font_tbl, WCHAR attr)
-{
- int font_index, line_index, i;
- for (line_index = 0; line_index < 256; line_index++) {
- if (DIRECT_FONT(line_tbl[line_index]))
- continue;
- for(i = 0; i < 256; i++) {
- font_index = ((32 + i) & 0xFF);
- if (line_tbl[line_index] == font_tbl[font_index]) {
- line_tbl[line_index] = (WCHAR) (attr + font_index);
- break;
- }
- }
- }
-}
-
-wchar_t xlat_uskbd2cyrllic(int ch)
-{
- static const wchar_t cyrtab[] = {
- 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 0x042d, 35, 36, 37, 38, 0x044d,
- 40, 41, 42, 0x0406, 0x0431, 0x0454, 0x044e, 0x002e,
- 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 0x0416, 0x0436, 0x0411, 0x0456, 0x042e, 0x002c,
- 64, 0x0424, 0x0418, 0x0421, 0x0412, 0x0423, 0x0410, 0x041f,
- 0x0420, 0x0428, 0x041e, 0x041b, 0x0414, 0x042c, 0x0422, 0x0429,
- 0x0417, 0x0419, 0x041a, 0x042b, 0x0415, 0x0413, 0x041c, 0x0426,
- 0x0427, 0x041d, 0x042f, 0x0445, 0x0457, 0x044a, 94, 0x0404,
- 96, 0x0444, 0x0438, 0x0441, 0x0432, 0x0443, 0x0430, 0x043f,
- 0x0440, 0x0448, 0x043e, 0x043b, 0x0434, 0x044c, 0x0442, 0x0449,
- 0x0437, 0x0439, 0x043a, 0x044b, 0x0435, 0x0433, 0x043c, 0x0446,
- 0x0447, 0x043d, 0x044f, 0x0425, 0x0407, 0x042a, 126, 127
- };
- return cyrtab[ch&0x7F];
-}
-
-int check_compose_internal(int first, int second, int recurse)
-{
-
- static const struct {
- char first, second;
- wchar_t composed;
- } composetbl[] = {
- {0x2b, 0x2b, 0x0023},
- {0x41, 0x41, 0x0040},
- {0x28, 0x28, 0x005b},
- {0x2f, 0x2f, 0x005c},
- {0x29, 0x29, 0x005d},
- {0x28, 0x2d, 0x007b},
- {0x2d, 0x29, 0x007d},
- {0x2f, 0x5e, 0x007c},
- {0x21, 0x21, 0x00a1},
- {0x43, 0x2f, 0x00a2},
- {0x43, 0x7c, 0x00a2},
- {0x4c, 0x2d, 0x00a3},
- {0x4c, 0x3d, 0x20a4},
- {0x58, 0x4f, 0x00a4},
- {0x58, 0x30, 0x00a4},
- {0x59, 0x2d, 0x00a5},
- {0x59, 0x3d, 0x00a5},
- {0x7c, 0x7c, 0x00a6},
- {0x53, 0x4f, 0x00a7},
- {0x53, 0x21, 0x00a7},
- {0x53, 0x30, 0x00a7},
- {0x22, 0x22, 0x00a8},
- {0x43, 0x4f, 0x00a9},
- {0x43, 0x30, 0x00a9},
- {0x41, 0x5f, 0x00aa},
- {0x3c, 0x3c, 0x00ab},
- {0x2c, 0x2d, 0x00ac},
- {0x2d, 0x2d, 0x00ad},
- {0x52, 0x4f, 0x00ae},
- {0x2d, 0x5e, 0x00af},
- {0x30, 0x5e, 0x00b0},
- {0x2b, 0x2d, 0x00b1},
- {0x32, 0x5e, 0x00b2},
- {0x33, 0x5e, 0x00b3},
- {0x27, 0x27, 0x00b4},
- {0x2f, 0x55, 0x00b5},
- {0x50, 0x21, 0x00b6},
- {0x2e, 0x5e, 0x00b7},
- {0x2c, 0x2c, 0x00b8},
- {0x31, 0x5e, 0x00b9},
- {0x4f, 0x5f, 0x00ba},
- {0x3e, 0x3e, 0x00bb},
- {0x31, 0x34, 0x00bc},
- {0x31, 0x32, 0x00bd},
- {0x33, 0x34, 0x00be},
- {0x3f, 0x3f, 0x00bf},
- {0x60, 0x41, 0x00c0},
- {0x27, 0x41, 0x00c1},
- {0x5e, 0x41, 0x00c2},
- {0x7e, 0x41, 0x00c3},
- {0x22, 0x41, 0x00c4},
- {0x2a, 0x41, 0x00c5},
- {0x41, 0x45, 0x00c6},
- {0x2c, 0x43, 0x00c7},
- {0x60, 0x45, 0x00c8},
- {0x27, 0x45, 0x00c9},
- {0x5e, 0x45, 0x00ca},
- {0x22, 0x45, 0x00cb},
- {0x60, 0x49, 0x00cc},
- {0x27, 0x49, 0x00cd},
- {0x5e, 0x49, 0x00ce},
- {0x22, 0x49, 0x00cf},
- {0x2d, 0x44, 0x00d0},
- {0x7e, 0x4e, 0x00d1},
- {0x60, 0x4f, 0x00d2},
- {0x27, 0x4f, 0x00d3},
- {0x5e, 0x4f, 0x00d4},
- {0x7e, 0x4f, 0x00d5},
- {0x22, 0x4f, 0x00d6},
- {0x58, 0x58, 0x00d7},
- {0x2f, 0x4f, 0x00d8},
- {0x60, 0x55, 0x00d9},
- {0x27, 0x55, 0x00da},
- {0x5e, 0x55, 0x00db},
- {0x22, 0x55, 0x00dc},
- {0x27, 0x59, 0x00dd},
- {0x48, 0x54, 0x00de},
- {0x73, 0x73, 0x00df},
- {0x60, 0x61, 0x00e0},
- {0x27, 0x61, 0x00e1},
- {0x5e, 0x61, 0x00e2},
- {0x7e, 0x61, 0x00e3},
- {0x22, 0x61, 0x00e4},
- {0x2a, 0x61, 0x00e5},
- {0x61, 0x65, 0x00e6},
- {0x2c, 0x63, 0x00e7},
- {0x60, 0x65, 0x00e8},
- {0x27, 0x65, 0x00e9},
- {0x5e, 0x65, 0x00ea},
- {0x22, 0x65, 0x00eb},
- {0x60, 0x69, 0x00ec},
- {0x27, 0x69, 0x00ed},
- {0x5e, 0x69, 0x00ee},
- {0x22, 0x69, 0x00ef},
- {0x2d, 0x64, 0x00f0},
- {0x7e, 0x6e, 0x00f1},
- {0x60, 0x6f, 0x00f2},
- {0x27, 0x6f, 0x00f3},
- {0x5e, 0x6f, 0x00f4},
- {0x7e, 0x6f, 0x00f5},
- {0x22, 0x6f, 0x00f6},
- {0x3a, 0x2d, 0x00f7},
- {0x6f, 0x2f, 0x00f8},
- {0x60, 0x75, 0x00f9},
- {0x27, 0x75, 0x00fa},
- {0x5e, 0x75, 0x00fb},
- {0x22, 0x75, 0x00fc},
- {0x27, 0x79, 0x00fd},
- {0x68, 0x74, 0x00fe},
- {0x22, 0x79, 0x00ff},
- /* Unicode extras. */
- {0x6f, 0x65, 0x0153},
- {0x4f, 0x45, 0x0152},
- /* Compose pairs from UCS */
- {0x41, 0x2D, 0x0100},
- {0x61, 0x2D, 0x0101},
- {0x43, 0x27, 0x0106},
- {0x63, 0x27, 0x0107},
- {0x43, 0x5E, 0x0108},
- {0x63, 0x5E, 0x0109},
- {0x45, 0x2D, 0x0112},
- {0x65, 0x2D, 0x0113},
- {0x47, 0x5E, 0x011C},
- {0x67, 0x5E, 0x011D},
- {0x47, 0x2C, 0x0122},
- {0x67, 0x2C, 0x0123},
- {0x48, 0x5E, 0x0124},
- {0x68, 0x5E, 0x0125},
- {0x49, 0x7E, 0x0128},
- {0x69, 0x7E, 0x0129},
- {0x49, 0x2D, 0x012A},
- {0x69, 0x2D, 0x012B},
- {0x4A, 0x5E, 0x0134},
- {0x6A, 0x5E, 0x0135},
- {0x4B, 0x2C, 0x0136},
- {0x6B, 0x2C, 0x0137},
- {0x4C, 0x27, 0x0139},
- {0x6C, 0x27, 0x013A},
- {0x4C, 0x2C, 0x013B},
- {0x6C, 0x2C, 0x013C},
- {0x4E, 0x27, 0x0143},
- {0x6E, 0x27, 0x0144},
- {0x4E, 0x2C, 0x0145},
- {0x6E, 0x2C, 0x0146},
- {0x4F, 0x2D, 0x014C},
- {0x6F, 0x2D, 0x014D},
- {0x52, 0x27, 0x0154},
- {0x72, 0x27, 0x0155},
- {0x52, 0x2C, 0x0156},
- {0x72, 0x2C, 0x0157},
- {0x53, 0x27, 0x015A},
- {0x73, 0x27, 0x015B},
- {0x53, 0x5E, 0x015C},
- {0x73, 0x5E, 0x015D},
- {0x53, 0x2C, 0x015E},
- {0x73, 0x2C, 0x015F},
- {0x54, 0x2C, 0x0162},
- {0x74, 0x2C, 0x0163},
- {0x55, 0x7E, 0x0168},
- {0x75, 0x7E, 0x0169},
- {0x55, 0x2D, 0x016A},
- {0x75, 0x2D, 0x016B},
- {0x55, 0x2A, 0x016E},
- {0x75, 0x2A, 0x016F},
- {0x57, 0x5E, 0x0174},
- {0x77, 0x5E, 0x0175},
- {0x59, 0x5E, 0x0176},
- {0x79, 0x5E, 0x0177},
- {0x59, 0x22, 0x0178},
- {0x5A, 0x27, 0x0179},
- {0x7A, 0x27, 0x017A},
- {0x47, 0x27, 0x01F4},
- {0x67, 0x27, 0x01F5},
- {0x4E, 0x60, 0x01F8},
- {0x6E, 0x60, 0x01F9},
- {0x45, 0x2C, 0x0228},
- {0x65, 0x2C, 0x0229},
- {0x59, 0x2D, 0x0232},
- {0x79, 0x2D, 0x0233},
- {0x44, 0x2C, 0x1E10},
- {0x64, 0x2C, 0x1E11},
- {0x47, 0x2D, 0x1E20},
- {0x67, 0x2D, 0x1E21},
- {0x48, 0x22, 0x1E26},
- {0x68, 0x22, 0x1E27},
- {0x48, 0x2C, 0x1E28},
- {0x68, 0x2C, 0x1E29},
- {0x4B, 0x27, 0x1E30},
- {0x6B, 0x27, 0x1E31},
- {0x4D, 0x27, 0x1E3E},
- {0x6D, 0x27, 0x1E3F},
- {0x50, 0x27, 0x1E54},
- {0x70, 0x27, 0x1E55},
- {0x56, 0x7E, 0x1E7C},
- {0x76, 0x7E, 0x1E7D},
- {0x57, 0x60, 0x1E80},
- {0x77, 0x60, 0x1E81},
- {0x57, 0x27, 0x1E82},
- {0x77, 0x27, 0x1E83},
- {0x57, 0x22, 0x1E84},
- {0x77, 0x22, 0x1E85},
- {0x58, 0x22, 0x1E8C},
- {0x78, 0x22, 0x1E8D},
- {0x5A, 0x5E, 0x1E90},
- {0x7A, 0x5E, 0x1E91},
- {0x74, 0x22, 0x1E97},
- {0x77, 0x2A, 0x1E98},
- {0x79, 0x2A, 0x1E99},
- {0x45, 0x7E, 0x1EBC},
- {0x65, 0x7E, 0x1EBD},
- {0x59, 0x60, 0x1EF2},
- {0x79, 0x60, 0x1EF3},
- {0x59, 0x7E, 0x1EF8},
- {0x79, 0x7E, 0x1EF9},
- /* Compatible/possibles from UCS */
- {0x49, 0x4A, 0x0132},
- {0x69, 0x6A, 0x0133},
- {0x4C, 0x4A, 0x01C7},
- {0x4C, 0x6A, 0x01C8},
- {0x6C, 0x6A, 0x01C9},
- {0x4E, 0x4A, 0x01CA},
- {0x4E, 0x6A, 0x01CB},
- {0x6E, 0x6A, 0x01CC},
- {0x44, 0x5A, 0x01F1},
- {0x44, 0x7A, 0x01F2},
- {0x64, 0x7A, 0x01F3},
- {0x2E, 0x2E, 0x2025},
- {0x21, 0x21, 0x203C},
- {0x3F, 0x21, 0x2048},
- {0x21, 0x3F, 0x2049},
- {0x52, 0x73, 0x20A8},
- {0x4E, 0x6F, 0x2116},
- {0x53, 0x4D, 0x2120},
- {0x54, 0x4D, 0x2122},
- {0x49, 0x49, 0x2161},
- {0x49, 0x56, 0x2163},
- {0x56, 0x49, 0x2165},
- {0x49, 0x58, 0x2168},
- {0x58, 0x49, 0x216A},
- {0x69, 0x69, 0x2171},
- {0x69, 0x76, 0x2173},
- {0x76, 0x69, 0x2175},
- {0x69, 0x78, 0x2178},
- {0x78, 0x69, 0x217A},
- {0x31, 0x30, 0x2469},
- {0x31, 0x31, 0x246A},
- {0x31, 0x32, 0x246B},
- {0x31, 0x33, 0x246C},
- {0x31, 0x34, 0x246D},
- {0x31, 0x35, 0x246E},
- {0x31, 0x36, 0x246F},
- {0x31, 0x37, 0x2470},
- {0x31, 0x38, 0x2471},
- {0x31, 0x39, 0x2472},
- {0x32, 0x30, 0x2473},
- {0x31, 0x2E, 0x2488},
- {0x32, 0x2E, 0x2489},
- {0x33, 0x2E, 0x248A},
- {0x34, 0x2E, 0x248B},
- {0x35, 0x2E, 0x248C},
- {0x36, 0x2E, 0x248D},
- {0x37, 0x2E, 0x248E},
- {0x38, 0x2E, 0x248F},
- {0x39, 0x2E, 0x2490},
- {0x64, 0x61, 0x3372},
- {0x41, 0x55, 0x3373},
- {0x6F, 0x56, 0x3375},
- {0x70, 0x63, 0x3376},
- {0x70, 0x41, 0x3380},
- {0x6E, 0x41, 0x3381},
- {0x6D, 0x41, 0x3383},
- {0x6B, 0x41, 0x3384},
- {0x4B, 0x42, 0x3385},
- {0x4D, 0x42, 0x3386},
- {0x47, 0x42, 0x3387},
- {0x70, 0x46, 0x338A},
- {0x6E, 0x46, 0x338B},
- {0x6D, 0x67, 0x338E},
- {0x6B, 0x67, 0x338F},
- {0x48, 0x7A, 0x3390},
- {0x66, 0x6D, 0x3399},
- {0x6E, 0x6D, 0x339A},
- {0x6D, 0x6D, 0x339C},
- {0x63, 0x6D, 0x339D},
- {0x6B, 0x6D, 0x339E},
- {0x50, 0x61, 0x33A9},
- {0x70, 0x73, 0x33B0},
- {0x6E, 0x73, 0x33B1},
- {0x6D, 0x73, 0x33B3},
- {0x70, 0x56, 0x33B4},
- {0x6E, 0x56, 0x33B5},
- {0x6D, 0x56, 0x33B7},
- {0x6B, 0x56, 0x33B8},
- {0x4D, 0x56, 0x33B9},
- {0x70, 0x57, 0x33BA},
- {0x6E, 0x57, 0x33BB},
- {0x6D, 0x57, 0x33BD},
- {0x6B, 0x57, 0x33BE},
- {0x4D, 0x57, 0x33BF},
- {0x42, 0x71, 0x33C3},
- {0x63, 0x63, 0x33C4},
- {0x63, 0x64, 0x33C5},
- {0x64, 0x42, 0x33C8},
- {0x47, 0x79, 0x33C9},
- {0x68, 0x61, 0x33CA},
- {0x48, 0x50, 0x33CB},
- {0x69, 0x6E, 0x33CC},
- {0x4B, 0x4B, 0x33CD},
- {0x4B, 0x4D, 0x33CE},
- {0x6B, 0x74, 0x33CF},
- {0x6C, 0x6D, 0x33D0},
- {0x6C, 0x6E, 0x33D1},
- {0x6C, 0x78, 0x33D3},
- {0x6D, 0x62, 0x33D4},
- {0x50, 0x48, 0x33D7},
- {0x50, 0x52, 0x33DA},
- {0x73, 0x72, 0x33DB},
- {0x53, 0x76, 0x33DC},
- {0x57, 0x62, 0x33DD},
- {0x66, 0x66, 0xFB00},
- {0x66, 0x69, 0xFB01},
- {0x66, 0x6C, 0xFB02},
- {0x73, 0x74, 0xFB06},
- {0, 0, 0}
- }, *c;
-
- int nc = -1;
-
- for (c = composetbl; c->first; c++) {
- if (c->first == first && c->second == second)
- return c->composed;
- }
-
- if (recurse == 0) {
- nc = check_compose_internal(second, first, 1);
- if (nc == -1)
- nc = check_compose_internal(toupper(first), toupper(second), 1);
- if (nc == -1)
- nc = check_compose_internal(toupper(second), toupper(first), 1);
- }
- return nc;
-}
-
-int check_compose(int first, int second)
-{
- return check_compose_internal(first, second, 0);
-}
-
-int decode_codepage(char *cp_name)
-{
- char *s, *d;
- const struct cp_list_item *cpi;
- int codepage = -1;
- CPINFO cpinfo;
-
- if (!cp_name || !*cp_name)
- return CP_UTF8; /* default */
-
- for (cpi = cp_list; cpi->name; cpi++) {
- s = cp_name;
- d = cpi->name;
- for (;;) {
- while (*s && !isalnum(*s) && *s != ':')
- s++;
- while (*d && !isalnum(*d) && *d != ':')
- d++;
- if (*s == 0) {
- codepage = cpi->codepage;
- if (codepage == CP_UTF8)
- goto break_break;
- if (codepage == -1)
- return codepage;
- if (codepage == 0) {
- codepage = 65536 + (cpi - cp_list);
- goto break_break;
- }
-
- if (GetCPInfo(codepage, &cpinfo) != 0)
- goto break_break;
- }
- if (tolower((unsigned char)*s++) != tolower((unsigned char)*d++))
- break;
- }
- }
-
- d = cp_name;
- if (tolower((unsigned char)d[0]) == 'c' &&
- tolower((unsigned char)d[1]) == 'p')
- d += 2;
- if (tolower((unsigned char)d[0]) == 'i' &&
- tolower((unsigned char)d[1]) == 'b' &&
- tolower((unsigned char)d[2]) == 'm')
- d += 3;
- for (s = d; *s >= '0' && *s <= '9'; s++);
- if (*s == 0 && s != d)
- codepage = atoi(d); /* CP999 or IBM999 */
-
- if (codepage == CP_ACP)
- codepage = GetACP();
- if (codepage == CP_OEMCP)
- codepage = GetOEMCP();
- if (codepage > 65535)
- codepage = -2;
-
- break_break:;
- if (codepage != -1) {
- if (codepage != CP_UTF8 && codepage < 65536) {
- if (GetCPInfo(codepage, &cpinfo) == 0) {
- codepage = -2;
- } else if (cpinfo.MaxCharSize > 1)
- codepage = -3;
- }
- }
- if (codepage == -1 && *cp_name)
- codepage = -2;
- return codepage;
-}
-
-const char *cp_name(int codepage)
-{
- const struct cp_list_item *cpi, *cpno;
- static char buf[32];
-
- if (codepage == -1) {
- sprintf(buf, "Use font encoding");
- return buf;
- }
-
- if (codepage > 0 && codepage < 65536)
- sprintf(buf, "CP%03d", codepage);
- else
- *buf = 0;
-
- if (codepage >= 65536) {
- cpno = 0;
- for (cpi = cp_list; cpi->name; cpi++)
- if (cpi == cp_list + (codepage - 65536)) {
- cpno = cpi;
- break;
- }
- if (cpno)
- for (cpi = cp_list; cpi->name; cpi++) {
- if (cpno->cp_table == cpi->cp_table)
- return cpi->name;
- }
- } else {
- for (cpi = cp_list; cpi->name; cpi++) {
- if (codepage == cpi->codepage)
- return cpi->name;
- }
- }
- return buf;
-}
-
-/*
- * Return the nth code page in the list, for use in the GUI
- * configurer.
- */
-const char *cp_enumerate(int index)
-{
- if (index < 0 || index >= lenof(cp_list))
- return NULL;
- return cp_list[index].name;
-}
-
-void get_unitab(int codepage, wchar_t * unitab, int ftype)
-{
- char tbuf[4];
- int i, max = 256, flg = MB_ERR_INVALID_CHARS;
-
- if (ftype)
- flg |= MB_USEGLYPHCHARS;
- if (ftype == 2)
- max = 128;
-
- if (codepage == CP_UTF8) {
- for (i = 0; i < max; i++)
- unitab[i] = i;
- return;
- }
-
- if (codepage == CP_ACP)
- codepage = GetACP();
- else if (codepage == CP_OEMCP)
- codepage = GetOEMCP();
-
- if (codepage > 0 && codepage < 65536) {
- for (i = 0; i < max; i++) {
- tbuf[0] = i;
-
- if (mb_to_wc(codepage, flg, tbuf, 1, unitab + i, 1)
- != 1)
- unitab[i] = 0xFFFD;
- }
- } else {
- int j = 256 - cp_list[codepage & 0xFFFF].cp_size;
- for (i = 0; i < max; i++)
- unitab[i] = i;
- for (i = j; i < max; i++)
- unitab[i] = cp_list[codepage & 0xFFFF].cp_table[i - j];
- }
-}
-
-int wc_to_mb(int codepage, int flags, const wchar_t *wcstr, int wclen,
- char *mbstr, int mblen, const char *defchr,
- struct unicode_data *ucsdata)
-{
- char *p;
- int i;
- if (ucsdata && codepage == ucsdata->line_codepage && ucsdata->uni_tbl) {
- /* Do this by array lookup if we can. */
- if (wclen < 0) {
- for (wclen = 0; wcstr[wclen++] ;); /* will include the NUL */
- }
- for (p = mbstr, i = 0; i < wclen; i++) {
- wchar_t ch = wcstr[i];
- int by;
- char *p1;
-
- #define WRITECH(chr) do \
- { \
- assert(p - mbstr < mblen); \
- *p++ = (char)(chr); \
- } while (0)
-
- if (ucsdata->uni_tbl &&
- (p1 = ucsdata->uni_tbl[(ch >> 8) & 0xFF]) != NULL &&
- (by = p1[ch & 0xFF]) != '\0')
- WRITECH(by);
- else if (ch < 0x80)
- WRITECH(ch);
- else if (defchr)
- for (const char *q = defchr; *q; q++)
- WRITECH(*q);
-#if 1
- else
- WRITECH('.');
-#endif
-
- #undef WRITECH
- }
- return p - mbstr;
- } else {
- int defused;
- return WideCharToMultiByte(codepage, flags, wcstr, wclen,
- mbstr, mblen, defchr, &defused);
- }
-}
-
-int mb_to_wc(int codepage, int flags, const char *mbstr, int mblen,
- wchar_t *wcstr, int wclen)
-{
- return MultiByteToWideChar(codepage, flags, mbstr, mblen, wcstr, wclen);
-}
-
-bool is_dbcs_leadbyte(int codepage, char byte)
-{
- return IsDBCSLeadByteEx(codepage, byte);
-}
diff --git a/WINDOWS/WINUTILS.C b/WINDOWS/WINUTILS.C
deleted file mode 100644
index dec8984b..00000000
--- a/WINDOWS/WINUTILS.C
+++ /dev/null
@@ -1,788 +0,0 @@
-/*
- * winutils.c: miscellaneous Windows utilities for GUI apps
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-#include "putty.h"
-#include "misc.h"
-
-#ifdef TESTMODE
-/* Definitions to allow this module to be compiled standalone for testing
- * split_into_argv(). */
-#define smalloc malloc
-#define srealloc realloc
-#define sfree free
-#endif
-
-/*
- * GetOpenFileName/GetSaveFileName tend to muck around with the process'
- * working directory on at least some versions of Windows.
- * Here's a wrapper that gives more control over this, and hides a little
- * bit of other grottiness.
- */
-
-struct filereq_tag {
- TCHAR cwd[MAX_PATH];
-};
-
-/*
- * `of' is expected to be initialised with most interesting fields, but
- * this function does some administrivia. (assume `of' was memset to 0)
- * save==1 -> GetSaveFileName; save==0 -> GetOpenFileName
- * `state' is optional.
- */
-bool request_file(filereq *state, OPENFILENAME *of, bool preserve, bool save)
-{
- TCHAR cwd[MAX_PATH]; /* process CWD */
- bool ret;
-
- /* Get process CWD */
- if (preserve) {
- DWORD r = GetCurrentDirectory(lenof(cwd), cwd);
- if (r == 0 || r >= lenof(cwd))
- /* Didn't work, oh well. Stop trying to be clever. */
- preserve = false;
- }
-
- /* Open the file requester, maybe setting lpstrInitialDir */
- {
-#ifdef OPENFILENAME_SIZE_VERSION_400
- of->lStructSize = OPENFILENAME_SIZE_VERSION_400;
-#else
- of->lStructSize = sizeof(*of);
-#endif
- of->lpstrInitialDir = (state && state->cwd[0]) ? state->cwd : NULL;
- /* Actually put up the requester. */
- ret = save ? GetSaveFileName(of) : GetOpenFileName(of);
- }
-
- /* Get CWD left by requester */
- if (state) {
- DWORD r = GetCurrentDirectory(lenof(state->cwd), state->cwd);
- if (r == 0 || r >= lenof(state->cwd))
- /* Didn't work, oh well. */
- state->cwd[0] = '\0';
- }
-
- /* Restore process CWD */
- if (preserve)
- /* If it fails, there's not much we can do. */
- (void) SetCurrentDirectory(cwd);
-
- return ret;
-}
-
-filereq *filereq_new(void)
-{
- filereq *ret = snew(filereq);
- ret->cwd[0] = '\0';
- return ret;
-}
-
-void filereq_free(filereq *state)
-{
- sfree(state);
-}
-
-/*
- * Message box with optional context help.
- */
-
-static HWND message_box_owner;
-
-/* Callback function to launch context help. */
-static VOID CALLBACK message_box_help_callback(LPHELPINFO lpHelpInfo)
-{
- const char *context = NULL;
-#define CHECK_CTX(name) \
- do { \
- if (lpHelpInfo->dwContextId == WINHELP_CTXID_ ## name) \
- context = WINHELP_CTX_ ## name; \
- } while (0)
- CHECK_CTX(errors_hostkey_absent);
- CHECK_CTX(errors_hostkey_changed);
- CHECK_CTX(errors_cantloadkey);
- CHECK_CTX(option_cleanup);
- CHECK_CTX(pgp_fingerprints);
-#undef CHECK_CTX
- if (context)
- launch_help(message_box_owner, context);
-}
-
-int message_box(HWND owner, LPCTSTR text, LPCTSTR caption,
- DWORD style, DWORD helpctxid)
-{
- MSGBOXPARAMS mbox;
-
- /*
- * We use MessageBoxIndirect() because it allows us to specify a
- * callback function for the Help button.
- */
- mbox.cbSize = sizeof(mbox);
- /* Assumes the globals `hinst' and `hwnd' have sensible values. */
- mbox.hInstance = hinst;
- mbox.hwndOwner = message_box_owner = owner;
- mbox.lpfnMsgBoxCallback = &message_box_help_callback;
- mbox.dwLanguageId = LANG_NEUTRAL;
- mbox.lpszText = text;
- mbox.lpszCaption = caption;
- mbox.dwContextHelpId = helpctxid;
- mbox.dwStyle = style;
- if (helpctxid != 0 && has_help()) mbox.dwStyle |= MB_HELP;
- return MessageBoxIndirect(&mbox);
-}
-
-/*
- * Display the fingerprints of the PGP Master Keys to the user.
- */
-void pgp_fingerprints_msgbox(HWND owner)
-{
- message_box(
- owner,
- "These are the fingerprints of the PuTTY PGP Master Keys. They can\n"
- "be used to establish a trust path from this executable to another\n"
- "one. See the manual for more information.\n"
- "(Note: these fingerprints have nothing to do with SSH!)\n"
- "\n"
- "PuTTY Master Key as of " PGP_MASTER_KEY_YEAR
- " (" PGP_MASTER_KEY_DETAILS "):\n"
- " " PGP_MASTER_KEY_FP "\n\n"
- "Previous Master Key (" PGP_PREV_MASTER_KEY_YEAR
- ", " PGP_PREV_MASTER_KEY_DETAILS "):\n"
- " " PGP_PREV_MASTER_KEY_FP,
- "PGP fingerprints", MB_ICONINFORMATION | MB_OK,
- HELPCTXID(pgp_fingerprints));
-}
-
-/*
- * Helper function to remove the border around a dialog item such as
- * a read-only edit control.
- */
-void MakeDlgItemBorderless(HWND parent, int id)
-{
- HWND child = GetDlgItem(parent, id);
- LONG_PTR style = GetWindowLongPtr(child, GWL_STYLE);
- LONG_PTR exstyle = GetWindowLongPtr(child, GWL_EXSTYLE);
- style &= ~WS_BORDER;
- exstyle &= ~(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE | WS_EX_WINDOWEDGE);
- SetWindowLongPtr(child, GWL_STYLE, style);
- SetWindowLongPtr(child, GWL_EXSTYLE, exstyle);
- SetWindowPos(child, NULL, 0, 0, 0, 0,
- SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
-}
-
-/*
- * Handy wrapper around GetDlgItemText which doesn't make you invent
- * an arbitrary length limit on the output string. Returned string is
- * dynamically allocated; caller must free.
- */
-char *GetDlgItemText_alloc(HWND hwnd, int id)
-{
- char *ret = NULL;
- size_t size = 0;
-
- do {
- sgrowarray_nm(ret, size, size);
- GetDlgItemText(hwnd, id, ret, size);
- } while (!memchr(ret, '\0', size-1));
-
- return ret;
-}
-
-/*
- * Split a complete command line into argc/argv, attempting to do it
- * exactly the same way the Visual Studio C library would do it (so
- * that our console utilities, which receive argc and argv already
- * broken apart by the C library, will have their command lines
- * processed in the same way as the GUI utilities which get a whole
- * command line and must call this function).
- *
- * Does not modify the input command line.
- *
- * The final parameter (argstart) is used to return a second array
- * of char * pointers, the same length as argv, each one pointing
- * at the start of the corresponding element of argv in the
- * original command line. So if you get half way through processing
- * your command line in argc/argv form and then decide you want to
- * treat the rest as a raw string, you can. If you don't want to,
- * `argstart' can be safely left NULL.
- */
-
-/*
- * The precise argument-breaking rules vary with compiler version, or
- * rather, with the crt0-type startup code that comes with each
- * compiler's C library. We do our best to match the compiler version,
- * so that we faithfully imitate in our GUI utilities what the
- * corresponding set of CLI utilities can't be prevented from doing.
- *
- * The basic rules are:
- *
- * - Single quotes are not special characters.
- *
- * - Double quotes are removed, but within them spaces cease to be
- * special.
- *
- * - Backslashes are _only_ special when a sequence of them appear
- * just before a double quote. In this situation, they are treated
- * like C backslashes: so \" just gives a literal quote, \\" gives
- * a literal backslash and then opens or closes a double-quoted
- * segment, \\\" gives a literal backslash and then a literal
- * quote, \\\\" gives two literal backslashes and then opens/closes
- * a double-quoted segment, and so forth. Note that this behaviour
- * is identical inside and outside double quotes.
- *
- * - Two successive double quotes become one literal double quote,
- * but only _inside_ a double-quoted segment. Outside, they just
- * form an empty double-quoted segment (which may cause an empty
- * argument word).
- *
- * That only leaves the interesting question of what happens when one
- * or more backslashes precedes two or more double quotes, starting
- * inside a double-quoted string.
- *
- * I investigated this in an ordinary CLI program, using the
- * toolchain's crt0 to split a command line of the form
- *
- * "a\\\"""b c" d
- *
- * Here I tabulate number of backslashes (across the top) against
- * number of quotes (down the left), and indicate how many backslashes
- * are output, how many quotes are output, and whether a quoted
- * segment is open at the end of the sequence:
- *
- * backslashes
- *
- * 0 1 2 3 4
- *
- * 0 0,0,y | 1,0,y 2,0,y 3,0,y 4,0,y
- * --------+-----------------------------
- * 1 0,0,n | 0,1,y 1,0,n 1,1,y 2,0,n
- * q 2 0,1,y | 0,1,n 1,1,y 1,1,n 2,1,y
- * u 3 0,1,n | 0,2,y 1,1,n 1,2,y 2,1,n
- * o 4 0,2,y | 0,2,n 1,2,y 1,2,n 2,2,y
- * t 5 0,2,n | 0,3,y 1,2,n 1,3,y 2,2,n
- * e 6 0,3,y | 0,3,n 1,3,y 1,3,n 2,3,y
- * s 7 0,3,n | 0,4,y 1,3,n 1,4,y 2,3,n
- * 8 0,4,y | 0,4,n 1,4,y 1,4,n 2,4,y
- *
- * The row at the top of this table, with quotes=0, demonstrates what
- * I claimed above, that when a sequence of backslashes are not
- * followed by a double quote, they don't act specially at all. The
- * rest of the table shows that the backslashes escape each other in
- * pairs (so that with 2n or 2n+1 input backslashes you get n output
- * ones); if there's an odd number of input backslashes then the last
- * one escapes the first double quote (so you get a literal quote and
- * enter a quoted string); thereafter, each input quote character
- * either opens or closes a quoted string, and if it closes one, it
- * generates a literal " as a side effect.
- *
- * But here's the corresponding table from the older Visual Studio 7:
- *
- * backslashes
- *
- * 0 1 2 3 4
- *
- * 0 0,0,y | 1,0,y 2,0,y 3,0,y 4,0,y
- * --------+-----------------------------
- * 1 0,0,n | 0,1,y 1,0,n 1,1,y 2,0,n
- * q 2 0,1,n | 0,1,n 1,1,n 1,1,n 2,1,n
- * u 3 0,1,y | 0,2,n 1,1,y 1,2,n 2,1,y
- * o 4 0,1,n | 0,2,y 1,1,n 1,2,y 2,1,n
- * t 5 0,2,n | 0,2,n 1,2,n 1,2,n 2,2,n
- * e 6 0,2,y | 0,3,n 1,2,y 1,3,n 2,2,y
- * s 7 0,2,n | 0,3,y 1,2,n 1,3,y 2,2,n
- * 8 0,3,n | 0,3,n 1,3,n 1,3,n 2,3,n
- * 9 0,3,y | 0,4,n 1,3,y 1,4,n 2,3,y
- * 10 0,3,n | 0,4,y 1,3,n 1,4,y 2,3,n
- * 11 0,4,n | 0,4,n 1,4,n 1,4,n 2,4,n
- *
- * There is very weird mod-3 behaviour going on here in the
- * number of quotes, and it even applies when there aren't any
- * backslashes! How ghastly.
- *
- * With a bit of thought, this extremely odd diagram suddenly
- * coalesced itself into a coherent, if still ghastly, model of
- * how things work:
- *
- * - As before, backslashes are only special when one or more
- * of them appear contiguously before at least one double
- * quote. In this situation the backslashes do exactly what
- * you'd expect: each one quotes the next thing in front of
- * it, so you end up with n/2 literal backslashes (if n is
- * even) or (n-1)/2 literal backslashes and a literal quote
- * (if n is odd). In the latter case the double quote
- * character right after the backslashes is used up.
- *
- * - After that, any remaining double quotes are processed. A
- * string of contiguous unescaped double quotes has a mod-3
- * behaviour:
- *
- * * inside a quoted segment, a quote ends the segment.
- * * _immediately_ after ending a quoted segment, a quote
- * simply produces a literal quote.
- * * otherwise, outside a quoted segment, a quote begins a
- * quoted segment.
- *
- * So, for example, if we started inside a quoted segment
- * then two contiguous quotes would close the segment and
- * produce a literal quote; three would close the segment,
- * produce a literal quote, and open a new segment. If we
- * started outside a quoted segment, then two contiguous
- * quotes would open and then close a segment, producing no
- * output (but potentially creating a zero-length argument);
- * but three quotes would open and close a segment and then
- * produce a literal quote.
- */
-
-/*
- * We select between two behaviours depending on the version of Visual
- * Studio (see large comment below). I don't know exactly when the bug
- * fix happened, but I know that VS7 had the odd mod-3 behaviour.
- */
-#if _MSC_VER < 1400
-#define MOD3 1
-#else
-#define MOD3 0
-#endif
-
-void split_into_argv(char *cmdline, int *argc, char ***argv,
- char ***argstart)
-{
- char *p;
- char *outputline, *q;
- char **outputargv, **outputargstart;
- int outputargc;
-
- /*
- * First deal with the simplest of all special cases: if there
- * aren't any arguments, return 0,NULL,NULL.
- */
- while (*cmdline && isspace(*cmdline)) cmdline++;
- if (!*cmdline) {
- if (argc) *argc = 0;
- if (argv) *argv = NULL;
- if (argstart) *argstart = NULL;
- return;
- }
-
- /*
- * This will guaranteeably be big enough; we can realloc it
- * down later.
- */
- outputline = snewn(1+strlen(cmdline), char);
- outputargv = snewn(strlen(cmdline)+1 / 2, char *);
- outputargstart = snewn(strlen(cmdline)+1 / 2, char *);
-
- p = cmdline; q = outputline; outputargc = 0;
-
- while (*p) {
- bool quote;
-
- /* Skip whitespace searching for start of argument. */
- while (*p && isspace(*p)) p++;
- if (!*p) break;
-
- /* We have an argument; start it. */
- outputargv[outputargc] = q;
- outputargstart[outputargc] = p;
- outputargc++;
- quote = false;
-
- /* Copy data into the argument until it's finished. */
- while (*p) {
- if (!quote && isspace(*p))
- break; /* argument is finished */
-
- if (*p == '"' || *p == '\\') {
- /*
- * We have a sequence of zero or more backslashes
- * followed by a sequence of zero or more quotes.
- * Count up how many of each, and then deal with
- * them as appropriate.
- */
- int i, slashes = 0, quotes = 0;
- while (*p == '\\') slashes++, p++;
- while (*p == '"') quotes++, p++;
-
- if (!quotes) {
- /*
- * Special case: if there are no quotes,
- * slashes are not special at all, so just copy
- * n slashes to the output string.
- */
- while (slashes--) *q++ = '\\';
- } else {
- /* Slashes annihilate in pairs. */
- while (slashes >= 2) slashes -= 2, *q++ = '\\';
-
- /* One remaining slash takes out the first quote. */
- if (slashes) quotes--, *q++ = '"';
-
- if (quotes > 0) {
- /* Outside a quote segment, a quote starts one. */
- if (!quote) quotes--;
-
-#if !MOD3
- /* New behaviour: produce n/2 literal quotes... */
- for (i = 2; i <= quotes; i += 2) *q++ = '"';
- /* ... and end in a quote segment iff 2 divides n. */
- quote = (quotes % 2 == 0);
-#else
- /* Old behaviour: produce (n+1)/3 literal quotes... */
- for (i = 3; i <= quotes+1; i += 3) *q++ = '"';
- /* ... and end in a quote segment iff 3 divides n. */
- quote = (quotes % 3 == 0);
-#endif
- }
- }
- } else {
- *q++ = *p++;
- }
- }
-
- /* At the end of an argument, just append a trailing NUL. */
- *q++ = '\0';
- }
-
- outputargv = sresize(outputargv, outputargc, char *);
- outputargstart = sresize(outputargstart, outputargc, char *);
-
- if (argc) *argc = outputargc;
- if (argv) *argv = outputargv; else sfree(outputargv);
- if (argstart) *argstart = outputargstart; else sfree(outputargstart);
-}
-
-#ifdef TESTMODE
-
-const struct argv_test {
- const char *cmdline;
- const char *argv[10];
-} argv_tests[] = {
- /*
- * We generate this set of tests by invoking ourself with
- * `-generate'.
- */
-#if !MOD3
- /* Newer behaviour, with no weird mod-3 glitch. */
- {"ab c\" d", {"ab", "c d", NULL}},
- {"a\"b c\" d", {"ab c", "d", NULL}},
- {"a\"\"b c\" d", {"ab", "c d", NULL}},
- {"a\"\"\"b c\" d", {"a\"b c", "d", NULL}},
- {"a\"\"\"\"b c\" d", {"a\"b", "c d", NULL}},
- {"a\"\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}},
- {"a\"\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
- {"a\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b c", "d", NULL}},
- {"a\"\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}},
- {"a\\b c\" d", {"a\\b", "c d", NULL}},
- {"a\\\"b c\" d", {"a\"b", "c d", NULL}},
- {"a\\\"\"b c\" d", {"a\"b c", "d", NULL}},
- {"a\\\"\"\"b c\" d", {"a\"b", "c d", NULL}},
- {"a\\\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}},
- {"a\\\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
- {"a\\\"\"\"\"\"\"b c\" d", {"a\"\"\"b c", "d", NULL}},
- {"a\\\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}},
- {"a\\\"\"\"\"\"\"\"\"b c\" d", {"a\"\"\"\"b c", "d", NULL}},
- {"a\\\\b c\" d", {"a\\\\b", "c d", NULL}},
- {"a\\\\\"b c\" d", {"a\\b c", "d", NULL}},
- {"a\\\\\"\"b c\" d", {"a\\b", "c d", NULL}},
- {"a\\\\\"\"\"b c\" d", {"a\\\"b c", "d", NULL}},
- {"a\\\\\"\"\"\"b c\" d", {"a\\\"b", "c d", NULL}},
- {"a\\\\\"\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}},
- {"a\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
- {"a\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b c", "d", NULL}},
- {"a\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}},
- {"a\\\\\\b c\" d", {"a\\\\\\b", "c d", NULL}},
- {"a\\\\\\\"b c\" d", {"a\\\"b", "c d", NULL}},
- {"a\\\\\\\"\"b c\" d", {"a\\\"b c", "d", NULL}},
- {"a\\\\\\\"\"\"b c\" d", {"a\\\"b", "c d", NULL}},
- {"a\\\\\\\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}},
- {"a\\\\\\\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
- {"a\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b c", "d", NULL}},
- {"a\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}},
- {"a\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"\"b c", "d", NULL}},
- {"a\\\\\\\\b c\" d", {"a\\\\\\\\b", "c d", NULL}},
- {"a\\\\\\\\\"b c\" d", {"a\\\\b c", "d", NULL}},
- {"a\\\\\\\\\"\"b c\" d", {"a\\\\b", "c d", NULL}},
- {"a\\\\\\\\\"\"\"b c\" d", {"a\\\\\"b c", "d", NULL}},
- {"a\\\\\\\\\"\"\"\"b c\" d", {"a\\\\\"b", "c d", NULL}},
- {"a\\\\\\\\\"\"\"\"\"b c\" d", {"a\\\\\"\"b c", "d", NULL}},
- {"a\\\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\\\"\"b", "c d", NULL}},
- {"a\\\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"\"b c", "d", NULL}},
- {"a\\\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"\"b", "c d", NULL}},
- {"\"ab c\" d", {"ab c", "d", NULL}},
- {"\"a\"b c\" d", {"ab", "c d", NULL}},
- {"\"a\"\"b c\" d", {"a\"b c", "d", NULL}},
- {"\"a\"\"\"b c\" d", {"a\"b", "c d", NULL}},
- {"\"a\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}},
- {"\"a\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
- {"\"a\"\"\"\"\"\"b c\" d", {"a\"\"\"b c", "d", NULL}},
- {"\"a\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}},
- {"\"a\"\"\"\"\"\"\"\"b c\" d", {"a\"\"\"\"b c", "d", NULL}},
- {"\"a\\b c\" d", {"a\\b c", "d", NULL}},
- {"\"a\\\"b c\" d", {"a\"b c", "d", NULL}},
- {"\"a\\\"\"b c\" d", {"a\"b", "c d", NULL}},
- {"\"a\\\"\"\"b c\" d", {"a\"\"b c", "d", NULL}},
- {"\"a\\\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
- {"\"a\\\"\"\"\"\"b c\" d", {"a\"\"\"b c", "d", NULL}},
- {"\"a\\\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}},
- {"\"a\\\"\"\"\"\"\"\"b c\" d", {"a\"\"\"\"b c", "d", NULL}},
- {"\"a\\\"\"\"\"\"\"\"\"b c\" d", {"a\"\"\"\"b", "c d", NULL}},
- {"\"a\\\\b c\" d", {"a\\\\b c", "d", NULL}},
- {"\"a\\\\\"b c\" d", {"a\\b", "c d", NULL}},
- {"\"a\\\\\"\"b c\" d", {"a\\\"b c", "d", NULL}},
- {"\"a\\\\\"\"\"b c\" d", {"a\\\"b", "c d", NULL}},
- {"\"a\\\\\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}},
- {"\"a\\\\\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
- {"\"a\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b c", "d", NULL}},
- {"\"a\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}},
- {"\"a\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"\"b c", "d", NULL}},
- {"\"a\\\\\\b c\" d", {"a\\\\\\b c", "d", NULL}},
- {"\"a\\\\\\\"b c\" d", {"a\\\"b c", "d", NULL}},
- {"\"a\\\\\\\"\"b c\" d", {"a\\\"b", "c d", NULL}},
- {"\"a\\\\\\\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}},
- {"\"a\\\\\\\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
- {"\"a\\\\\\\"\"\"\"\"b c\" d", {"a\\\"\"\"b c", "d", NULL}},
- {"\"a\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}},
- {"\"a\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"\"b c", "d", NULL}},
- {"\"a\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"\"b", "c d", NULL}},
- {"\"a\\\\\\\\b c\" d", {"a\\\\\\\\b c", "d", NULL}},
- {"\"a\\\\\\\\\"b c\" d", {"a\\\\b", "c d", NULL}},
- {"\"a\\\\\\\\\"\"b c\" d", {"a\\\\\"b c", "d", NULL}},
- {"\"a\\\\\\\\\"\"\"b c\" d", {"a\\\\\"b", "c d", NULL}},
- {"\"a\\\\\\\\\"\"\"\"b c\" d", {"a\\\\\"\"b c", "d", NULL}},
- {"\"a\\\\\\\\\"\"\"\"\"b c\" d", {"a\\\\\"\"b", "c d", NULL}},
- {"\"a\\\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\\\"\"\"b c", "d", NULL}},
- {"\"a\\\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"\"b", "c d", NULL}},
- {"\"a\\\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"\"\"b c", "d", NULL}},
-#else /* MOD3 */
- /* VS7 mod-3 behaviour. */
- {"ab c\" d", {"ab", "c d", NULL}},
- {"a\"b c\" d", {"ab c", "d", NULL}},
- {"a\"\"b c\" d", {"ab", "c d", NULL}},
- {"a\"\"\"b c\" d", {"a\"b", "c d", NULL}},
- {"a\"\"\"\"b c\" d", {"a\"b c", "d", NULL}},
- {"a\"\"\"\"\"b c\" d", {"a\"b", "c d", NULL}},
- {"a\"\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
- {"a\"\"\"\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}},
- {"a\"\"\"\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
- {"a\\b c\" d", {"a\\b", "c d", NULL}},
- {"a\\\"b c\" d", {"a\"b", "c d", NULL}},
- {"a\\\"\"b c\" d", {"a\"b c", "d", NULL}},
- {"a\\\"\"\"b c\" d", {"a\"b", "c d", NULL}},
- {"a\\\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
- {"a\\\"\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}},
- {"a\\\"\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
- {"a\\\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}},
- {"a\\\"\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b c", "d", NULL}},
- {"a\\\\b c\" d", {"a\\\\b", "c d", NULL}},
- {"a\\\\\"b c\" d", {"a\\b c", "d", NULL}},
- {"a\\\\\"\"b c\" d", {"a\\b", "c d", NULL}},
- {"a\\\\\"\"\"b c\" d", {"a\\\"b", "c d", NULL}},
- {"a\\\\\"\"\"\"b c\" d", {"a\\\"b c", "d", NULL}},
- {"a\\\\\"\"\"\"\"b c\" d", {"a\\\"b", "c d", NULL}},
- {"a\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
- {"a\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}},
- {"a\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
- {"a\\\\\\b c\" d", {"a\\\\\\b", "c d", NULL}},
- {"a\\\\\\\"b c\" d", {"a\\\"b", "c d", NULL}},
- {"a\\\\\\\"\"b c\" d", {"a\\\"b c", "d", NULL}},
- {"a\\\\\\\"\"\"b c\" d", {"a\\\"b", "c d", NULL}},
- {"a\\\\\\\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
- {"a\\\\\\\"\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}},
- {"a\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
- {"a\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}},
- {"a\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b c", "d", NULL}},
- {"a\\\\\\\\b c\" d", {"a\\\\\\\\b", "c d", NULL}},
- {"a\\\\\\\\\"b c\" d", {"a\\\\b c", "d", NULL}},
- {"a\\\\\\\\\"\"b c\" d", {"a\\\\b", "c d", NULL}},
- {"a\\\\\\\\\"\"\"b c\" d", {"a\\\\\"b", "c d", NULL}},
- {"a\\\\\\\\\"\"\"\"b c\" d", {"a\\\\\"b c", "d", NULL}},
- {"a\\\\\\\\\"\"\"\"\"b c\" d", {"a\\\\\"b", "c d", NULL}},
- {"a\\\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\\\"\"b", "c d", NULL}},
- {"a\\\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"b c", "d", NULL}},
- {"a\\\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"b", "c d", NULL}},
- {"\"ab c\" d", {"ab c", "d", NULL}},
- {"\"a\"b c\" d", {"ab", "c d", NULL}},
- {"\"a\"\"b c\" d", {"a\"b", "c d", NULL}},
- {"\"a\"\"\"b c\" d", {"a\"b c", "d", NULL}},
- {"\"a\"\"\"\"b c\" d", {"a\"b", "c d", NULL}},
- {"\"a\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
- {"\"a\"\"\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}},
- {"\"a\"\"\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
- {"\"a\"\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}},
- {"\"a\\b c\" d", {"a\\b c", "d", NULL}},
- {"\"a\\\"b c\" d", {"a\"b c", "d", NULL}},
- {"\"a\\\"\"b c\" d", {"a\"b", "c d", NULL}},
- {"\"a\\\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
- {"\"a\\\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}},
- {"\"a\\\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
- {"\"a\\\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}},
- {"\"a\\\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b c", "d", NULL}},
- {"\"a\\\"\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}},
- {"\"a\\\\b c\" d", {"a\\\\b c", "d", NULL}},
- {"\"a\\\\\"b c\" d", {"a\\b", "c d", NULL}},
- {"\"a\\\\\"\"b c\" d", {"a\\\"b", "c d", NULL}},
- {"\"a\\\\\"\"\"b c\" d", {"a\\\"b c", "d", NULL}},
- {"\"a\\\\\"\"\"\"b c\" d", {"a\\\"b", "c d", NULL}},
- {"\"a\\\\\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
- {"\"a\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}},
- {"\"a\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
- {"\"a\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}},
- {"\"a\\\\\\b c\" d", {"a\\\\\\b c", "d", NULL}},
- {"\"a\\\\\\\"b c\" d", {"a\\\"b c", "d", NULL}},
- {"\"a\\\\\\\"\"b c\" d", {"a\\\"b", "c d", NULL}},
- {"\"a\\\\\\\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
- {"\"a\\\\\\\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}},
- {"\"a\\\\\\\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
- {"\"a\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}},
- {"\"a\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b c", "d", NULL}},
- {"\"a\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}},
- {"\"a\\\\\\\\b c\" d", {"a\\\\\\\\b c", "d", NULL}},
- {"\"a\\\\\\\\\"b c\" d", {"a\\\\b", "c d", NULL}},
- {"\"a\\\\\\\\\"\"b c\" d", {"a\\\\\"b", "c d", NULL}},
- {"\"a\\\\\\\\\"\"\"b c\" d", {"a\\\\\"b c", "d", NULL}},
- {"\"a\\\\\\\\\"\"\"\"b c\" d", {"a\\\\\"b", "c d", NULL}},
- {"\"a\\\\\\\\\"\"\"\"\"b c\" d", {"a\\\\\"\"b", "c d", NULL}},
- {"\"a\\\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\\\"\"b c", "d", NULL}},
- {"\"a\\\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"b", "c d", NULL}},
- {"\"a\\\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"\"b", "c d", NULL}},
-#endif /* MOD3 */
-};
-
-int main(int argc, char **argv)
-{
- int i, j;
-
- if (argc > 1) {
- /*
- * Generation of tests.
- *
- * Given `-splat <args>', we print out a C-style
- * representation of each argument (in the form "a", "b",
- * NULL), backslash-escaping each backslash and double
- * quote.
- *
- * Given `-split <string>', we first doctor `string' by
- * turning forward slashes into backslashes, single quotes
- * into double quotes and underscores into spaces; and then
- * we feed the resulting string to ourself with `-splat'.
- *
- * Given `-generate', we concoct a variety of fun test
- * cases, encode them in quote-safe form (mapping \, " and
- * space to /, ' and _ respectively) and feed each one to
- * `-split'.
- */
- if (!strcmp(argv[1], "-splat")) {
- int i;
- char *p;
- for (i = 2; i < argc; i++) {
- putchar('"');
- for (p = argv[i]; *p; p++) {
- if (*p == '\\' || *p == '"')
- putchar('\\');
- putchar(*p);
- }
- printf("\", ");
- }
- printf("NULL");
- return 0;
- }
-
- if (!strcmp(argv[1], "-split") && argc > 2) {
- char *str = malloc(20 + strlen(argv[0]) + strlen(argv[2]));
- char *p, *q;
-
- q = str + sprintf(str, "%s -splat ", argv[0]);
- printf(" {\"");
- for (p = argv[2]; *p; p++, q++) {
- switch (*p) {
- case '/': printf("\\\\"); *q = '\\'; break;
- case '\'': printf("\\\""); *q = '"'; break;
- case '_': printf(" "); *q = ' '; break;
- default: putchar(*p); *q = *p; break;
- }
- }
- *p = '\0';
- printf("\", {");
- fflush(stdout);
-
- system(str);
-
- printf("}},\n");
-
- return 0;
- }
-
- if (!strcmp(argv[1], "-generate")) {
- char *teststr, *p;
- int i, initialquote, backslashes, quotes;
-
- teststr = malloc(200 + strlen(argv[0]));
-
- for (initialquote = 0; initialquote <= 1; initialquote++) {
- for (backslashes = 0; backslashes < 5; backslashes++) {
- for (quotes = 0; quotes < 9; quotes++) {
- p = teststr + sprintf(teststr, "%s -split ", argv[0]);
- if (initialquote) *p++ = '\'';
- *p++ = 'a';
- for (i = 0; i < backslashes; i++) *p++ = '/';
- for (i = 0; i < quotes; i++) *p++ = '\'';
- *p++ = 'b';
- *p++ = '_';
- *p++ = 'c';
- *p++ = '\'';
- *p++ = '_';
- *p++ = 'd';
- *p = '\0';
-
- system(teststr);
- }
- }
- }
- return 0;
- }
-
- fprintf(stderr, "unrecognised option: \"%s\"\n", argv[1]);
- return 1;
- }
-
- /*
- * If we get here, we were invoked with no arguments, so just
- * run the tests.
- */
-
- for (i = 0; i < lenof(argv_tests); i++) {
- int ac;
- char **av;
-
- split_into_argv(argv_tests[i].cmdline, &ac, &av);
-
- for (j = 0; j < ac && argv_tests[i].argv[j]; j++) {
- if (strcmp(av[j], argv_tests[i].argv[j])) {
- printf("failed test %d (|%s|) arg %d: |%s| should be |%s|\n",
- i, argv_tests[i].cmdline,
- j, av[j], argv_tests[i].argv[j]);
- }
-#ifdef VERBOSE
- else {
- printf("test %d (|%s|) arg %d: |%s| == |%s|\n",
- i, argv_tests[i].cmdline,
- j, av[j], argv_tests[i].argv[j]);
- }
-#endif
- }
- if (j < ac)
- printf("failed test %d (|%s|): %d args returned, should be %d\n",
- i, argv_tests[i].cmdline, ac, j);
- if (argv_tests[i].argv[j])
- printf("failed test %d (|%s|): %d args returned, should be more\n",
- i, argv_tests[i].cmdline, ac);
- }
-
- return 0;
-}
-
-#endif
diff --git a/WINDOWS/WINX11.C b/WINDOWS/WINX11.C
deleted file mode 100644
index 800d8509..00000000
--- a/WINDOWS/WINX11.C
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * winx11.c: fetch local auth data for X forwarding.
- */
-
-#include <ctype.h>
-#include <assert.h>
-#include <stdlib.h>
-
-#include "putty.h"
-#include "ssh.h"
-
-void platform_get_x11_auth(struct X11Display *disp, Conf *conf)
-{
- char *xauthpath = conf_get_filename(conf, CONF_xauthfile)->path;
- if (xauthpath[0])
- x11_get_auth_from_authfile(disp, xauthpath);
-}
-
-const bool platform_uses_x11_unix_by_default = false;
diff --git a/WINDOWS/WIN_RES.H b/WINDOWS/WIN_RES.H
deleted file mode 100644
index d34f6852..00000000
--- a/WINDOWS/WIN_RES.H
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * win_res.h - constants shared between win_res.rc2 and the C code.
- */
-
-#ifndef PUTTY_WIN_RES_H
-#define PUTTY_WIN_RES_H
-
-#define IDI_MAINICON 200
-#define IDI_CFGICON 201
-
-#define IDD_MAINBOX 102
-#define IDD_LOGBOX 110
-#define IDD_ABOUTBOX 111
-#define IDD_RECONF 112
-#define IDD_LICENCEBOX 113
-#define IDD_HK_ABSENT 114
-#define IDD_HK_WRONG 115
-#define IDD_HK_MOREINFO 116
-
-#define IDN_LIST 1001
-#define IDN_COPY 1002
-
-#define IDA_ICON 1001
-#define IDA_TEXT 1002
-#define IDA_LICENCE 1003
-#define IDA_WEB 1004
-
-#define IDC_TAB 1001
-#define IDC_TABSTATIC1 1002
-#define IDC_TABSTATIC2 1003
-#define IDC_TABLIST 1004
-#define IDC_HELPBTN 1005
-#define IDC_ABOUT 1006
-
-#define IDC_HK_ICON 98
-#define IDC_HK_TITLE 99
-#define IDC_HK_ACCEPT 1001
-#define IDC_HK_ONCE 1000
-#define IDC_HK_FINGERPRINT 1002
-#define IDC_HK_MOREINFO 1003
-
-#define IDC_HKI_SHA256 1000
-#define IDC_HKI_MD5 1001
-#define IDC_HKI_PUBKEY 1002
-
-#define ID_CUSTOM_CHMFILE 2000
-#define TYPE_CUSTOM_CHMFILE 2000
-
-#endif
diff --git a/WINDOWS/WIN_RES.RC2 b/WINDOWS/WIN_RES.RC2
deleted file mode 100644
index ccec3122..00000000
--- a/WINDOWS/WIN_RES.RC2
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Windows resources shared between PuTTY and PuTTYtel, to be #include'd
- * after defining appropriate macros.
- *
- * Note that many of these strings mention PuTTY. Due to restrictions in
- * VC's handling of string concatenation, this can't easily be fixed.
- * It's fixed up at runtime.
- *
- * This file has the more or less arbitrary extension '.rc2' to avoid
- * IDEs taking it to be a top-level resource script in its own right
- * (which has been known to happen if the extension was '.rc'), and
- * also to avoid the resource compiler ignoring everything included
- * from it (which happens if the extension is '.h').
- */
-
-#include "win_res.h"
-
-IDI_MAINICON ICON "putty.ico"
-
-IDI_CFGICON ICON "puttycfg.ico"
-
-/* Accelerators used: clw */
-IDD_ABOUTBOX DIALOG DISCARDABLE 140, 40, 270, 136
-STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "About PuTTY"
-FONT 8, "MS Shell Dlg"
-BEGIN
- DEFPUSHBUTTON "&Close", IDOK, 216, 118, 48, 14
- PUSHBUTTON "View &Licence", IDA_LICENCE, 6, 118, 70, 14
- PUSHBUTTON "Visit &Web Site", IDA_WEB, 140, 118, 70, 14
- EDITTEXT IDA_TEXT, 10, 6, 250, 110, ES_READONLY | ES_MULTILINE | ES_CENTER, WS_EX_STATICEDGE
-END
-
-/* Accelerators used: aco */
-IDD_MAINBOX DIALOG DISCARDABLE 0, 0, 300, 252
-STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "PuTTY Configuration"
-FONT 8, "MS Shell Dlg"
-CLASS "PuTTYConfigBox"
-BEGIN
-END
-
-/* Accelerators used: co */
-IDD_LOGBOX DIALOG DISCARDABLE 100, 20, 300, 119
-STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "PuTTY Event Log"
-FONT 8, "MS Shell Dlg"
-BEGIN
- DEFPUSHBUTTON "&Close", IDOK, 135, 102, 44, 14
- PUSHBUTTON "C&opy", IDN_COPY, 81, 102, 44, 14
- LISTBOX IDN_LIST, 3, 3, 294, 95, LBS_HASSTRINGS | LBS_USETABSTOPS | WS_VSCROLL | LBS_EXTENDEDSEL
-END
-
-/* No accelerators used */
-IDD_LICENCEBOX DIALOG DISCARDABLE 50, 50, 326, 239
-STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "PuTTY Licence"
-FONT 8, "MS Shell Dlg"
-BEGIN
- DEFPUSHBUTTON "OK", IDOK, 148, 219, 44, 14
-
- EDITTEXT IDA_TEXT, 10, 10, 306, 200, ES_READONLY | ES_MULTILINE | ES_LEFT, WS_EX_STATICEDGE
-END
-
-/* No accelerators used */
-IDD_HK_ABSENT DIALOG DISCARDABLE 50, 50, 340, 148
-STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "PuTTY Security Alert"
-FONT 8, "MS Shell Dlg"
-BEGIN
- LTEXT "The server's host key is not cached in the registry. You have no", 100, 40, 20, 300, 8
- LTEXT "guarantee that the server is the computer you think it is.", 101, 40, 28, 300, 8
- LTEXT "The server's {KEYTYPE} key fingerprint is:", 102, 40, 40, 300, 8
- LTEXT "If you trust this host, press ""Accept"" to add the key to {APPNAME}'s", 103, 40, 60, 300, 8
- LTEXT "cache and carry on connecting.", 104, 40, 68, 300, 8
- LTEXT "If you want to carry on connecting just once, without adding the key", 105, 40, 80, 300, 8
- LTEXT "to the cache, press ""Connect Once"".", 106, 40, 88, 300, 8
- LTEXT "If you do not trust this host, press ""Cancel"" to abandon the connection.", 107, 40, 100, 300, 8
-
- ICON "", IDC_HK_ICON, 10, 18, 0, 0
-
- PUSHBUTTON "Cancel", IDCANCEL, 288, 128, 40, 14
- PUSHBUTTON "Accept", IDC_HK_ACCEPT, 168, 128, 40, 14
- PUSHBUTTON "Connect Once", IDC_HK_ONCE, 216, 128, 64, 14
- PUSHBUTTON "More info...", IDC_HK_MOREINFO, 60, 128, 64, 14
- PUSHBUTTON "Help", IDHELP, 12, 128, 40, 14
-
- EDITTEXT IDC_HK_FINGERPRINT, 40, 48, 300, 12, ES_READONLY | ES_LEFT, 0
-END
-
-/* No accelerators used */
-IDD_HK_WRONG DIALOG DISCARDABLE 50, 50, 340, 188
-STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "PuTTY Security Alert"
-FONT 8, "MS Shell Dlg"
-BEGIN
- LTEXT "WARNING - POTENTIAL SECURITY BREACH!", IDC_HK_TITLE, 40, 20, 300, 12
-
- LTEXT "The server's host key does not match the one {APPNAME} has cached in", 100, 40, 36, 300, 8
- LTEXT "the registry. This means that either the server administrator has", 101, 40, 44, 300, 8
- LTEXT "changed the host key, or you have actually connected to another", 102, 40, 52, 300, 8
- LTEXT "computer pretending to be the server.", 103, 40, 60, 300, 8
- LTEXT "The new {KEYTYPE} key fingerprint is:", 104, 40, 72, 300, 8
- LTEXT "If you were expecting this change and trust the new key, press", 105, 40, 92, 300, 8
- LTEXT """Accept"" to update {APPNAME}'s cache and continue connecting.", 106, 40, 100, 300, 8
- LTEXT "If you want to carry on connecting but without updating the cache,", 107, 40, 112, 300, 8
- LTEXT "press ""Connect Once"".", 108, 40, 120, 300, 8
- LTEXT "If you want to abandon the connection completely, press ""Cancel"".", 109, 40, 132, 300, 8
- LTEXT "Pressing ""Cancel"" is the ONLY guaranteed safe choice.", 110, 40, 140, 300, 8
-
- ICON "", IDC_HK_ICON, 10, 16, 0, 0
-
- PUSHBUTTON "Cancel", IDCANCEL, 288, 168, 40, 14
- PUSHBUTTON "Accept", IDC_HK_ACCEPT, 168, 168, 40, 14
- PUSHBUTTON "Connect Once", IDC_HK_ONCE, 216, 168, 64, 14
- PUSHBUTTON "More info...", IDC_HK_MOREINFO, 60, 168, 64, 14
- PUSHBUTTON "Help", IDHELP, 12, 168, 40, 14
-
- EDITTEXT IDC_HK_FINGERPRINT, 40, 80, 300, 12, ES_READONLY | ES_LEFT, 0
-END
-
-/* Accelerators used: clw */
-IDD_HK_MOREINFO DIALOG DISCARDABLE 140, 40, 400, 156
-STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "PuTTY: information about the server's host key"
-FONT 8, "MS Shell Dlg"
-BEGIN
- LTEXT "SHA256 fingerprint:", 100, 12, 12, 80, 8
- EDITTEXT IDC_HKI_SHA256, 100, 10, 288, 12, ES_READONLY
- LTEXT "MD5 fingerprint:", 101, 12, 28, 80, 8
- EDITTEXT IDC_HKI_MD5, 100, 26, 288, 12, ES_READONLY
- LTEXT "Full public key:", 102, 12, 44, 376, 8
- EDITTEXT IDC_HKI_PUBKEY, 12, 54, 376, 64, ES_READONLY | ES_MULTILINE | ES_LEFT | ES_AUTOVSCROLL, WS_EX_STATICEDGE
- DEFPUSHBUTTON "&Close", IDOK, 176, 130, 48, 14
-END
-
-#include "version.rc2"
diff --git a/WINDOWS/installer.wxs b/WINDOWS/installer.wxs
index b221320e..65a7f379 100644
--- a/WINDOWS/installer.wxs
+++ b/WINDOWS/installer.wxs
@@ -91,6 +91,10 @@
<?define Desktop_Shortcut_Component_GUID = "8999BBE1-F99E-4301-B7A6-480C19DE13B9" ?>
<?endif ?>
+<?ifndef HelpFilePath ?>
+ <?define HelpFilePath = "../doc/putty.chm" ?>
+<?endif ?>
+
<?define ProgramName = "PuTTY$(var.Bitness)" ?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
@@ -117,12 +121,6 @@
Language="1033" Codepage="1252" Version="$(var.Winver)">
<!--
- We force the install scope to perMachine, largely because I
- don't really understand how to make it usefully switchable
- between the two. If anyone is a WiX expert and does want to
- install PuTTY locally in a user account, I hope they'll send a
- well explained patch!
-
$(var.Puttytextver) is again defined on the candle command
line, and describes the version of PuTTY in human-readable
form, e.g. "PuTTY 0.67" or "PuTTY development snapshot [foo]".
@@ -131,8 +129,7 @@
Description="$(var.Puttytextver) installer"
Manufacturer="Simon Tatham"
InstallerVersion="$(var.InstallerVersion)" Languages="1033"
- Compressed="yes" SummaryCodepage="1252"
- InstallScope="perMachine" />
+ Compressed="yes" SummaryCodepage="1252" />
<!--
Permit installing an arbitrary one of these PuTTY installers
@@ -238,7 +235,7 @@ https://msdn.microsoft.com/en-us/library/windows/desktop/dd391569(v=vs.85).aspx
<Component Id="HelpFile_Component"
Guid="$(var.HelpFile_Component_GUID)">
<File Id="HelpFile_File"
- Source="../doc/putty.chm" KeyPath="yes">
+ Source="$(var.HelpFilePath)" KeyPath="yes">
<Shortcut Id="startmenuManual" Directory="ProgramMenuDir"
Name="PuTTY Manual"
Advertise="no" />
diff --git a/WINDOWS/wincapi.c b/WINDOWS/wincapi.c
deleted file mode 100644
index de78988b..00000000
--- a/WINDOWS/wincapi.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * wincapi.c: implementation of wincapi.h.
- */
-
-#include "putty.h"
-
-#if !defined NO_SECURITY
-
-#include "putty.h"
-#include "ssh.h"
-
-#include "wincapi.h"
-
-DEF_WINDOWS_FUNCTION(CryptProtectMemory);
-
-bool got_crypt(void)
-{
- static bool attempted = false;
- static bool successful;
- static HMODULE crypt;
-
- if (!attempted) {
- attempted = true;
- crypt = load_system32_dll("crypt32.dll");
- successful = crypt &&
- GET_WINDOWS_FUNCTION(crypt, CryptProtectMemory);
- }
- return successful;
-}
-
-char *capi_obfuscate_string(const char *realname)
-{
- char *cryptdata;
- int cryptlen;
- unsigned char digest[32];
- char retbuf[65];
- int i;
-
- cryptlen = strlen(realname) + 1;
- cryptlen += CRYPTPROTECTMEMORY_BLOCK_SIZE - 1;
- cryptlen /= CRYPTPROTECTMEMORY_BLOCK_SIZE;
- cryptlen *= CRYPTPROTECTMEMORY_BLOCK_SIZE;
-
- cryptdata = snewn(cryptlen, char);
- memset(cryptdata, 0, cryptlen);
- strcpy(cryptdata, realname);
-
- /*
- * CRYPTPROTECTMEMORY_CROSS_PROCESS causes CryptProtectMemory to
- * use the same key in all processes with this user id, meaning
- * that the next PuTTY process calling this function with the same
- * input will get the same data.
- *
- * (Contrast with CryptProtectData, which invents a new session
- * key every time since its API permits returning more data than
- * was input, so calling _that_ and hashing the output would not
- * be stable.)
- *
- * We don't worry too much if this doesn't work for some reason.
- * Omitting this step still has _some_ privacy value (in that
- * another user can test-hash things to confirm guesses as to
- * where you might be connecting to, but cannot invert SHA-256 in
- * the absence of any plausible guess). So we don't abort if we
- * can't call CryptProtectMemory at all, or if it fails.
- */
- if (got_crypt())
- p_CryptProtectMemory(cryptdata, cryptlen,
- CRYPTPROTECTMEMORY_CROSS_PROCESS);
-
- /*
- * We don't want to give away the length of the hostname either,
- * so having got it back out of CryptProtectMemory we now hash it.
- */
- {
- ssh_hash *h = ssh_hash_new(&ssh_sha256);
- put_string(h, cryptdata, cryptlen);
- ssh_hash_final(h, digest);
- }
-
- sfree(cryptdata);
-
- /*
- * Finally, make printable.
- */
- for (i = 0; i < 32; i++) {
- sprintf(retbuf + 2*i, "%02x", digest[i]);
- /* the last of those will also write the trailing NUL */
- }
-
- return dupstr(retbuf);
-}
-
-#endif /* !defined NO_SECURITY */
diff --git a/WINDOWS/wincapi.h b/WINDOWS/wincapi.h
deleted file mode 100644
index 732412e2..00000000
--- a/WINDOWS/wincapi.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * wincapi.h: Windows Crypto API functions defined in wincapi.c that
- * use the crypt32 library. Also centralises the machinery for
- * dynamically loading that library, and our own functions using that
- * in turn.
- */
-
-#if !defined NO_SECURITY
-
-DECL_WINDOWS_FUNCTION(extern, BOOL, CryptProtectMemory, (LPVOID,DWORD,DWORD));
-
-bool got_crypt(void);
-
-/*
- * Function to obfuscate an input string into something usable as a
- * pathname for a Windows named pipe. Uses CryptProtectMemory to make
- * the obfuscation depend on a key Windows stores for the owning user,
- * and then hashes the string as well to make it have a manageable
- * length and be composed of filename-legal characters.
- *
- * Rationale: Windows's named pipes all live in the same namespace, so
- * one user can see what pipes another user has open. This is an
- * undesirable privacy leak: in particular, if we used unobfuscated
- * names for the connection-sharing pipe names, it would permit one
- * user to know what username@host another user is SSHing to.
- *
- * The returned string is dynamically allocated.
- */
-char *capi_obfuscate_string(const char *realname);
-
-#endif
diff --git a/WINDOWS/wincliloop.c b/WINDOWS/wincliloop.c
deleted file mode 100644
index 26a4d3aa..00000000
--- a/WINDOWS/wincliloop.c
+++ /dev/null
@@ -1,136 +0,0 @@
-#include "putty.h"
-
-void cli_main_loop(cliloop_pre_t pre, cliloop_post_t post, void *ctx)
-{
- SOCKET *sklist = NULL;
- size_t skcount = 0, sksize = 0;
- unsigned long now, next, then;
- now = GETTICKCOUNT();
-
- while (true) {
- int nhandles;
- HANDLE *handles;
- DWORD n;
- DWORD ticks;
-
- const HANDLE *extra_handles = NULL;
- size_t n_extra_handles = 0;
- if (!pre(ctx, &extra_handles, &n_extra_handles))
- break;
-
- if (toplevel_callback_pending()) {
- ticks = 0;
- next = now;
- } else if (run_timers(now, &next)) {
- then = now;
- now = GETTICKCOUNT();
- if (now - then > next - then)
- ticks = 0;
- else
- ticks = next - now;
- } else {
- ticks = INFINITE;
- /* no need to initialise next here because we can never
- * get WAIT_TIMEOUT */
- }
-
- handles = handle_get_events(&nhandles);
- size_t winselcli_index = -(size_t)1;
- size_t extra_base = nhandles;
- if (winselcli_event != INVALID_HANDLE_VALUE) {
- winselcli_index = extra_base++;
- handles = sresize(handles, extra_base, HANDLE);
- handles[winselcli_index] = winselcli_event;
- }
- size_t total_handles = extra_base + n_extra_handles;
- handles = sresize(handles, total_handles, HANDLE);
- for (size_t i = 0; i < n_extra_handles; i++)
- handles[extra_base + i] = extra_handles[i];
-
- n = WaitForMultipleObjects(total_handles, handles, false, ticks);
-
- size_t extra_handle_index = n_extra_handles;
-
- if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) {
- handle_got_event(handles[n - WAIT_OBJECT_0]);
- } else if (winselcli_event != INVALID_HANDLE_VALUE &&
- n == WAIT_OBJECT_0 + winselcli_index) {
- WSANETWORKEVENTS things;
- SOCKET socket;
- int i, socketstate;
-
- /*
- * We must not call select_result() for any socket
- * until we have finished enumerating within the tree.
- * This is because select_result() may close the socket
- * and modify the tree.
- */
- /* Count the active sockets. */
- i = 0;
- for (socket = first_socket(&socketstate);
- socket != INVALID_SOCKET;
- socket = next_socket(&socketstate)) i++;
-
- /* Expand the buffer if necessary. */
- sgrowarray(sklist, sksize, i);
-
- /* Retrieve the sockets into sklist. */
- skcount = 0;
- for (socket = first_socket(&socketstate);
- socket != INVALID_SOCKET;
- socket = next_socket(&socketstate)) {
- sklist[skcount++] = socket;
- }
-
- /* Now we're done enumerating; go through the list. */
- for (i = 0; i < skcount; i++) {
- WPARAM wp;
- socket = sklist[i];
- wp = (WPARAM) socket;
- if (!p_WSAEnumNetworkEvents(socket, NULL, &things)) {
- static const struct { int bit, mask; } eventtypes[] = {
- {FD_CONNECT_BIT, FD_CONNECT},
- {FD_READ_BIT, FD_READ},
- {FD_CLOSE_BIT, FD_CLOSE},
- {FD_OOB_BIT, FD_OOB},
- {FD_WRITE_BIT, FD_WRITE},
- {FD_ACCEPT_BIT, FD_ACCEPT},
- };
- int e;
-
- noise_ultralight(NOISE_SOURCE_IOID, socket);
-
- for (e = 0; e < lenof(eventtypes); e++)
- if (things.lNetworkEvents & eventtypes[e].mask) {
- LPARAM lp;
- int err = things.iErrorCode[eventtypes[e].bit];
- lp = WSAMAKESELECTREPLY(eventtypes[e].mask, err);
- select_result(wp, lp);
- }
- }
- }
- } else if (n >= WAIT_OBJECT_0 + extra_base &&
- n < WAIT_OBJECT_0 + extra_base + n_extra_handles) {
- extra_handle_index = n - (WAIT_OBJECT_0 + extra_base);
- }
-
- run_toplevel_callbacks();
-
- if (n == WAIT_TIMEOUT) {
- now = next;
- } else {
- now = GETTICKCOUNT();
- }
-
- sfree(handles);
-
- if (!post(ctx, extra_handle_index))
- break;
- }
-
- sfree(sklist);
-}
-
-bool cliloop_null_pre(void *vctx, const HANDLE **eh, size_t *neh)
-{ return true; }
-bool cliloop_null_post(void *vctx, size_t ehi) { return true; }
diff --git a/WINDOWS/winhelp.rc2 b/WINDOWS/winhelp.rc2
deleted file mode 100644
index 3499d25e..00000000
--- a/WINDOWS/winhelp.rc2
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "win_res.h"
-
-#ifdef EMBED_CHM
-ID_CUSTOM_CHMFILE TYPE_CUSTOM_CHMFILE "../doc/putty.chm"
-#define HELPVER " (with embedded help)"
-#else
-#define HELPVER " (without embedded help)"
-#endif
diff --git a/WINDOWS/winhsock.c b/WINDOWS/winhsock.c
deleted file mode 100644
index 543b77b6..00000000
--- a/WINDOWS/winhsock.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * General mechanism for wrapping up reading/writing of Windows
- * HANDLEs into a PuTTY Socket abstraction.
- */
-
-#include <stdio.h>
-#include <assert.h>
-#include <limits.h>
-
-#include "tree234.h"
-#include "putty.h"
-#include "network.h"
-
-typedef struct HandleSocket {
- HANDLE send_H, recv_H, stderr_H;
- struct handle *send_h, *recv_h, *stderr_h;
-
- /*
- * Freezing one of these sockets is a slightly fiddly business,
- * because the reads from the handle are happening in a separate
- * thread as blocking system calls and so once one is in progress
- * it can't sensibly be interrupted. Hence, after the user tries
- * to freeze one of these sockets, it's unavoidable that we may
- * receive one more load of data before we manage to get
- * winhandl.c to stop reading.
- */
- enum {
- UNFROZEN, /* reading as normal */
- FREEZING, /* have been set to frozen but winhandl is still reading */
- FROZEN, /* really frozen - winhandl has been throttled */
- THAWING /* we're gradually releasing our remaining data */
- } frozen;
- /* We buffer data here if we receive it from winhandl while frozen. */
- bufchain inputdata;
-
- /* Handle logging proxy error messages from stderr_H, if we have one. */
- ProxyStderrBuf psb;
-
- bool defer_close, deferred_close; /* in case of re-entrance */
-
- char *error;
-
- Plug *plug;
-
- Socket sock;
-} HandleSocket;
-
-static size_t handle_gotdata(
- struct handle *h, const void *data, size_t len, int err)
-{
- HandleSocket *hs = (HandleSocket *)handle_get_privdata(h);
-
- if (err) {
- plug_closing(hs->plug, "Read error from handle", 0, 0);
- return 0;
- } else if (len == 0) {
- plug_closing(hs->plug, NULL, 0, 0);
- return 0;
- } else {
- assert(hs->frozen != FROZEN && hs->frozen != THAWING);
- if (hs->frozen == FREEZING) {
- /*
- * If we've received data while this socket is supposed to
- * be frozen (because the read winhandl.c started before
- * sk_set_frozen was called has now returned) then buffer
- * the data for when we unfreeze.
- */
- bufchain_add(&hs->inputdata, data, len);
- hs->frozen = FROZEN;
-
- /*
- * And return a very large backlog, to prevent further
- * data arriving from winhandl until we unfreeze.
- */
- return INT_MAX;
- } else {
- plug_receive(hs->plug, 0, data, len);
- return 0;
- }
- }
-}
-
-static size_t handle_stderr(
- struct handle *h, const void *data, size_t len, int err)
-{
- HandleSocket *hs = (HandleSocket *)handle_get_privdata(h);
-
- if (!err && len > 0)
- log_proxy_stderr(hs->plug, &hs->psb, data, len);
-
- return 0;
-}
-
-static void handle_sentdata(struct handle *h, size_t new_backlog, int err)
-{
- HandleSocket *hs = (HandleSocket *)handle_get_privdata(h);
-
- if (err) {
- plug_closing(hs->plug, win_strerror(err), err, 0);
- return;
- }
-
- plug_sent(hs->plug, new_backlog);
-}
-
-static Plug *sk_handle_plug(Socket *s, Plug *p)
-{
- HandleSocket *hs = container_of(s, HandleSocket, sock);
- Plug *ret = hs->plug;
- if (p)
- hs->plug = p;
- return ret;
-}
-
-static void sk_handle_close(Socket *s)
-{
- HandleSocket *hs = container_of(s, HandleSocket, sock);
-
- if (hs->defer_close) {
- hs->deferred_close = true;
- return;
- }
-
- handle_free(hs->send_h);
- handle_free(hs->recv_h);
- CloseHandle(hs->send_H);
- if (hs->recv_H != hs->send_H)
- CloseHandle(hs->recv_H);
- bufchain_clear(&hs->inputdata);
-
- delete_callbacks_for_context(hs);
-
- sfree(hs);
-}
-
-static size_t sk_handle_write(Socket *s, const void *data, size_t len)
-{
- HandleSocket *hs = container_of(s, HandleSocket, sock);
-
- return handle_write(hs->send_h, data, len);
-}
-
-static size_t sk_handle_write_oob(Socket *s, const void *data, size_t len)
-{
- /*
- * oob data is treated as inband; nasty, but nothing really
- * better we can do
- */
- return sk_handle_write(s, data, len);
-}
-
-static void sk_handle_write_eof(Socket *s)
-{
- HandleSocket *hs = container_of(s, HandleSocket, sock);
-
- handle_write_eof(hs->send_h);
-}
-
-static void handle_socket_unfreeze(void *hsv)
-{
- HandleSocket *hs = (HandleSocket *)hsv;
-
- /*
- * If we've been put into a state other than THAWING since the
- * last callback, then we're done.
- */
- if (hs->frozen != THAWING)
- return;
-
- /*
- * Get some of the data we've buffered.
- */
- ptrlen data = bufchain_prefix(&hs->inputdata);
- assert(data.len > 0);
-
- /*
- * Hand it off to the plug. Be careful of re-entrance - that might
- * have the effect of trying to close this socket.
- */
- hs->defer_close = true;
- plug_receive(hs->plug, 0, data.ptr, data.len);
- bufchain_consume(&hs->inputdata, data.len);
- hs->defer_close = false;
- if (hs->deferred_close) {
- sk_handle_close(&hs->sock);
- return;
- }
-
- if (bufchain_size(&hs->inputdata) > 0) {
- /*
- * If there's still data in our buffer, stay in THAWING state,
- * and reschedule ourself.
- */
- queue_toplevel_callback(handle_socket_unfreeze, hs);
- } else {
- /*
- * Otherwise, we've successfully thawed!
- */
- hs->frozen = UNFROZEN;
- handle_unthrottle(hs->recv_h, 0);
- }
-}
-
-static void sk_handle_set_frozen(Socket *s, bool is_frozen)
-{
- HandleSocket *hs = container_of(s, HandleSocket, sock);
-
- if (is_frozen) {
- switch (hs->frozen) {
- case FREEZING:
- case FROZEN:
- return; /* nothing to do */
-
- case THAWING:
- /*
- * We were in the middle of emptying our bufchain, and got
- * frozen again. In that case, winhandl.c is already
- * throttled, so just return to FROZEN state. The toplevel
- * callback will notice and disable itself.
- */
- hs->frozen = FROZEN;
- break;
-
- case UNFROZEN:
- /*
- * The normal case. Go to FREEZING, and expect one more
- * load of data from winhandl if we're unlucky.
- */
- hs->frozen = FREEZING;
- break;
- }
- } else {
- switch (hs->frozen) {
- case UNFROZEN:
- case THAWING:
- return; /* nothing to do */
-
- case FREEZING:
- /*
- * If winhandl didn't send us any data throughout the time
- * we were frozen, then we'll still be in this state and
- * can just unfreeze in the trivial way.
- */
- assert(bufchain_size(&hs->inputdata) == 0);
- hs->frozen = UNFROZEN;
- break;
-
- case FROZEN:
- /*
- * If we have buffered data, go to THAWING and start
- * releasing it in top-level callbacks.
- */
- hs->frozen = THAWING;
- queue_toplevel_callback(handle_socket_unfreeze, hs);
- }
- }
-}
-
-static const char *sk_handle_socket_error(Socket *s)
-{
- HandleSocket *hs = container_of(s, HandleSocket, sock);
- return hs->error;
-}
-
-static SocketPeerInfo *sk_handle_peer_info(Socket *s)
-{
- HandleSocket *hs = container_of(s, HandleSocket, sock);
- ULONG pid;
- static HMODULE kernel32_module;
- DECL_WINDOWS_FUNCTION(static, BOOL, GetNamedPipeClientProcessId,
- (HANDLE, PULONG));
-
- if (!kernel32_module) {
- kernel32_module = load_system32_dll("kernel32.dll");
-#if (defined _MSC_VER && _MSC_VER < 1900) || defined __MINGW32__
- /* For older Visual Studio, and MinGW too (at least as of
- * Ubuntu 16.04), this function isn't available in the header
- * files to type-check. Ditto the toolchain I use for
- * Coveritying the Windows code. */
- GET_WINDOWS_FUNCTION_NO_TYPECHECK(
- kernel32_module, GetNamedPipeClientProcessId);
-#else
- GET_WINDOWS_FUNCTION(
- kernel32_module, GetNamedPipeClientProcessId);
-#endif
- }
-
- /*
- * Of course, not all handles managed by this module will be
- * server ends of named pipes, but if they are, then it's useful
- * to log what we can find out about the client end.
- */
- if (p_GetNamedPipeClientProcessId &&
- p_GetNamedPipeClientProcessId(hs->send_H, &pid)) {
- SocketPeerInfo *pi = snew(SocketPeerInfo);
- pi->addressfamily = ADDRTYPE_LOCAL;
- pi->addr_text = NULL;
- pi->port = -1;
- pi->log_text = dupprintf("process id %lu", (unsigned long)pid);
- return pi;
- }
-
- return NULL;
-}
-
-static const SocketVtable HandleSocket_sockvt = {
- .plug = sk_handle_plug,
- .close = sk_handle_close,
- .write = sk_handle_write,
- .write_oob = sk_handle_write_oob,
- .write_eof = sk_handle_write_eof,
- .set_frozen = sk_handle_set_frozen,
- .socket_error = sk_handle_socket_error,
- .peer_info = sk_handle_peer_info,
-};
-
-Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H,
- Plug *plug, bool overlapped)
-{
- HandleSocket *hs;
- int flags = (overlapped ? HANDLE_FLAG_OVERLAPPED : 0);
-
- hs = snew(HandleSocket);
- hs->sock.vt = &HandleSocket_sockvt;
- hs->plug = plug;
- hs->error = NULL;
- hs->frozen = UNFROZEN;
- bufchain_init(&hs->inputdata);
- psb_init(&hs->psb);
-
- hs->recv_H = recv_H;
- hs->recv_h = handle_input_new(hs->recv_H, handle_gotdata, hs, flags);
- hs->send_H = send_H;
- hs->send_h = handle_output_new(hs->send_H, handle_sentdata, hs, flags);
- hs->stderr_H = stderr_H;
- if (hs->stderr_H)
- hs->stderr_h = handle_input_new(hs->stderr_H, handle_stderr,
- hs, flags);
-
- hs->defer_close = hs->deferred_close = false;
-
- return &hs->sock;
-}
diff --git a/WINDOWS/winmiscs.c b/WINDOWS/winmiscs.c
deleted file mode 100644
index 571a9122..00000000
--- a/WINDOWS/winmiscs.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * winmiscs.c: Windows-specific standalone functions. Has the same
- * relationship to winmisc.c that utils.c does to misc.c, but the
- * corresponding name 'winutils.c' was already taken.
- */
-
-#include "putty.h"
-
-#ifndef NO_SECUREZEROMEMORY
-/*
- * Windows implementation of smemclr (see misc.c) using SecureZeroMemory.
- */
-void smemclr(void *b, size_t n) {
- if (b && n > 0)
- SecureZeroMemory(b, n);
-}
-#endif
-
-#ifdef MINEFIELD
-/*
- * Minefield - a Windows equivalent for Electric Fence
- */
-
-#define PAGESIZE 4096
-
-/*
- * Design:
- *
- * We start by reserving as much virtual address space as Windows
- * will sensibly (or not sensibly) let us have. We flag it all as
- * invalid memory.
- *
- * Any allocation attempt is satisfied by committing one or more
- * pages, with an uncommitted page on either side. The returned
- * memory region is jammed up against the _end_ of the pages.
- *
- * Freeing anything causes instantaneous decommitment of the pages
- * involved, so stale pointers are caught as soon as possible.
- */
-
-static int minefield_initialised = 0;
-static void *minefield_region = NULL;
-static long minefield_size = 0;
-static long minefield_npages = 0;
-static long minefield_curpos = 0;
-static unsigned short *minefield_admin = NULL;
-static void *minefield_pages = NULL;
-
-static void minefield_admin_hide(int hide)
-{
- int access = hide ? PAGE_NOACCESS : PAGE_READWRITE;
- VirtualProtect(minefield_admin, minefield_npages * 2, access, NULL);
-}
-
-static void minefield_init(void)
-{
- int size;
- int admin_size;
- int i;
-
- for (size = 0x40000000; size > 0; size = ((size >> 3) * 7) & ~0xFFF) {
- minefield_region = VirtualAlloc(NULL, size,
- MEM_RESERVE, PAGE_NOACCESS);
- if (minefield_region)
- break;
- }
- minefield_size = size;
-
- /*
- * Firstly, allocate a section of that to be the admin block.
- * We'll need a two-byte field for each page.
- */
- minefield_admin = minefield_region;
- minefield_npages = minefield_size / PAGESIZE;
- admin_size = (minefield_npages * 2 + PAGESIZE - 1) & ~(PAGESIZE - 1);
- minefield_npages = (minefield_size - admin_size) / PAGESIZE;
- minefield_pages = (char *) minefield_region + admin_size;
-
- /*
- * Commit the admin region.
- */
- VirtualAlloc(minefield_admin, minefield_npages * 2,
- MEM_COMMIT, PAGE_READWRITE);
-
- /*
- * Mark all pages as unused (0xFFFF).
- */
- for (i = 0; i < minefield_npages; i++)
- minefield_admin[i] = 0xFFFF;
-
- /*
- * Hide the admin region.
- */
- minefield_admin_hide(1);
-
- minefield_initialised = 1;
-}
-
-static void minefield_bomb(void)
-{
- div(1, *(int *) minefield_pages);
-}
-
-static void *minefield_alloc(int size)
-{
- int npages;
- int pos, lim, region_end, region_start;
- int start;
- int i;
-
- npages = (size + PAGESIZE - 1) / PAGESIZE;
-
- minefield_admin_hide(0);
-
- /*
- * Search from current position until we find a contiguous
- * bunch of npages+2 unused pages.
- */
- pos = minefield_curpos;
- lim = minefield_npages;
- while (1) {
- /* Skip over used pages. */
- while (pos < lim && minefield_admin[pos] != 0xFFFF)
- pos++;
- /* Count unused pages. */
- start = pos;
- while (pos < lim && pos - start < npages + 2 &&
- minefield_admin[pos] == 0xFFFF)
- pos++;
- if (pos - start == npages + 2)
- break;
- /* If we've reached the limit, reset the limit or stop. */
- if (pos >= lim) {
- if (lim == minefield_npages) {
- /* go round and start again at zero */
- lim = minefield_curpos;
- pos = 0;
- } else {
- minefield_admin_hide(1);
- return NULL;
- }
- }
- }
-
- minefield_curpos = pos - 1;
-
- /*
- * We have npages+2 unused pages starting at start. We leave
- * the first and last of these alone and use the rest.
- */
- region_end = (start + npages + 1) * PAGESIZE;
- region_start = region_end - size;
- /* FIXME: could align here if we wanted */
-
- /*
- * Update the admin region.
- */
- for (i = start + 2; i < start + npages + 1; i++)
- minefield_admin[i] = 0xFFFE; /* used but no region starts here */
- minefield_admin[start + 1] = region_start % PAGESIZE;
-
- minefield_admin_hide(1);
-
- VirtualAlloc((char *) minefield_pages + region_start, size,
- MEM_COMMIT, PAGE_READWRITE);
- return (char *) minefield_pages + region_start;
-}
-
-static void minefield_free(void *ptr)
-{
- int region_start, i, j;
-
- minefield_admin_hide(0);
-
- region_start = (char *) ptr - (char *) minefield_pages;
- i = region_start / PAGESIZE;
- if (i < 0 || i >= minefield_npages ||
- minefield_admin[i] != region_start % PAGESIZE)
- minefield_bomb();
- for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++) {
- minefield_admin[j] = 0xFFFF;
- }
-
- VirtualFree(ptr, j * PAGESIZE - region_start, MEM_DECOMMIT);
-
- minefield_admin_hide(1);
-}
-
-static int minefield_get_size(void *ptr)
-{
- int region_start, i, j;
-
- minefield_admin_hide(0);
-
- region_start = (char *) ptr - (char *) minefield_pages;
- i = region_start / PAGESIZE;
- if (i < 0 || i >= minefield_npages ||
- minefield_admin[i] != region_start % PAGESIZE)
- minefield_bomb();
- for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++);
-
- minefield_admin_hide(1);
-
- return j * PAGESIZE - region_start;
-}
-
-void *minefield_c_malloc(size_t size)
-{
- if (!minefield_initialised)
- minefield_init();
- return minefield_alloc(size);
-}
-
-void minefield_c_free(void *p)
-{
- if (!minefield_initialised)
- minefield_init();
- minefield_free(p);
-}
-
-/*
- * realloc _always_ moves the chunk, for rapid detection of code
- * that assumes it won't.
- */
-void *minefield_c_realloc(void *p, size_t size)
-{
- size_t oldsize;
- void *q;
- if (!minefield_initialised)
- minefield_init();
- q = minefield_alloc(size);
- oldsize = minefield_get_size(p);
- memcpy(q, p, (oldsize < size ? oldsize : size));
- minefield_free(p);
- return q;
-}
-
-#endif /* MINEFIELD */
-
-#if defined _MSC_VER && _MSC_VER < 1800
-
-/*
- * Work around lack of strtoumax in older MSVC libraries
- */
-uintmax_t strtoumax(const char *nptr, char **endptr, int base)
-{
- return _strtoui64(nptr, endptr, base);
-}
-
-#endif
-
-#if defined _M_ARM || defined _M_ARM64
-
-bool platform_aes_hw_available(void)
-{
- return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
-}
-
-bool platform_sha256_hw_available(void)
-{
- return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
-}
-
-bool platform_sha1_hw_available(void)
-{
- return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
-}
-
-bool platform_sha512_hw_available(void)
-{
- /* As of 2020-12-24, as far as I can tell from docs.microsoft.com,
- * Windows on Arm does not yet provide a PF_ARM_V8_* flag for the
- * SHA-512 architecture extension. */
- return false;
-}
-
-#endif
-
-bool is_console_handle(HANDLE handle)
-{
- DWORD ignored_output;
- if (GetConsoleMode(handle, &ignored_output))
- return true;
- return false;
-}
diff --git a/WINDOWS/winnohlp.c b/WINDOWS/winnohlp.c
deleted file mode 100644
index 62ddc65c..00000000
--- a/WINDOWS/winnohlp.c
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * nohelp.c: implement the has_embedded_chm() function for
- * applications that have no help file at all, so that misc.c's
- * buildinfo string knows not to talk meaninglessly about whether the
- * nonexistent help file is present.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#include "putty.h"
-
-int has_embedded_chm(void) { return -1; }
diff --git a/WINDOWS/winnpc.c b/WINDOWS/winnpc.c
deleted file mode 100644
index eabfb4bc..00000000
--- a/WINDOWS/winnpc.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Windows support module which deals with being a named-pipe client.
- */
-
-#include <stdio.h>
-#include <assert.h>
-
-#include "tree234.h"
-#include "putty.h"
-#include "network.h"
-#include "proxy.h"
-#include "ssh.h"
-
-#if !defined NO_SECURITY
-
-#include "winsecur.h"
-
-HANDLE connect_to_named_pipe(const char *pipename, char **err)
-{
- HANDLE pipehandle;
- PSID usersid, pipeowner;
- PSECURITY_DESCRIPTOR psd;
-
- assert(strncmp(pipename, "\\\\.\\pipe\\", 9) == 0);
- assert(strchr(pipename + 9, '\\') == NULL);
-
- while (1) {
- pipehandle = CreateFile(pipename, GENERIC_READ | GENERIC_WRITE,
- 0, NULL, OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED, NULL);
-
- if (pipehandle != INVALID_HANDLE_VALUE)
- break;
-
- if (GetLastError() != ERROR_PIPE_BUSY) {
- *err = dupprintf(
- "Unable to open named pipe '%s': %s",
- pipename, win_strerror(GetLastError()));
- return INVALID_HANDLE_VALUE;
- }
-
- /*
- * If we got ERROR_PIPE_BUSY, wait for the server to
- * create a new pipe instance. (Since the server is
- * expected to be winnps.c, which will do that immediately
- * after a previous connection is accepted, that shouldn't
- * take excessively long.)
- */
- if (!WaitNamedPipe(pipename, NMPWAIT_USE_DEFAULT_WAIT)) {
- *err = dupprintf(
- "Error waiting for named pipe '%s': %s",
- pipename, win_strerror(GetLastError()));
- return INVALID_HANDLE_VALUE;
- }
- }
-
- if ((usersid = get_user_sid()) == NULL) {
- CloseHandle(pipehandle);
- *err = dupprintf(
- "Unable to get user SID: %s", win_strerror(GetLastError()));
- return INVALID_HANDLE_VALUE;
- }
-
- if (p_GetSecurityInfo(pipehandle, SE_KERNEL_OBJECT,
- OWNER_SECURITY_INFORMATION,
- &pipeowner, NULL, NULL, NULL,
- &psd) != ERROR_SUCCESS) {
- CloseHandle(pipehandle);
- *err = dupprintf(
- "Unable to get named pipe security information: %s",
- win_strerror(GetLastError()));
- return INVALID_HANDLE_VALUE;
- }
-
- if (!EqualSid(pipeowner, usersid)) {
- CloseHandle(pipehandle);
- LocalFree(psd);
- *err = dupprintf(
- "Owner of named pipe '%s' is not us", pipename);
- return INVALID_HANDLE_VALUE;
- }
-
- LocalFree(psd);
-
- return pipehandle;
-}
-
-Socket *new_named_pipe_client(const char *pipename, Plug *plug)
-{
- char *err = NULL;
- HANDLE pipehandle = connect_to_named_pipe(pipename, &err);
- if (pipehandle == INVALID_HANDLE_VALUE)
- return new_error_socket_consume_string(plug, err);
- else
- return make_handle_socket(pipehandle, pipehandle, NULL, plug, true);
-}
-
-#endif /* !defined NO_SECURITY */
diff --git a/WINDOWS/winnps.c b/WINDOWS/winnps.c
deleted file mode 100644
index 1757cdbb..00000000
--- a/WINDOWS/winnps.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Windows support module which deals with being a named-pipe server.
- */
-
-#include <stdio.h>
-#include <assert.h>
-
-#include "tree234.h"
-#include "putty.h"
-#include "network.h"
-#include "proxy.h"
-#include "ssh.h"
-
-#if !defined NO_SECURITY
-
-#include "winsecur.h"
-
-typedef struct NamedPipeServerSocket {
- /* Parameters for (repeated) creation of named pipe objects */
- PSECURITY_DESCRIPTOR psd;
- PACL acl;
- char *pipename;
-
- /* The current named pipe object + attempt to connect to it */
- HANDLE pipehandle;
- OVERLAPPED connect_ovl;
- struct handle *callback_handle; /* winhandl.c's reference */
-
- /* PuTTY Socket machinery */
- Plug *plug;
- char *error;
-
- Socket sock;
-} NamedPipeServerSocket;
-
-static Plug *sk_namedpipeserver_plug(Socket *s, Plug *p)
-{
- NamedPipeServerSocket *ps = container_of(s, NamedPipeServerSocket, sock);
- Plug *ret = ps->plug;
- if (p)
- ps->plug = p;
- return ret;
-}
-
-static void sk_namedpipeserver_close(Socket *s)
-{
- NamedPipeServerSocket *ps = container_of(s, NamedPipeServerSocket, sock);
-
- if (ps->callback_handle)
- handle_free(ps->callback_handle);
- CloseHandle(ps->pipehandle);
- CloseHandle(ps->connect_ovl.hEvent);
- sfree(ps->error);
- sfree(ps->pipename);
- if (ps->acl)
- LocalFree(ps->acl);
- if (ps->psd)
- LocalFree(ps->psd);
- sfree(ps);
-}
-
-static const char *sk_namedpipeserver_socket_error(Socket *s)
-{
- NamedPipeServerSocket *ps = container_of(s, NamedPipeServerSocket, sock);
- return ps->error;
-}
-
-static SocketPeerInfo *sk_namedpipeserver_peer_info(Socket *s)
-{
- return NULL;
-}
-
-static bool create_named_pipe(NamedPipeServerSocket *ps, bool first_instance)
-{
- SECURITY_ATTRIBUTES sa;
-
- memset(&sa, 0, sizeof(sa));
- sa.nLength = sizeof(sa);
- sa.lpSecurityDescriptor = ps->psd;
- sa.bInheritHandle = false;
-
- ps->pipehandle = CreateNamedPipe
- (/* lpName */
- ps->pipename,
-
- /* dwOpenMode */
- PIPE_ACCESS_DUPLEX |
- FILE_FLAG_OVERLAPPED |
- (first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0),
-
- /* dwPipeMode */
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT
-#ifdef PIPE_REJECT_REMOTE_CLIENTS
- | PIPE_REJECT_REMOTE_CLIENTS
-#endif
- ,
-
- /* nMaxInstances */
- PIPE_UNLIMITED_INSTANCES,
-
- /* nOutBufferSize, nInBufferSize */
- 4096, 4096, /* FIXME: think harder about buffer sizes? */
-
- /* nDefaultTimeOut */
- 0 /* default timeout */,
-
- /* lpSecurityAttributes */
- &sa);
-
- return ps->pipehandle != INVALID_HANDLE_VALUE;
-}
-
-static Socket *named_pipe_accept(accept_ctx_t ctx, Plug *plug)
-{
- HANDLE conn = (HANDLE)ctx.p;
-
- return make_handle_socket(conn, conn, NULL, plug, true);
-}
-
-static void named_pipe_accept_loop(NamedPipeServerSocket *ps,
- bool got_one_already)
-{
- while (1) {
- int error;
- char *errmsg;
-
- if (got_one_already) {
- /* If we were called with a connection already waiting,
- * skip this step. */
- got_one_already = false;
- error = 0;
- } else {
- /*
- * Call ConnectNamedPipe, which might succeed or might
- * tell us that an overlapped operation is in progress and
- * we should wait for our event object.
- */
- if (ConnectNamedPipe(ps->pipehandle, &ps->connect_ovl))
- error = 0;
- else
- error = GetLastError();
-
- if (error == ERROR_IO_PENDING)
- return;
- }
-
- if (error == 0 || error == ERROR_PIPE_CONNECTED) {
- /*
- * We've successfully retrieved an incoming connection, so
- * ps->pipehandle now refers to that connection. So
- * convert that handle into a separate connection-type
- * Socket, and create a fresh one to be the new listening
- * pipe.
- */
- HANDLE conn = ps->pipehandle;
- accept_ctx_t actx;
-
- actx.p = (void *)conn;
- if (plug_accepting(ps->plug, named_pipe_accept, actx)) {
- /*
- * If the plug didn't want the connection, might as
- * well close this handle.
- */
- CloseHandle(conn);
- }
-
- if (!create_named_pipe(ps, false)) {
- error = GetLastError();
- } else {
- /*
- * Go round again to see if more connections can be
- * got, or to begin waiting on the event object.
- */
- continue;
- }
- }
-
- errmsg = dupprintf("Error while listening to named pipe: %s",
- win_strerror(error));
- plug_log(ps->plug, 1, sk_namedpipe_addr(ps->pipename), 0,
- errmsg, error);
- sfree(errmsg);
- break;
- }
-}
-
-static void named_pipe_connect_callback(void *vps)
-{
- NamedPipeServerSocket *ps = (NamedPipeServerSocket *)vps;
- named_pipe_accept_loop(ps, true);
-}
-
-/*
- * This socket type is only used for listening, so it should never
- * be asked to write or set_frozen.
- */
-static const SocketVtable NamedPipeServerSocket_sockvt = {
- .plug = sk_namedpipeserver_plug,
- .close = sk_namedpipeserver_close,
- .socket_error = sk_namedpipeserver_socket_error,
- .peer_info = sk_namedpipeserver_peer_info,
-};
-
-Socket *new_named_pipe_listener(const char *pipename, Plug *plug)
-{
- NamedPipeServerSocket *ret = snew(NamedPipeServerSocket);
- ret->sock.vt = &NamedPipeServerSocket_sockvt;
- ret->plug = plug;
- ret->error = NULL;
- ret->psd = NULL;
- ret->pipename = dupstr(pipename);
- ret->acl = NULL;
- ret->callback_handle = NULL;
-
- assert(strncmp(pipename, "\\\\.\\pipe\\", 9) == 0);
- assert(strchr(pipename + 9, '\\') == NULL);
-
- if (!make_private_security_descriptor(GENERIC_READ | GENERIC_WRITE,
- &ret->psd, &ret->acl, &ret->error)) {
- goto cleanup;
- }
-
- if (!create_named_pipe(ret, true)) {
- ret->error = dupprintf("unable to create named pipe '%s': %s",
- pipename, win_strerror(GetLastError()));
- goto cleanup;
- }
-
- memset(&ret->connect_ovl, 0, sizeof(ret->connect_ovl));
- ret->connect_ovl.hEvent = CreateEvent(NULL, true, false, NULL);
- ret->callback_handle =
- handle_add_foreign_event(ret->connect_ovl.hEvent,
- named_pipe_connect_callback, ret);
- named_pipe_accept_loop(ret, false);
-
- cleanup:
- return &ret->sock;
-}
-
-#endif /* !defined NO_SECURITY */
diff --git a/WINDOWS/winseat.h b/WINDOWS/winseat.h
deleted file mode 100644
index c6b5fa96..00000000
--- a/WINDOWS/winseat.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Small implementation of Seat and LogPolicy shared between window.c
- * and windlg.c.
- */
-
-typedef struct WinGuiSeat WinGuiSeat;
-
-struct WinGuiSeat {
- HWND term_hwnd;
- Seat seat;
- LogPolicy logpolicy;
-};
-
-extern const LogPolicyVtable win_gui_logpolicy_vt; /* in windlg.c */
diff --git a/WINDOWS/winsecur.c b/WINDOWS/winsecur.c
deleted file mode 100644
index a1164af5..00000000
--- a/WINDOWS/winsecur.c
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * winsecur.c: implementation of winsecur.h.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "putty.h"
-
-#if !defined NO_SECURITY
-
-#include "winsecur.h"
-
-/* Initialised once, then kept around to reuse forever */
-static PSID worldsid, networksid, usersid;
-
-DEF_WINDOWS_FUNCTION(OpenProcessToken);
-DEF_WINDOWS_FUNCTION(GetTokenInformation);
-DEF_WINDOWS_FUNCTION(InitializeSecurityDescriptor);
-DEF_WINDOWS_FUNCTION(SetSecurityDescriptorOwner);
-DEF_WINDOWS_FUNCTION(GetSecurityInfo);
-DEF_WINDOWS_FUNCTION(SetSecurityInfo);
-DEF_WINDOWS_FUNCTION(SetEntriesInAclA);
-
-bool got_advapi(void)
-{
- static bool attempted = false;
- static bool successful;
- static HMODULE advapi;
-
- if (!attempted) {
- attempted = true;
- advapi = load_system32_dll("advapi32.dll");
- successful = advapi &&
- GET_WINDOWS_FUNCTION(advapi, GetSecurityInfo) &&
- GET_WINDOWS_FUNCTION(advapi, SetSecurityInfo) &&
- GET_WINDOWS_FUNCTION(advapi, OpenProcessToken) &&
- GET_WINDOWS_FUNCTION(advapi, GetTokenInformation) &&
- GET_WINDOWS_FUNCTION(advapi, InitializeSecurityDescriptor) &&
- GET_WINDOWS_FUNCTION(advapi, SetSecurityDescriptorOwner) &&
- GET_WINDOWS_FUNCTION(advapi, SetEntriesInAclA);
- }
- return successful;
-}
-
-PSID get_user_sid(void)
-{
- HANDLE proc = NULL, tok = NULL;
- TOKEN_USER *user = NULL;
- DWORD toklen, sidlen;
- PSID sid = NULL, ret = NULL;
-
- if (usersid)
- return usersid;
-
- if (!got_advapi())
- goto cleanup;
-
- if ((proc = OpenProcess(MAXIMUM_ALLOWED, false,
- GetCurrentProcessId())) == NULL)
- goto cleanup;
-
- if (!p_OpenProcessToken(proc, TOKEN_QUERY, &tok))
- goto cleanup;
-
- if (!p_GetTokenInformation(tok, TokenUser, NULL, 0, &toklen) &&
- GetLastError() != ERROR_INSUFFICIENT_BUFFER)
- goto cleanup;
-
- if ((user = (TOKEN_USER *)LocalAlloc(LPTR, toklen)) == NULL)
- goto cleanup;
-
- if (!p_GetTokenInformation(tok, TokenUser, user, toklen, &toklen))
- goto cleanup;
-
- sidlen = GetLengthSid(user->User.Sid);
-
- sid = (PSID)smalloc(sidlen);
-
- if (!CopySid(sidlen, sid, user->User.Sid))
- goto cleanup;
-
- /* Success. Move sid into the return value slot, and null it out
- * to stop the cleanup code freeing it. */
- ret = usersid = sid;
- sid = NULL;
-
- cleanup:
- if (proc != NULL)
- CloseHandle(proc);
- if (tok != NULL)
- CloseHandle(tok);
- if (user != NULL)
- LocalFree(user);
- if (sid != NULL)
- sfree(sid);
-
- return ret;
-}
-
-static bool getsids(char **error)
-{
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmissing-braces"
-#endif
- SID_IDENTIFIER_AUTHORITY world_auth = SECURITY_WORLD_SID_AUTHORITY;
- SID_IDENTIFIER_AUTHORITY nt_auth = SECURITY_NT_AUTHORITY;
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
- bool ret = false;
-
- *error = NULL;
-
- if (!usersid) {
- if ((usersid = get_user_sid()) == NULL) {
- *error = dupprintf("unable to construct SID for current user: %s",
- win_strerror(GetLastError()));
- goto cleanup;
- }
- }
-
- if (!worldsid) {
- if (!AllocateAndInitializeSid(&world_auth, 1, SECURITY_WORLD_RID,
- 0, 0, 0, 0, 0, 0, 0, &worldsid)) {
- *error = dupprintf("unable to construct SID for world: %s",
- win_strerror(GetLastError()));
- goto cleanup;
- }
- }
-
- if (!networksid) {
- if (!AllocateAndInitializeSid(&nt_auth, 1, SECURITY_NETWORK_RID,
- 0, 0, 0, 0, 0, 0, 0, &networksid)) {
- *error = dupprintf("unable to construct SID for "
- "local same-user access only: %s",
- win_strerror(GetLastError()));
- goto cleanup;
- }
- }
-
- ret = true;
-
- cleanup:
- return ret;
-}
-
-
-bool make_private_security_descriptor(DWORD permissions,
- PSECURITY_DESCRIPTOR *psd,
- PACL *acl,
- char **error)
-{
- EXPLICIT_ACCESS ea[3];
- int acl_err;
- bool ret = false;
-
-
- *psd = NULL;
- *acl = NULL;
- *error = NULL;
-
- if (!getsids(error))
- goto cleanup;
-
- memset(ea, 0, sizeof(ea));
- ea[0].grfAccessPermissions = permissions;
- ea[0].grfAccessMode = REVOKE_ACCESS;
- ea[0].grfInheritance = NO_INHERITANCE;
- ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
- ea[0].Trustee.ptstrName = (LPTSTR)worldsid;
- ea[1].grfAccessPermissions = permissions;
- ea[1].grfAccessMode = GRANT_ACCESS;
- ea[1].grfInheritance = NO_INHERITANCE;
- ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
- ea[1].Trustee.ptstrName = (LPTSTR)usersid;
- ea[2].grfAccessPermissions = permissions;
- ea[2].grfAccessMode = REVOKE_ACCESS;
- ea[2].grfInheritance = NO_INHERITANCE;
- ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID;
- ea[2].Trustee.ptstrName = (LPTSTR)networksid;
-
- acl_err = p_SetEntriesInAclA(3, ea, NULL, acl);
- if (acl_err != ERROR_SUCCESS || *acl == NULL) {
- *error = dupprintf("unable to construct ACL: %s",
- win_strerror(acl_err));
- goto cleanup;
- }
-
- *psd = (PSECURITY_DESCRIPTOR)
- LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
- if (!*psd) {
- *error = dupprintf("unable to allocate security descriptor: %s",
- win_strerror(GetLastError()));
- goto cleanup;
- }
-
- if (!InitializeSecurityDescriptor(*psd, SECURITY_DESCRIPTOR_REVISION)) {
- *error = dupprintf("unable to initialise security descriptor: %s",
- win_strerror(GetLastError()));
- goto cleanup;
- }
-
- if (!SetSecurityDescriptorOwner(*psd, usersid, false)) {
- *error = dupprintf("unable to set owner in security descriptor: %s",
- win_strerror(GetLastError()));
- goto cleanup;
- }
-
- if (!SetSecurityDescriptorDacl(*psd, true, *acl, false)) {
- *error = dupprintf("unable to set DACL in security descriptor: %s",
- win_strerror(GetLastError()));
- goto cleanup;
- }
-
- ret = true;
-
- cleanup:
- if (!ret) {
- if (*psd) {
- LocalFree(*psd);
- *psd = NULL;
- }
- if (*acl) {
- LocalFree(*acl);
- *acl = NULL;
- }
- } else {
- sfree(*error);
- *error = NULL;
- }
- return ret;
-}
-
-static bool acl_restricted = false;
-bool restricted_acl(void) { return acl_restricted; }
-
-static bool really_restrict_process_acl(char **error)
-{
- EXPLICIT_ACCESS ea[2];
- int acl_err;
- bool ret = false;
- PACL acl = NULL;
-
- static const DWORD nastyace=WRITE_DAC | WRITE_OWNER |
- PROCESS_CREATE_PROCESS | PROCESS_CREATE_THREAD |
- PROCESS_DUP_HANDLE |
- PROCESS_SET_QUOTA | PROCESS_SET_INFORMATION |
- PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE |
- PROCESS_SUSPEND_RESUME;
-
- if (!getsids(error))
- goto cleanup;
-
- memset(ea, 0, sizeof(ea));
-
- /* Everyone: deny */
- ea[0].grfAccessPermissions = nastyace;
- ea[0].grfAccessMode = DENY_ACCESS;
- ea[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
- ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
- ea[0].Trustee.ptstrName = (LPTSTR)worldsid;
-
- /* User: user ace */
- ea[1].grfAccessPermissions = ~nastyace & 0x1fff;
- ea[1].grfAccessMode = GRANT_ACCESS;
- ea[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
- ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
- ea[1].Trustee.ptstrName = (LPTSTR)usersid;
-
- acl_err = p_SetEntriesInAclA(2, ea, NULL, &acl);
-
- if (acl_err != ERROR_SUCCESS || acl == NULL) {
- *error = dupprintf("unable to construct ACL: %s",
- win_strerror(acl_err));
- goto cleanup;
- }
-
- if (ERROR_SUCCESS != p_SetSecurityInfo
- (GetCurrentProcess(), SE_KERNEL_OBJECT,
- OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
- usersid, NULL, acl, NULL)) {
- *error = dupprintf("Unable to set process ACL: %s",
- win_strerror(GetLastError()));
- goto cleanup;
- }
-
- acl_restricted = true;
- ret=true;
-
- cleanup:
- if (!ret) {
- if (acl) {
- LocalFree(acl);
- acl = NULL;
- }
- }
- return ret;
-}
-#endif /* !defined NO_SECURITY */
-
-/*
- * Lock down our process's ACL, to present an obstacle to malware
- * trying to write into its memory. This can't be a full defence,
- * because well timed malware could attack us before this code runs -
- * even if it was unconditionally run at the very start of main(),
- * which we wouldn't want to do anyway because it turns out in practie
- * that interfering with other processes in this way has significant
- * non-infringing uses on Windows (e.g. screen reader software).
- *
- * If we've been requested to do this and are unsuccessful, bomb out
- * via modalfatalbox rather than continue in a less protected mode.
- *
- * This function is intentionally outside the #ifndef NO_SECURITY that
- * covers the rest of this file, because when PuTTY is compiled
- * without the ability to restrict its ACL, we don't want it to
- * silently pretend to honour the instruction to do so.
- */
-void restrict_process_acl(void)
-{
- char *error = NULL;
- bool ret;
-
-#if !defined NO_SECURITY
- ret = really_restrict_process_acl(&error);
-#else
- ret = false;
- error = dupstr("ACL restrictions not compiled into this binary");
-#endif
- if (!ret)
- modalfatalbox("Could not restrict process ACL: %s", error);
-}
diff --git a/WINDOWS/winsecur.h b/WINDOWS/winsecur.h
deleted file mode 100644
index fdd39d81..00000000
--- a/WINDOWS/winsecur.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * winsecur.h: some miscellaneous security-related helper functions,
- * defined in winsecur.c, that use the advapi32 library. Also
- * centralises the machinery for dynamically loading that library.
- */
-
-#if !defined NO_SECURITY
-
-#include <aclapi.h>
-
-/*
- * Functions loaded from advapi32.dll.
- */
-DECL_WINDOWS_FUNCTION(extern, BOOL, OpenProcessToken,
- (HANDLE, DWORD, PHANDLE));
-DECL_WINDOWS_FUNCTION(extern, BOOL, GetTokenInformation,
- (HANDLE, TOKEN_INFORMATION_CLASS,
- LPVOID, DWORD, PDWORD));
-DECL_WINDOWS_FUNCTION(extern, BOOL, InitializeSecurityDescriptor,
- (PSECURITY_DESCRIPTOR, DWORD));
-DECL_WINDOWS_FUNCTION(extern, BOOL, SetSecurityDescriptorOwner,
- (PSECURITY_DESCRIPTOR, PSID, BOOL));
-DECL_WINDOWS_FUNCTION(extern, DWORD, GetSecurityInfo,
- (HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION,
- PSID *, PSID *, PACL *, PACL *,
- PSECURITY_DESCRIPTOR *));
-DECL_WINDOWS_FUNCTION(extern, DWORD, SetSecurityInfo,
- (HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION,
- PSID, PSID, PACL, PACL));
-DECL_WINDOWS_FUNCTION(extern, DWORD, SetEntriesInAclA,
- (ULONG, PEXPLICIT_ACCESS, PACL, PACL *));
-bool got_advapi(void);
-
-/*
- * Find the SID describing the current user. The return value (if not
- * NULL for some error-related reason) is smalloced.
- */
-PSID get_user_sid(void);
-
-/*
- * Construct a PSECURITY_DESCRIPTOR of the type used for named pipe
- * servers, i.e. allowing access only to the current user id and also
- * only local (i.e. not over SMB) connections.
- *
- * If this function returns true, then 'psd' and 'acl' will have been
- * filled in with memory allocated using LocalAlloc (and hence must be
- * freed later using LocalFree). If it returns false, then instead
- * 'error' has been filled with a dynamically allocated error message.
- */
-bool make_private_security_descriptor(
- DWORD permissions, PSECURITY_DESCRIPTOR *psd, PACL *acl, char **error);
-
-#endif
diff --git a/WINDOWS/winselcli.c b/WINDOWS/winselcli.c
deleted file mode 100644
index f19a0bbe..00000000
--- a/WINDOWS/winselcli.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Implementation of do_select() for winnet.c to use, suitable for use
- * when there's no GUI window to have network activity reported to.
- *
- * It uses WSAEventSelect, where available, to convert network
- * activity into activity on an event object, for integration into an
- * event loop that includes WaitForMultipleObjects.
- *
- * It also maintains a list of currently active sockets, which can be
- * retrieved by a front end that wants to use WinSock's synchronous
- * select() function.
- */
-
-#include "putty.h"
-
-static tree234 *winselcli_sockets;
-
-static int socket_cmp(void *av, void *bv)
-{
- return memcmp(av, bv, sizeof(SOCKET));
-}
-
-HANDLE winselcli_event = INVALID_HANDLE_VALUE;
-
-void winselcli_setup(void)
-{
- if (!winselcli_sockets)
- winselcli_sockets = newtree234(socket_cmp);
-
- if (p_WSAEventSelect && winselcli_event == INVALID_HANDLE_VALUE)
- winselcli_event = CreateEvent(NULL, false, false, NULL);
-}
-
-SOCKET winselcli_unique_socket(void)
-{
- if (!winselcli_sockets)
- return INVALID_SOCKET;
-
- assert(count234(winselcli_sockets) <= 1);
-
- SOCKET *p = index234(winselcli_sockets, 0);
- if (!p)
- return INVALID_SOCKET;
-
- return *p;
-}
-
-const char *do_select(SOCKET skt, bool enable)
-{
- /* Check everything's been set up, for convenience of callers. */
- winselcli_setup();
-
- if (enable) {
- SOCKET *ptr = snew(SOCKET);
- *ptr = skt;
- if (add234(winselcli_sockets, ptr) != ptr)
- sfree(ptr); /* already there */
- } else {
- SOCKET *ptr = del234(winselcli_sockets, &skt);
- if (ptr)
- sfree(ptr);
- }
-
- if (p_WSAEventSelect) {
- int events;
- if (enable) {
- events = (FD_CONNECT | FD_READ | FD_WRITE |
- FD_OOB | FD_CLOSE | FD_ACCEPT);
- } else {
- events = 0;
- }
-
- if (p_WSAEventSelect(skt, winselcli_event, events) == SOCKET_ERROR)
- return winsock_error_string(p_WSAGetLastError());
- }
-
- return NULL;
-}
diff --git a/WINDOWS/winselgui.c b/WINDOWS/winselgui.c
deleted file mode 100644
index 48a15212..00000000
--- a/WINDOWS/winselgui.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Implementation of do_select() for winnet.c to use, that uses
- * WSAAsyncSelect to convert network activity into window messages,
- * for integration into a GUI event loop.
- */
-
-#include "putty.h"
-
-static HWND winsel_hwnd = NULL;
-
-void winselgui_set_hwnd(HWND hwnd)
-{
- winsel_hwnd = hwnd;
-}
-
-void winselgui_clear_hwnd(void)
-{
- winsel_hwnd = NULL;
-}
-
-const char *do_select(SOCKET skt, bool enable)
-{
- int msg, events;
- if (enable) {
- msg = WM_NETEVENT;
- events = (FD_CONNECT | FD_READ | FD_WRITE |
- FD_OOB | FD_CLOSE | FD_ACCEPT);
- } else {
- msg = events = 0;
- }
-
- assert(winsel_hwnd);
-
- if (p_WSAAsyncSelect(skt, winsel_hwnd, msg, events) == SOCKET_ERROR)
- return winsock_error_string(p_WSAGetLastError());
-
- return NULL;
-}
diff --git a/WINDOWS/winshare.c b/WINDOWS/winshare.c
deleted file mode 100644
index f0e409ac..00000000
--- a/WINDOWS/winshare.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Windows implementation of SSH connection-sharing IPC setup.
- */
-
-#include <stdio.h>
-#include <assert.h>
-
-#if !defined NO_SECURITY
-
-#include "tree234.h"
-#include "putty.h"
-#include "network.h"
-#include "proxy.h"
-#include "ssh.h"
-
-#include "wincapi.h"
-#include "winsecur.h"
-
-#define CONNSHARE_PIPE_PREFIX "\\\\.\\pipe\\putty-connshare"
-#define CONNSHARE_MUTEX_PREFIX "Local\\putty-connshare-mutex"
-
-static char *make_name(const char *prefix, const char *name)
-{
- char *username, *retname;
-
- username = get_username();
- retname = dupprintf("%s.%s.%s", prefix, username, name);
- sfree(username);
-
- return retname;
-}
-
-int platform_ssh_share(const char *pi_name, Conf *conf,
- Plug *downplug, Plug *upplug, Socket **sock,
- char **logtext, char **ds_err, char **us_err,
- bool can_upstream, bool can_downstream)
-{
- char *name, *mutexname, *pipename;
- HANDLE mutex;
- Socket *retsock;
- PSECURITY_DESCRIPTOR psd;
- PACL acl;
-
- /*
- * Transform the platform-independent version of the connection
- * identifier into the obfuscated version we'll use for our
- * Windows named pipe and mutex. A side effect of doing this is
- * that it also eliminates any characters illegal in Windows pipe
- * names.
- */
- name = capi_obfuscate_string(pi_name);
- if (!name) {
- *logtext = dupprintf("Unable to call CryptProtectMemory: %s",
- win_strerror(GetLastError()));
- return SHARE_NONE;
- }
-
- /*
- * Make a mutex name out of the connection identifier, and lock it
- * while we decide whether to be upstream or downstream.
- */
- {
- SECURITY_ATTRIBUTES sa;
-
- mutexname = make_name(CONNSHARE_MUTEX_PREFIX, name);
- if (!make_private_security_descriptor(MUTEX_ALL_ACCESS,
- &psd, &acl, logtext)) {
- sfree(mutexname);
- sfree(name);
- return SHARE_NONE;
- }
-
- memset(&sa, 0, sizeof(sa));
- sa.nLength = sizeof(sa);
- sa.lpSecurityDescriptor = psd;
- sa.bInheritHandle = false;
-
- mutex = CreateMutex(&sa, false, mutexname);
-
- if (!mutex) {
- *logtext = dupprintf("CreateMutex(\"%s\") failed: %s",
- mutexname, win_strerror(GetLastError()));
- sfree(mutexname);
- sfree(name);
- LocalFree(psd);
- LocalFree(acl);
- return SHARE_NONE;
- }
-
- sfree(mutexname);
- LocalFree(psd);
- LocalFree(acl);
-
- WaitForSingleObject(mutex, INFINITE);
- }
-
- pipename = make_name(CONNSHARE_PIPE_PREFIX, name);
-
- *logtext = NULL;
-
- if (can_downstream) {
- retsock = new_named_pipe_client(pipename, downplug);
- if (sk_socket_error(retsock) == NULL) {
- sfree(*logtext);
- *logtext = pipename;
- *sock = retsock;
- sfree(name);
- ReleaseMutex(mutex);
- CloseHandle(mutex);
- return SHARE_DOWNSTREAM;
- }
- sfree(*ds_err);
- *ds_err = dupprintf("%s: %s", pipename, sk_socket_error(retsock));
- sk_close(retsock);
- }
-
- if (can_upstream) {
- retsock = new_named_pipe_listener(pipename, upplug);
- if (sk_socket_error(retsock) == NULL) {
- sfree(*logtext);
- *logtext = pipename;
- *sock = retsock;
- sfree(name);
- ReleaseMutex(mutex);
- CloseHandle(mutex);
- return SHARE_UPSTREAM;
- }
- sfree(*us_err);
- *us_err = dupprintf("%s: %s", pipename, sk_socket_error(retsock));
- sk_close(retsock);
- }
-
- /* One of the above clauses ought to have happened. */
- assert(*logtext || *ds_err || *us_err);
-
- sfree(pipename);
- sfree(name);
- ReleaseMutex(mutex);
- CloseHandle(mutex);
- return SHARE_NONE;
-}
-
-void platform_ssh_share_cleanup(const char *name)
-{
-}
-
-#else /* !defined NO_SECURITY */
-
-#include "noshare.c"
-
-#endif /* !defined NO_SECURITY */
diff --git a/WINDOWS/winsocks.c b/WINDOWS/winsocks.c
deleted file mode 100644
index 83ba364c..00000000
--- a/WINDOWS/winsocks.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Main program for Windows psocks.
- */
-
-#include "putty.h"
-#include "ssh.h"
-#include "psocks.h"
-
-static const PsocksPlatform platform = {
- NULL /* open_pipes */,
- NULL /* start_subcommand */,
-};
-
-int main(int argc, char **argv)
-{
- psocks_state *ps = psocks_new(&platform);
- psocks_cmdline(ps, argc, argv);
-
- sk_init();
- winselcli_setup();
- psocks_start(ps);
-
- cli_main_loop(cliloop_null_pre, cliloop_null_post, NULL);
-}