mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-05-10 06:02:10 -05:00
Yet more trunk merges. Jacob's SSH signals stuff, some docs changes,
and stability stuff in ssh.c. [originally from svn r4674]
This commit is contained in:
parent
5db33359a2
commit
f12be80774
@ -1,4 +1,4 @@
|
|||||||
\versionid $Id: config.but,v 1.92.2.2 2004/10/24 13:29:02 simon Exp $
|
\versionid $Id: config.but,v 1.92.2.3 2004/10/24 13:31:55 simon Exp $
|
||||||
|
|
||||||
\C{config} Configuring PuTTY
|
\C{config} Configuring PuTTY
|
||||||
|
|
||||||
@ -1199,11 +1199,22 @@ native keyboard layout is not US or UK.
|
|||||||
|
|
||||||
\cfg{winhelp-topic}{translation.linedraw}
|
\cfg{winhelp-topic}{translation.linedraw}
|
||||||
|
|
||||||
VT100-series terminals allow the server to send control sequences
|
VT100-series terminals allow the server to send control sequences that
|
||||||
that shift temporarily into a separate character set for drawing
|
shift temporarily into a separate character set for drawing simple
|
||||||
lines and boxes. PuTTY has a variety of ways to support this
|
lines and boxes. However, there are a variety of ways in which PuTTY
|
||||||
capability. In general you should probably try lots of options until
|
can attempt to find appropriate characters, and the right one to use
|
||||||
you find one that your particular font supports.
|
depends on the locally configured font. In general you should probably
|
||||||
|
try lots of options until you find one that your particular font
|
||||||
|
supports.
|
||||||
|
|
||||||
|
\b \q{Use Unicode line drawing code points} tries to use the box
|
||||||
|
characters that are present in Unicode. For good Unicode-supporting
|
||||||
|
fonts this is probably the most reliable and functional option.
|
||||||
|
|
||||||
|
\b \q{Poor man's line drawing} assumes that the font \e{cannot}
|
||||||
|
generate the line and box characters at all, so it will use the
|
||||||
|
\c{+}, \c{-} and \c{|} characters to draw approximations to boxes.
|
||||||
|
You should use this option if none of the other options works.
|
||||||
|
|
||||||
\b \q{Font has XWindows encoding} is for use with fonts that have a
|
\b \q{Font has XWindows encoding} is for use with fonts that have a
|
||||||
special encoding, where the lowest 32 character positions (below the
|
special encoding, where the lowest 32 character positions (below the
|
||||||
@ -1220,15 +1231,6 @@ different size depending on which character set you try to use.
|
|||||||
\b \q{Use font in OEM mode only} is more reliable than that, but can
|
\b \q{Use font in OEM mode only} is more reliable than that, but can
|
||||||
miss out other characters from the main character set.
|
miss out other characters from the main character set.
|
||||||
|
|
||||||
\b \q{Poor man's line drawing} assumes that the font \e{cannot}
|
|
||||||
generate the line and box characters at all, so it will use the
|
|
||||||
\c{+}, \c{-} and \c{|} characters to draw approximations to boxes.
|
|
||||||
You should use this option if none of the other options works.
|
|
||||||
|
|
||||||
\b \q{Unicode mode} tries to use the box characters that are present
|
|
||||||
in Unicode. For good Unicode-supporting fonts this is probably the
|
|
||||||
most reliable and functional option.
|
|
||||||
|
|
||||||
\S{config-linedrawpaste} Controlling copy and paste of line drawing
|
\S{config-linedrawpaste} Controlling copy and paste of line drawing
|
||||||
characters
|
characters
|
||||||
|
|
||||||
@ -1248,7 +1250,8 @@ layout in another program, for example.
|
|||||||
|
|
||||||
Note that this option only applies to line-drawing characters which
|
Note that this option only applies to line-drawing characters which
|
||||||
\e{were} printed by using the VT100 mechanism. Line-drawing
|
\e{were} printed by using the VT100 mechanism. Line-drawing
|
||||||
characters displayed using Unicode will paste as Unicode always.
|
characters that were received as Unicode code points will paste as
|
||||||
|
Unicode always.
|
||||||
|
|
||||||
\H{config-selection} The Selection panel
|
\H{config-selection} The Selection panel
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
\versionid $Id: using.but,v 1.33.2.1 2004/10/24 13:21:11 simon Exp $
|
\versionid $Id: using.but,v 1.33.2.2 2004/10/24 13:31:55 simon Exp $
|
||||||
|
|
||||||
\C{using} Using PuTTY
|
\C{using} Using PuTTY
|
||||||
|
|
||||||
@ -175,19 +175,27 @@ PuTTY can also be configured to send this when Ctrl-Z is typed; see
|
|||||||
|
|
||||||
In an SSH connection, the following special commands are available:
|
In an SSH connection, the following special commands are available:
|
||||||
|
|
||||||
\b \I{Break, SSH special command}Break
|
|
||||||
|
|
||||||
\lcont{
|
|
||||||
Optional extension; may not be supported by server. PuTTY requests the
|
|
||||||
server's default break length.
|
|
||||||
}
|
|
||||||
|
|
||||||
\b \I{IGNORE message, SSH special command}\I{No-op, in SSH}IGNORE message
|
\b \I{IGNORE message, SSH special command}\I{No-op, in SSH}IGNORE message
|
||||||
|
|
||||||
\lcont{
|
\lcont{
|
||||||
Should have no effect.
|
Should have no effect.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
\b \I{Break, SSH special command}Break
|
||||||
|
|
||||||
|
\lcont{
|
||||||
|
Only available in SSH-2, and only during a session. Optional
|
||||||
|
extension; may not be supported by server. PuTTY requests the server's
|
||||||
|
default break length.
|
||||||
|
}
|
||||||
|
|
||||||
|
\b \I{Signal, SSH special command}Signals (SIGINT, SIGTERM etc)
|
||||||
|
|
||||||
|
\lcont{
|
||||||
|
Only available in SSH-2, and only during a session. Sends various
|
||||||
|
POSIX signals. Not honoured by all servers.
|
||||||
|
}
|
||||||
|
|
||||||
\S2{using-newsession} Starting new sessions
|
\S2{using-newsession} Starting new sessions
|
||||||
|
|
||||||
PuTTY's system menu provides some shortcut ways to start new
|
PuTTY's system menu provides some shortcut ways to start new
|
||||||
@ -278,15 +286,17 @@ See \k{config-logging} for more details and options.
|
|||||||
\H{using-translation} Altering your \i{character set} configuration
|
\H{using-translation} Altering your \i{character set} configuration
|
||||||
|
|
||||||
If you find that special characters (\i{accented characters}, for
|
If you find that special characters (\i{accented characters}, for
|
||||||
example) are not being displayed correctly in your PuTTY session, it
|
example, or \i{line-drawing characters}) are not being displayed
|
||||||
may be that PuTTY is interpreting the characters sent by the server
|
correctly in your PuTTY session, it may be that PuTTY is interpreting
|
||||||
according to the wrong \e{character set}. There are a lot of
|
the characters sent by the server according to the wrong \e{character
|
||||||
different character sets available, so it's entirely possible for
|
set}. There are a lot of different character sets available, so it's
|
||||||
this to happen.
|
entirely possible for this to happen.
|
||||||
|
|
||||||
If you click \q{Change Settings} and look at the \i{\q{Translation}
|
If you click \q{Change Settings} and look at the \i{\q{Translation}
|
||||||
panel}, you should see a large number of character sets which you
|
panel}, you should see a large number of character sets which you can
|
||||||
can select. Now all you need is to find out which of them you want!
|
select, and other related options. Now all you need is to find out
|
||||||
|
which of them you want! (See \k{config-translation} for more
|
||||||
|
information.)
|
||||||
|
|
||||||
\H{using-x-forwarding} Using \i{X11 forwarding} in SSH
|
\H{using-x-forwarding} Using \i{X11 forwarding} in SSH
|
||||||
|
|
||||||
|
14
putty.h
14
putty.h
@ -129,13 +129,23 @@ struct unicode_data {
|
|||||||
#define LGTYP_PACKETS 3 /* logmode: SSH data packets */
|
#define LGTYP_PACKETS 3 /* logmode: SSH data packets */
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
/* Actual special commands. Originally Telnet, but some codes have
|
||||||
|
* been re-used for similar specials in other protocols. */
|
||||||
TS_AYT, TS_BRK, TS_SYNCH, TS_EC, TS_EL, TS_GA, TS_NOP, TS_ABORT,
|
TS_AYT, TS_BRK, TS_SYNCH, TS_EC, TS_EL, TS_GA, TS_NOP, TS_ABORT,
|
||||||
TS_AO, TS_IP, TS_SUSP, TS_EOR, TS_EOF, TS_LECHO, TS_RECHO, TS_PING,
|
TS_AO, TS_IP, TS_SUSP, TS_EOR, TS_EOF, TS_LECHO, TS_RECHO, TS_PING,
|
||||||
TS_EOL
|
TS_EOL,
|
||||||
|
/* POSIX-style signals. (not Telnet) */
|
||||||
|
TS_SIGABRT, TS_SIGALRM, TS_SIGFPE, TS_SIGHUP, TS_SIGILL,
|
||||||
|
TS_SIGINT, TS_SIGKILL, TS_SIGPIPE, TS_SIGQUIT, TS_SIGSEGV,
|
||||||
|
TS_SIGTERM, TS_SIGUSR1, TS_SIGUSR2,
|
||||||
|
/* Pseudo-specials used for constructing the specials menu. */
|
||||||
|
TS_SEP, /* Separator */
|
||||||
|
TS_SUBMENU, /* Start a new submenu with specified name */
|
||||||
|
TS_EXITMENU /* Exit current submenu or end of specials */
|
||||||
} Telnet_Special;
|
} Telnet_Special;
|
||||||
|
|
||||||
struct telnet_special {
|
struct telnet_special {
|
||||||
const char *name; /* NULL==end, ""==separator */
|
const char *name;
|
||||||
int code;
|
int code;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
223
ssh.c
223
ssh.c
@ -460,7 +460,7 @@ struct ssh_channel {
|
|||||||
struct ssh_agent_channel {
|
struct ssh_agent_channel {
|
||||||
unsigned char *message;
|
unsigned char *message;
|
||||||
unsigned char msglen[4];
|
unsigned char msglen[4];
|
||||||
int lensofar, totallen;
|
unsigned lensofar, totallen;
|
||||||
} a;
|
} a;
|
||||||
struct ssh_x11_channel {
|
struct ssh_x11_channel {
|
||||||
Socket s;
|
Socket s;
|
||||||
@ -524,6 +524,8 @@ static void ssh_throttle_all(Ssh ssh, int enable, int bufsize);
|
|||||||
static void ssh2_set_window(struct ssh_channel *c, unsigned newwin);
|
static void ssh2_set_window(struct ssh_channel *c, unsigned newwin);
|
||||||
static int ssh_sendbuffer(void *handle);
|
static int ssh_sendbuffer(void *handle);
|
||||||
static void ssh_do_close(Ssh ssh);
|
static void ssh_do_close(Ssh ssh);
|
||||||
|
static unsigned long ssh_pkt_getuint32(Ssh ssh);
|
||||||
|
static void ssh_pkt_getstring(Ssh ssh, char **p, int *length);
|
||||||
|
|
||||||
struct rdpkt1_state_tag {
|
struct rdpkt1_state_tag {
|
||||||
long len, pad, biglen, to_read;
|
long len, pad, biglen, to_read;
|
||||||
@ -972,15 +974,14 @@ static int ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ssh->pktin.type == SSH1_MSG_DEBUG) {
|
if (ssh->pktin.type == SSH1_MSG_DEBUG) {
|
||||||
/* log debug message */
|
char *buf, *msg;
|
||||||
char buf[512];
|
int msglen;
|
||||||
int stringlen = GET_32BIT(ssh->pktin.body);
|
|
||||||
strcpy(buf, "Remote debug message: ");
|
ssh_pkt_getstring(ssh, &msg, &msglen);
|
||||||
if (stringlen > 480)
|
buf = dupprintf("Remote debug message: %.*s", msglen, msg);
|
||||||
stringlen = 480;
|
|
||||||
memcpy(buf + 8, ssh->pktin.body + 4, stringlen);
|
|
||||||
buf[8 + stringlen] = '\0';
|
|
||||||
logevent(buf);
|
logevent(buf);
|
||||||
|
sfree(buf);
|
||||||
|
|
||||||
goto next_packet;
|
goto next_packet;
|
||||||
} else if (ssh->pktin.type == SSH1_MSG_IGNORE) {
|
} else if (ssh->pktin.type == SSH1_MSG_IGNORE) {
|
||||||
/* do nothing */
|
/* do nothing */
|
||||||
@ -989,17 +990,12 @@ static int ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
|
|||||||
|
|
||||||
if (ssh->pktin.type == SSH1_MSG_DISCONNECT) {
|
if (ssh->pktin.type == SSH1_MSG_DISCONNECT) {
|
||||||
/* log reason code in disconnect message */
|
/* log reason code in disconnect message */
|
||||||
char buf[256];
|
char *msg;
|
||||||
unsigned msglen = GET_32BIT(ssh->pktin.body);
|
int msglen;
|
||||||
unsigned nowlen;
|
|
||||||
strcpy(buf, "Remote sent disconnect: ");
|
ssh_pkt_getstring(ssh, &msg, &msglen);
|
||||||
nowlen = strlen(buf);
|
|
||||||
if (msglen > sizeof(buf) - nowlen - 1)
|
bombout(("Server sent disconnect message:\n\"%.*s\"", msglen, msg));
|
||||||
msglen = sizeof(buf) - nowlen - 1;
|
|
||||||
memcpy(buf + nowlen, ssh->pktin.body + 4, msglen);
|
|
||||||
buf[nowlen + msglen] = '\0';
|
|
||||||
/* logevent(buf); (this is now done within the bombout macro) */
|
|
||||||
bombout(("Server sent disconnect message:\n\"%s\"", buf+nowlen));
|
|
||||||
crStop(0);
|
crStop(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1168,10 +1164,11 @@ static int ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
|
|||||||
case SSH2_MSG_DISCONNECT:
|
case SSH2_MSG_DISCONNECT:
|
||||||
{
|
{
|
||||||
/* log reason code in disconnect message */
|
/* log reason code in disconnect message */
|
||||||
char *buf;
|
char *buf, *msg;
|
||||||
int nowlen;
|
int nowlen, reason, msglen;
|
||||||
int reason = GET_32BIT(ssh->pktin.data + 6);
|
|
||||||
unsigned msglen = GET_32BIT(ssh->pktin.data + 10);
|
reason = ssh_pkt_getuint32(ssh);
|
||||||
|
ssh_pkt_getstring(ssh, &msg, &msglen);
|
||||||
|
|
||||||
if (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) {
|
if (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) {
|
||||||
buf = dupprintf("Received disconnect message (%s)",
|
buf = dupprintf("Received disconnect message (%s)",
|
||||||
@ -1183,7 +1180,7 @@ static int ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
|
|||||||
logevent(buf);
|
logevent(buf);
|
||||||
sfree(buf);
|
sfree(buf);
|
||||||
buf = dupprintf("Disconnection message text: %n%.*s",
|
buf = dupprintf("Disconnection message text: %n%.*s",
|
||||||
&nowlen, msglen, ssh->pktin.data + 14);
|
&nowlen, msglen, msg);
|
||||||
logevent(buf);
|
logevent(buf);
|
||||||
bombout(("Server sent disconnect message\ntype %d (%s):\n\"%s\"",
|
bombout(("Server sent disconnect message\ntype %d (%s):\n\"%s\"",
|
||||||
reason,
|
reason,
|
||||||
@ -1199,19 +1196,16 @@ static int ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
|
|||||||
case SSH2_MSG_DEBUG:
|
case SSH2_MSG_DEBUG:
|
||||||
{
|
{
|
||||||
/* log the debug message */
|
/* log the debug message */
|
||||||
char buf[512];
|
char *buf, *msg;
|
||||||
/* int display = ssh->pktin.body[6]; */
|
int msglen;
|
||||||
int stringlen = GET_32BIT(ssh->pktin.data+7);
|
|
||||||
int prefix;
|
ssh_pkt_getstring(ssh, &msg, &msglen);
|
||||||
strcpy(buf, "Remote debug message: ");
|
|
||||||
prefix = strlen(buf);
|
buf = dupprintf("Remote debug message: %.*s", msglen, msg);
|
||||||
if (stringlen > (int)(sizeof(buf)-prefix-1))
|
|
||||||
stringlen = sizeof(buf)-prefix-1;
|
|
||||||
memcpy(buf + prefix, ssh->pktin.data + 11, stringlen);
|
|
||||||
buf[prefix + stringlen] = '\0';
|
|
||||||
logevent(buf);
|
logevent(buf);
|
||||||
|
sfree(buf);
|
||||||
}
|
}
|
||||||
goto next_packet; /* FIXME: print the debug message */
|
goto next_packet;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These packets we need do nothing about here.
|
* These packets we need do nothing about here.
|
||||||
@ -5254,7 +5248,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
|
|||||||
ssh2_pkt_addstring_data(ssh, (char *)pub_blob,
|
ssh2_pkt_addstring_data(ssh, (char *)pub_blob,
|
||||||
pub_blob_len);
|
pub_blob_len);
|
||||||
ssh2_pkt_send(ssh);
|
ssh2_pkt_send(ssh);
|
||||||
logevent("Offered public key"); /* FIXME */
|
logevent("Offered public key");
|
||||||
|
|
||||||
crWaitUntilV(ispkt);
|
crWaitUntilV(ispkt);
|
||||||
if (ssh->pktin.type != SSH2_MSG_USERAUTH_PK_OK) {
|
if (ssh->pktin.type != SSH2_MSG_USERAUTH_PK_OK) {
|
||||||
@ -6354,6 +6348,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
|
|||||||
unsigned localid;
|
unsigned localid;
|
||||||
char *type;
|
char *type;
|
||||||
int typelen, want_reply;
|
int typelen, want_reply;
|
||||||
|
int reply = SSH2_MSG_CHANNEL_FAILURE; /* default */
|
||||||
struct ssh_channel *c;
|
struct ssh_channel *c;
|
||||||
|
|
||||||
localid = ssh_pkt_getuint32(ssh);
|
localid = ssh_pkt_getuint32(ssh);
|
||||||
@ -6385,18 +6380,94 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
|
|||||||
* the request type string to see if it's something
|
* the request type string to see if it's something
|
||||||
* we recognise.
|
* we recognise.
|
||||||
*/
|
*/
|
||||||
if (typelen == 11 && !memcmp(type, "exit-status", 11) &&
|
if (c == ssh->mainchan) {
|
||||||
c == ssh->mainchan) {
|
/*
|
||||||
/* We recognise "exit-status" on the primary channel. */
|
* We recognise "exit-status" and "exit-signal" on
|
||||||
char buf[100];
|
* the primary channel.
|
||||||
|
*/
|
||||||
|
if (typelen == 11 &&
|
||||||
|
!memcmp(type, "exit-status", 11)) {
|
||||||
|
|
||||||
ssh->exitcode = ssh_pkt_getuint32(ssh);
|
ssh->exitcode = ssh_pkt_getuint32(ssh);
|
||||||
sprintf(buf, "Server sent command exit status %d",
|
logeventf(ssh, "Server sent command exit status %d",
|
||||||
ssh->exitcode);
|
ssh->exitcode);
|
||||||
logevent(buf);
|
reply = SSH2_MSG_CHANNEL_SUCCESS;
|
||||||
if (want_reply) {
|
|
||||||
ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_SUCCESS);
|
} else if (typelen == 11 &&
|
||||||
ssh2_pkt_adduint32(ssh, c->remoteid);
|
!memcmp(type, "exit-signal", 11)) {
|
||||||
ssh2_pkt_send(ssh);
|
|
||||||
|
int is_plausible = TRUE, is_int = FALSE;
|
||||||
|
char *fmt_sig = "", *fmt_msg = "";
|
||||||
|
char *msg;
|
||||||
|
int msglen = 0, core = FALSE;
|
||||||
|
/* ICK: older versions of OpenSSH (e.g. 3.4p1)
|
||||||
|
* provide an `int' for the signal, despite its
|
||||||
|
* having been a `string' in the drafts since at
|
||||||
|
* least 2001. (Fixed in session.c 1.147.) Try to
|
||||||
|
* infer which we can safely parse it as. */
|
||||||
|
{
|
||||||
|
unsigned char *p = ssh->pktin.body +
|
||||||
|
ssh->pktin.savedpos;
|
||||||
|
long len = ssh->pktin.length - ssh->pktin.savedpos;
|
||||||
|
unsigned long num = GET_32BIT(p); /* what is it? */
|
||||||
|
/* If it's 0, it hardly matters; assume string */
|
||||||
|
if (num == 0) {
|
||||||
|
is_int = FALSE;
|
||||||
|
} else {
|
||||||
|
int maybe_int = FALSE, maybe_str = FALSE;
|
||||||
|
#define CHECK_HYPOTHESIS(offset, result) \
|
||||||
|
do { \
|
||||||
|
long q = offset; \
|
||||||
|
if (q >= 0 && q+4 <= len) { \
|
||||||
|
q = q + 4 + GET_32BIT(p+q); \
|
||||||
|
if (q >= 0 && q+4 <= len && \
|
||||||
|
(q = q + 4 + GET_32BIT(p+q)) && q == len) \
|
||||||
|
result = TRUE; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
CHECK_HYPOTHESIS(4+1, maybe_int);
|
||||||
|
CHECK_HYPOTHESIS(4+num+1, maybe_str);
|
||||||
|
#undef CHECK_HYPOTHESIS
|
||||||
|
if (maybe_int && !maybe_str)
|
||||||
|
is_int = TRUE;
|
||||||
|
else if (!maybe_int && maybe_str)
|
||||||
|
is_int = FALSE;
|
||||||
|
else
|
||||||
|
/* Crikey. Either or neither. Panic. */
|
||||||
|
is_plausible = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_plausible) {
|
||||||
|
if (is_int) {
|
||||||
|
/* Old non-standard OpenSSH. */
|
||||||
|
int signum = ssh_pkt_getuint32(ssh);
|
||||||
|
fmt_sig = dupprintf(" %d", signum);
|
||||||
|
} else {
|
||||||
|
/* As per the drafts. */
|
||||||
|
char *sig;
|
||||||
|
int siglen;
|
||||||
|
ssh_pkt_getstring(ssh, &sig, &siglen);
|
||||||
|
/* Signal name isn't supposed to be blank, but
|
||||||
|
* let's cope gracefully if it is. */
|
||||||
|
if (siglen) {
|
||||||
|
fmt_sig = dupprintf(" \"%.*s\"",
|
||||||
|
siglen, sig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core = ssh2_pkt_getbool(ssh);
|
||||||
|
ssh_pkt_getstring(ssh, &msg, &msglen);
|
||||||
|
if (msglen) {
|
||||||
|
fmt_msg = dupprintf(" (\"%.*s\")", msglen, msg);
|
||||||
|
}
|
||||||
|
/* ignore lang tag */
|
||||||
|
} /* else don't attempt to parse */
|
||||||
|
logeventf(ssh, "Server exited on signal%s%s%s",
|
||||||
|
fmt_sig, core ? " (core dumped)" : "",
|
||||||
|
fmt_msg);
|
||||||
|
if (*fmt_sig) sfree(fmt_sig);
|
||||||
|
if (*fmt_msg) sfree(fmt_msg);
|
||||||
|
reply = SSH2_MSG_CHANNEL_SUCCESS;
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
@ -6405,12 +6476,13 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
|
|||||||
* or respond with CHANNEL_FAILURE, depending
|
* or respond with CHANNEL_FAILURE, depending
|
||||||
* on want_reply.
|
* on want_reply.
|
||||||
*/
|
*/
|
||||||
|
reply = SSH2_MSG_CHANNEL_FAILURE;
|
||||||
|
}
|
||||||
if (want_reply) {
|
if (want_reply) {
|
||||||
ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_FAILURE);
|
ssh2_pkt_init(ssh, reply);
|
||||||
ssh2_pkt_adduint32(ssh, c->remoteid);
|
ssh2_pkt_adduint32(ssh, c->remoteid);
|
||||||
ssh2_pkt_send(ssh);
|
ssh2_pkt_send(ssh);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if (ssh->pktin.type == SSH2_MSG_GLOBAL_REQUEST) {
|
} else if (ssh->pktin.type == SSH2_MSG_GLOBAL_REQUEST) {
|
||||||
char *type;
|
char *type;
|
||||||
int typelen, want_reply;
|
int typelen, want_reply;
|
||||||
@ -6885,12 +6957,25 @@ static const struct telnet_special *ssh_get_specials(void *handle)
|
|||||||
{"IGNORE message", TS_NOP},
|
{"IGNORE message", TS_NOP},
|
||||||
};
|
};
|
||||||
static const struct telnet_special ssh2_session_specials[] = {
|
static const struct telnet_special ssh2_session_specials[] = {
|
||||||
{"", 0},
|
{NULL, TS_SEP},
|
||||||
{"Break", TS_BRK}
|
{"Break", TS_BRK},
|
||||||
/* XXX we should also support signals */
|
/* These are the signal names defined by draft-ietf-secsh-connect-19.
|
||||||
|
* They include all the ISO C signals, but are a subset of the POSIX
|
||||||
|
* required signals. */
|
||||||
|
{"SIGINT (Interrupt)", TS_SIGINT},
|
||||||
|
{"SIGTERM (Terminate)", TS_SIGTERM},
|
||||||
|
{"SIGKILL (Kill)", TS_SIGKILL},
|
||||||
|
{"SIGQUIT (Quit)", TS_SIGQUIT},
|
||||||
|
{"SIGHUP (Hangup)", TS_SIGHUP},
|
||||||
|
{"More signals", TS_SUBMENU},
|
||||||
|
{"SIGABRT", TS_SIGABRT}, {"SIGALRM", TS_SIGALRM},
|
||||||
|
{"SIGFPE", TS_SIGFPE}, {"SIGILL", TS_SIGILL},
|
||||||
|
{"SIGPIPE", TS_SIGPIPE}, {"SIGSEGV", TS_SIGSEGV},
|
||||||
|
{"SIGUSR1", TS_SIGUSR1}, {"SIGUSR2", TS_SIGUSR2},
|
||||||
|
{NULL, TS_EXITMENU}
|
||||||
};
|
};
|
||||||
static const struct telnet_special specials_end[] = {
|
static const struct telnet_special specials_end[] = {
|
||||||
{NULL, 0}
|
{NULL, TS_EXITMENU}
|
||||||
};
|
};
|
||||||
static struct telnet_special ssh_specials[lenof(ignore_special) +
|
static struct telnet_special ssh_specials[lenof(ignore_special) +
|
||||||
lenof(ssh2_session_specials) +
|
lenof(ssh2_session_specials) +
|
||||||
@ -6978,7 +7063,37 @@ static void ssh_special(void *handle, Telnet_Special code)
|
|||||||
ssh2_pkt_send(ssh);
|
ssh2_pkt_send(ssh);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* do nothing */
|
/* Is is a POSIX signal? */
|
||||||
|
char *signame = NULL;
|
||||||
|
if (code == TS_SIGABRT) signame = "ABRT";
|
||||||
|
if (code == TS_SIGALRM) signame = "ALRM";
|
||||||
|
if (code == TS_SIGFPE) signame = "FPE";
|
||||||
|
if (code == TS_SIGHUP) signame = "HUP";
|
||||||
|
if (code == TS_SIGILL) signame = "ILL";
|
||||||
|
if (code == TS_SIGINT) signame = "INT";
|
||||||
|
if (code == TS_SIGKILL) signame = "KILL";
|
||||||
|
if (code == TS_SIGPIPE) signame = "PIPE";
|
||||||
|
if (code == TS_SIGQUIT) signame = "QUIT";
|
||||||
|
if (code == TS_SIGSEGV) signame = "SEGV";
|
||||||
|
if (code == TS_SIGTERM) signame = "TERM";
|
||||||
|
if (code == TS_SIGUSR1) signame = "USR1";
|
||||||
|
if (code == TS_SIGUSR2) signame = "USR2";
|
||||||
|
/* The SSH-2 protocol does in principle support arbitrary named
|
||||||
|
* signals, including signame@domain, but we don't support those. */
|
||||||
|
if (signame) {
|
||||||
|
/* It's a signal. */
|
||||||
|
if (ssh->version == 2 && ssh->mainchan) {
|
||||||
|
ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_REQUEST);
|
||||||
|
ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid);
|
||||||
|
ssh2_pkt_addstring(ssh, "signal");
|
||||||
|
ssh2_pkt_addbool(ssh, 0);
|
||||||
|
ssh2_pkt_addstring(ssh, signame);
|
||||||
|
ssh2_pkt_send(ssh);
|
||||||
|
logeventf(ssh, "Sent signal SIG%s", signame);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Never heard of it. Do nothing */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
134
sshzlib.c
134
sshzlib.c
@ -40,7 +40,25 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#ifdef ZLIB_STANDALONE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This module also makes a handy zlib decoding tool for when
|
||||||
|
* you're picking apart Zip files or PDFs or PNGs. If you compile
|
||||||
|
* it with ZLIB_STANDALONE defined, it builds on its own and
|
||||||
|
* becomes a command-line utility.
|
||||||
|
*
|
||||||
|
* Therefore, here I provide a self-contained implementation of the
|
||||||
|
* macros required from the rest of the PuTTY sources.
|
||||||
|
*/
|
||||||
|
#define snew(type) ( (type *) malloc(sizeof(type)) )
|
||||||
|
#define snewn(n, type) ( (type *) malloc((n) * sizeof(type)) )
|
||||||
|
#define sresize(x, n, type) ( (type *) realloc((x), (n) * sizeof(type)) )
|
||||||
|
#define sfree(x) ( free((x)) )
|
||||||
|
|
||||||
|
#else
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef FALSE
|
#ifndef FALSE
|
||||||
#define FALSE 0
|
#define FALSE 0
|
||||||
@ -1027,13 +1045,14 @@ int zlib_decompress_block(void *handle, unsigned char *block, int len,
|
|||||||
{
|
{
|
||||||
struct zlib_decompress_ctx *dctx = (struct zlib_decompress_ctx *)handle;
|
struct zlib_decompress_ctx *dctx = (struct zlib_decompress_ctx *)handle;
|
||||||
const coderecord *rec;
|
const coderecord *rec;
|
||||||
int code, blktype, rep, dist, nlen;
|
int code, blktype, rep, dist, nlen, header;
|
||||||
static const unsigned char lenlenmap[] = {
|
static const unsigned char lenlenmap[] = {
|
||||||
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
|
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
|
||||||
};
|
};
|
||||||
|
|
||||||
dctx->outblk = NULL;
|
dctx->outblk = snewn(256, unsigned char);
|
||||||
dctx->outsize = dctx->outlen = 0;
|
dctx->outsize = 256;
|
||||||
|
dctx->outlen = 0;
|
||||||
|
|
||||||
while (len > 0 || dctx->nbits > 0) {
|
while (len > 0 || dctx->nbits > 0) {
|
||||||
while (dctx->nbits < 24 && len > 0) {
|
while (dctx->nbits < 24 && len > 0) {
|
||||||
@ -1043,10 +1062,35 @@ int zlib_decompress_block(void *handle, unsigned char *block, int len,
|
|||||||
}
|
}
|
||||||
switch (dctx->state) {
|
switch (dctx->state) {
|
||||||
case START:
|
case START:
|
||||||
/* Expect 16-bit zlib header, which we'll dishonourably ignore. */
|
/* Expect 16-bit zlib header. */
|
||||||
if (dctx->nbits < 16)
|
if (dctx->nbits < 16)
|
||||||
goto finished; /* done all we can */
|
goto finished; /* done all we can */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The header is stored as a big-endian 16-bit integer,
|
||||||
|
* in contrast to the general little-endian policy in
|
||||||
|
* the rest of the format :-(
|
||||||
|
*/
|
||||||
|
header = (((dctx->bits & 0xFF00) >> 8) |
|
||||||
|
((dctx->bits & 0x00FF) << 8));
|
||||||
EATBITS(16);
|
EATBITS(16);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check the header:
|
||||||
|
*
|
||||||
|
* - bits 8-11 should be 1000 (Deflate/RFC1951)
|
||||||
|
* - bits 12-15 should be at most 0111 (window size)
|
||||||
|
* - bit 5 should be zero (no dictionary present)
|
||||||
|
* - we don't care about bits 6-7 (compression rate)
|
||||||
|
* - bits 0-4 should be set up to make the whole thing
|
||||||
|
* a multiple of 31 (checksum).
|
||||||
|
*/
|
||||||
|
if ((header & 0x0F00) != 0x0800 ||
|
||||||
|
(header & 0xF000) > 0x7000 ||
|
||||||
|
(header & 0x0020) != 0x0000 ||
|
||||||
|
(header % 31) != 0)
|
||||||
|
goto decode_error;
|
||||||
|
|
||||||
dctx->state = OUTSIDEBLK;
|
dctx->state = OUTSIDEBLK;
|
||||||
break;
|
break;
|
||||||
case OUTSIDEBLK:
|
case OUTSIDEBLK:
|
||||||
@ -1242,6 +1286,86 @@ int zlib_decompress_block(void *handle, unsigned char *block, int len,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ZLIB_STANDALONE
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
unsigned char buf[16], *outbuf;
|
||||||
|
int ret, outlen;
|
||||||
|
void *handle;
|
||||||
|
int noheader = FALSE, opts = TRUE;
|
||||||
|
char *filename = NULL;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
while (--argc) {
|
||||||
|
char *p = *++argv;
|
||||||
|
|
||||||
|
if (p[0] == '-' && opts) {
|
||||||
|
if (!strcmp(p, "-d"))
|
||||||
|
noheader = TRUE;
|
||||||
|
else if (!strcmp(p, "--"))
|
||||||
|
opts = FALSE; /* next thing is filename */
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "unknown command line option '%s'\n", p);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (!filename) {
|
||||||
|
filename = p;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "can only handle one filename\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle = zlib_decompress_init();
|
||||||
|
|
||||||
|
if (noheader) {
|
||||||
|
/*
|
||||||
|
* Provide missing zlib header if -d was specified.
|
||||||
|
*/
|
||||||
|
zlib_decompress_block(handle, "\x78\x9C", 2, &outbuf, &outlen);
|
||||||
|
assert(outlen == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filename)
|
||||||
|
fp = fopen(filename, "rb");
|
||||||
|
else
|
||||||
|
fp = stdin;
|
||||||
|
|
||||||
|
if (!fp) {
|
||||||
|
assert(filename);
|
||||||
|
fprintf(stderr, "unable to open '%s'\n", filename);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
ret = fread(buf, 1, sizeof(buf), fp);
|
||||||
|
if (ret <= 0)
|
||||||
|
break;
|
||||||
|
zlib_decompress_block(handle, buf, ret, &outbuf, &outlen);
|
||||||
|
if (outbuf) {
|
||||||
|
if (outlen)
|
||||||
|
fwrite(outbuf, 1, outlen, stdout);
|
||||||
|
sfree(outbuf);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "decoding error\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zlib_decompress_cleanup(handle);
|
||||||
|
|
||||||
|
if (filename)
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
const struct ssh_compress ssh_zlib = {
|
const struct ssh_compress ssh_zlib = {
|
||||||
"zlib",
|
"zlib",
|
||||||
zlib_compress_init,
|
zlib_compress_init,
|
||||||
@ -1253,3 +1377,5 @@ const struct ssh_compress ssh_zlib = {
|
|||||||
zlib_disable_compression,
|
zlib_disable_compression,
|
||||||
"zlib (RFC1950)"
|
"zlib (RFC1950)"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
8
telnet.c
8
telnet.c
@ -963,6 +963,8 @@ static void telnet_special(void *handle, Telnet_Special code)
|
|||||||
telnet->bufsize = sk_write(telnet->s, (char *)b, 2);
|
telnet->bufsize = sk_write(telnet->s, (char *)b, 2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break; /* never heard of it */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -976,15 +978,15 @@ static const struct telnet_special *telnet_get_specials(void *handle)
|
|||||||
{"Erase Line", TS_EL},
|
{"Erase Line", TS_EL},
|
||||||
{"Go Ahead", TS_GA},
|
{"Go Ahead", TS_GA},
|
||||||
{"No Operation", TS_NOP},
|
{"No Operation", TS_NOP},
|
||||||
{"", 0},
|
{NULL, TS_SEP},
|
||||||
{"Abort Process", TS_ABORT},
|
{"Abort Process", TS_ABORT},
|
||||||
{"Abort Output", TS_AO},
|
{"Abort Output", TS_AO},
|
||||||
{"Interrupt Process", TS_IP},
|
{"Interrupt Process", TS_IP},
|
||||||
{"Suspend Process", TS_SUSP},
|
{"Suspend Process", TS_SUSP},
|
||||||
{"", 0},
|
{NULL, TS_SEP},
|
||||||
{"End Of Record", TS_EOR},
|
{"End Of Record", TS_EOR},
|
||||||
{"End Of File", TS_EOF},
|
{"End Of File", TS_EOF},
|
||||||
{NULL, 0}
|
{NULL, TS_EXITMENU}
|
||||||
};
|
};
|
||||||
return specials;
|
return specials;
|
||||||
}
|
}
|
||||||
|
41
unix/pterm.c
41
unix/pterm.c
@ -3144,23 +3144,52 @@ void update_specials_menu(void *frontend)
|
|||||||
else
|
else
|
||||||
specials = NULL;
|
specials = NULL;
|
||||||
|
|
||||||
|
/* I believe this disposes of submenus too. */
|
||||||
gtk_container_foreach(GTK_CONTAINER(inst->specialsmenu),
|
gtk_container_foreach(GTK_CONTAINER(inst->specialsmenu),
|
||||||
(GtkCallback)gtk_widget_destroy, NULL);
|
(GtkCallback)gtk_widget_destroy, NULL);
|
||||||
if (specials) {
|
if (specials) {
|
||||||
int i;
|
int i;
|
||||||
GtkWidget *menuitem;
|
GtkWidget *menu = inst->specialsmenu;
|
||||||
for (i = 0; specials[i].name; i++) {
|
/* A lame "stack" for submenus that will do for now. */
|
||||||
if (*specials[i].name) {
|
GtkWidget *saved_menu = NULL;
|
||||||
|
int nesting = 1;
|
||||||
|
for (i = 0; nesting > 0; i++) {
|
||||||
|
GtkWidget *menuitem = NULL;
|
||||||
|
switch (specials[i].code) {
|
||||||
|
case TS_SUBMENU:
|
||||||
|
assert (nesting < 2);
|
||||||
|
saved_menu = menu; /* XXX lame stacking */
|
||||||
|
menu = gtk_menu_new();
|
||||||
|
menuitem = gtk_menu_item_new_with_label(specials[i].name);
|
||||||
|
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
|
||||||
|
gtk_container_add(GTK_CONTAINER(saved_menu), menuitem);
|
||||||
|
gtk_widget_show(menuitem);
|
||||||
|
menuitem = NULL;
|
||||||
|
nesting++;
|
||||||
|
break;
|
||||||
|
case TS_EXITMENU:
|
||||||
|
nesting--;
|
||||||
|
if (nesting) {
|
||||||
|
menu = saved_menu; /* XXX lame stacking */
|
||||||
|
saved_menu = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TS_SEP:
|
||||||
|
menuitem = gtk_menu_item_new();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
menuitem = gtk_menu_item_new_with_label(specials[i].name);
|
menuitem = gtk_menu_item_new_with_label(specials[i].name);
|
||||||
gtk_object_set_data(GTK_OBJECT(menuitem), "user-data",
|
gtk_object_set_data(GTK_OBJECT(menuitem), "user-data",
|
||||||
GINT_TO_POINTER(specials[i].code));
|
GINT_TO_POINTER(specials[i].code));
|
||||||
gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
|
gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
|
||||||
GTK_SIGNAL_FUNC(special_menuitem), inst);
|
GTK_SIGNAL_FUNC(special_menuitem), inst);
|
||||||
} else
|
break;
|
||||||
menuitem = gtk_menu_item_new();
|
}
|
||||||
gtk_container_add(GTK_CONTAINER(inst->specialsmenu), menuitem);
|
if (menuitem) {
|
||||||
|
gtk_container_add(GTK_CONTAINER(menu), menuitem);
|
||||||
gtk_widget_show(menuitem);
|
gtk_widget_show(menuitem);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
gtk_widget_show(inst->specialsitem1);
|
gtk_widget_show(inst->specialsitem1);
|
||||||
gtk_widget_show(inst->specialsitem2);
|
gtk_widget_show(inst->specialsitem2);
|
||||||
} else {
|
} else {
|
||||||
|
47
window.c
47
window.c
@ -111,6 +111,7 @@ static struct unicode_data ucsdata;
|
|||||||
static int session_closed;
|
static int session_closed;
|
||||||
|
|
||||||
static const struct telnet_special *specials;
|
static const struct telnet_special *specials;
|
||||||
|
static int n_specials;
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
HMENU menu;
|
HMENU menu;
|
||||||
@ -915,20 +916,48 @@ void update_specials_menu(void *frontend)
|
|||||||
specials = NULL;
|
specials = NULL;
|
||||||
|
|
||||||
if (specials) {
|
if (specials) {
|
||||||
p = CreateMenu();
|
/* We can't use Windows to provide a stack for submenus, so
|
||||||
for (i = 0; specials[i].name; i++) {
|
* here's a lame "stack" that will do for now. */
|
||||||
|
HMENU saved_menu = NULL;
|
||||||
|
int nesting = 1;
|
||||||
|
p = CreatePopupMenu();
|
||||||
|
for (i = 0; nesting > 0; i++) {
|
||||||
assert(IDM_SPECIAL_MIN + 0x10 * i < IDM_SPECIAL_MAX);
|
assert(IDM_SPECIAL_MIN + 0x10 * i < IDM_SPECIAL_MAX);
|
||||||
if (*specials[i].name)
|
switch (specials[i].code) {
|
||||||
|
case TS_SEP:
|
||||||
|
AppendMenu(p, MF_SEPARATOR, 0, 0);
|
||||||
|
break;
|
||||||
|
case TS_SUBMENU:
|
||||||
|
assert(nesting < 2);
|
||||||
|
nesting++;
|
||||||
|
saved_menu = p; /* XXX lame stacking */
|
||||||
|
p = CreatePopupMenu();
|
||||||
|
AppendMenu(saved_menu, MF_POPUP | MF_ENABLED,
|
||||||
|
(UINT) p, specials[i].name);
|
||||||
|
break;
|
||||||
|
case TS_EXITMENU:
|
||||||
|
nesting--;
|
||||||
|
if (nesting) {
|
||||||
|
p = saved_menu; /* XXX lame stacking */
|
||||||
|
saved_menu = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
AppendMenu(p, MF_ENABLED, IDM_SPECIAL_MIN + 0x10 * i,
|
AppendMenu(p, MF_ENABLED, IDM_SPECIAL_MIN + 0x10 * i,
|
||||||
specials[i].name);
|
specials[i].name);
|
||||||
else
|
break;
|
||||||
AppendMenu(p, MF_SEPARATOR, 0, 0);
|
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
/* Squirrel the highest special. */
|
||||||
|
n_specials = i - 1;
|
||||||
|
} else {
|
||||||
p = NULL;
|
p = NULL;
|
||||||
|
n_specials = 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (j = 0; j < lenof(popup_menus); j++) {
|
for (j = 0; j < lenof(popup_menus); j++) {
|
||||||
if (menu_already_exists) {
|
if (menu_already_exists) {
|
||||||
|
/* XXX does this free up all submenus? */
|
||||||
DeleteMenu(popup_menus[j].menu,
|
DeleteMenu(popup_menus[j].menu,
|
||||||
popup_menus[j].specials_submenu_pos,
|
popup_menus[j].specials_submenu_pos,
|
||||||
MF_BYPOSITION);
|
MF_BYPOSITION);
|
||||||
@ -2087,22 +2116,18 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
|||||||
}
|
}
|
||||||
if (wParam >= IDM_SPECIAL_MIN && wParam <= IDM_SPECIAL_MAX) {
|
if (wParam >= IDM_SPECIAL_MIN && wParam <= IDM_SPECIAL_MAX) {
|
||||||
int i = (wParam - IDM_SPECIAL_MIN) / 0x10;
|
int i = (wParam - IDM_SPECIAL_MIN) / 0x10;
|
||||||
int j;
|
|
||||||
/*
|
/*
|
||||||
* Ensure we haven't been sent a bogus SYSCOMMAND
|
* Ensure we haven't been sent a bogus SYSCOMMAND
|
||||||
* which would cause us to reference invalid memory
|
* which would cause us to reference invalid memory
|
||||||
* and crash. Perhaps I'm just too paranoid here.
|
* and crash. Perhaps I'm just too paranoid here.
|
||||||
*/
|
*/
|
||||||
for (j = 0; j < i; j++)
|
if (i >= n_specials)
|
||||||
if (!specials || !specials[j].name)
|
|
||||||
break;
|
break;
|
||||||
if (j == i) {
|
|
||||||
if (back)
|
if (back)
|
||||||
back->special(backhandle, specials[i].code);
|
back->special(backhandle, specials[i].code);
|
||||||
net_pending_errors();
|
net_pending_errors();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#define X_POS(l) ((int)(short)LOWORD(l))
|
#define X_POS(l) ((int)(short)LOWORD(l))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user