1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-10 01:48:00 +00:00

Rework special-commands system to add an integer argument.

In order to list cross-certifiable host keys in the GUI specials menu,
the SSH backend has been inventing new values on the end of the
Telnet_Special enumeration, starting from the value TS_LOCALSTART.
This is inelegant, and also makes it awkward to break up special
handlers (e.g. to dispatch different specials to different SSH
layers), since if all you know about a special is that it's somewhere
in the TS_LOCALSTART+n space, you can't tell what _general kind_ of
thing it is. Also, if I ever need another open-ended set of specials
in future, I'll have to remember which TS_LOCALSTART+n codes are in
which set.

So here's a revamp that causes every special to take an extra integer
argument. For all previously numbered specials, this argument is
passed as zero and ignored, but there's a new main special code for
SSH host key cross-certification, in which the integer argument is an
index into the backend's list of available keys. TS_LOCALSTART is now
a thing of the past: if I need any other open-ended sets of specials
in future, I can add a new top-level code with a nicely separated
space of arguments.

While I'm at it, I've removed the legacy misnomer 'Telnet_Special'
from the code completely; the enum is now SessionSpecialCode, the
struct containing full details of a menu entry is SessionSpecial, and
the enum values now start SS_ rather than TS_.
This commit is contained in:
Simon Tatham 2018-09-24 09:35:52 +01:00
parent 26f7a2ac72
commit f4fbaa1bd9
19 changed files with 224 additions and 194 deletions

2
defs.h
View File

@ -70,6 +70,8 @@ typedef struct settings_w settings_w;
typedef struct settings_r settings_r;
typedef struct settings_e settings_e;
typedef struct SessionSpecial SessionSpecial;
/* Note indirection: for historical reasons (it used to be closer to
* the OS socket type), the type that most code uses for a socket is
* 'Socket', not 'Socket *'. So an implementation of Socket or Plug

20
ldisc.c
View File

@ -217,7 +217,7 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive)
bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1]));
ldisc->buflen--;
}
backend_special(ldisc->backend, TS_EL);
backend_special(ldisc->backend, SS_EL, 0);
/*
* We don't send IP, SUSP or ABORT if the user has
* configured telnet specials off! This breaks
@ -226,11 +226,11 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive)
if (!ldisc->telnet_keyboard)
goto default_case;
if (c == CTRL('C'))
backend_special(ldisc->backend, TS_IP);
backend_special(ldisc->backend, SS_IP, 0);
if (c == CTRL('Z'))
backend_special(ldisc->backend, TS_SUSP);
backend_special(ldisc->backend, SS_SUSP, 0);
if (c == CTRL('\\'))
backend_special(ldisc->backend, TS_ABORT);
backend_special(ldisc->backend, SS_ABORT, 0);
break;
case CTRL('R'): /* redraw line */
if (ECHOING) {
@ -245,7 +245,7 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive)
break;
case CTRL('D'): /* logout or send */
if (ldisc->buflen == 0) {
backend_special(ldisc->backend, TS_EOF);
backend_special(ldisc->backend, SS_EOF, 0);
} else {
backend_send(ldisc->backend, ldisc->buf, ldisc->buflen);
ldisc->buflen = 0;
@ -288,7 +288,7 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive)
if (ldisc->protocol == PROT_RAW)
backend_send(ldisc->backend, "\r\n", 2);
else if (ldisc->protocol == PROT_TELNET && ldisc->telnet_newline)
backend_special(ldisc->backend, TS_EOL);
backend_special(ldisc->backend, SS_EOL, 0);
else
backend_send(ldisc->backend, "\r", 1);
if (ECHOING)
@ -325,24 +325,24 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, int interactive)
switch (buf[0]) {
case CTRL('M'):
if (ldisc->protocol == PROT_TELNET && ldisc->telnet_newline)
backend_special(ldisc->backend, TS_EOL);
backend_special(ldisc->backend, SS_EOL, 0);
else
backend_send(ldisc->backend, "\r", 1);
break;
case CTRL('?'):
case CTRL('H'):
if (ldisc->telnet_keyboard) {
backend_special(ldisc->backend, TS_EC);
backend_special(ldisc->backend, SS_EC, 0);
break;
}
case CTRL('C'):
if (ldisc->telnet_keyboard) {
backend_special(ldisc->backend, TS_IP);
backend_special(ldisc->backend, SS_IP, 0);
break;
}
case CTRL('Z'):
if (ldisc->telnet_keyboard) {
backend_special(ldisc->backend, TS_SUSP);
backend_special(ldisc->backend, SS_SUSP, 0);
break;
}

View File

@ -1,5 +1,5 @@
/*
* pinger.c: centralised module that deals with sending TS_PING
* pinger.c: centralised module that deals with sending SS_PING
* keepalives, to avoid replicating this code in multiple backends.
*/
@ -19,7 +19,7 @@ static void pinger_timer(void *ctx, unsigned long now)
Pinger pinger = (Pinger)ctx;
if (pinger->pending && now == pinger->next) {
backend_special(pinger->backend, TS_PING);
backend_special(pinger->backend, SS_PING, 0);
pinger->pending = FALSE;
pinger_schedule(pinger);
}

4
pscp.c
View File

@ -293,7 +293,7 @@ static void bump(const char *fmt, ...)
if (backend && backend_connected(backend)) {
char ch;
backend_special(backend, TS_EOF);
backend_special(backend, SS_EOF, 0);
sent_eof = TRUE;
ssh_scp_recv(&ch, 1);
}
@ -2367,7 +2367,7 @@ int psftp_main(int argc, char *argv[])
if (backend && backend_connected(backend)) {
char ch;
backend_special(backend, TS_EOF);
backend_special(backend, SS_EOF, 0);
sent_eof = TRUE;
ssh_scp_recv(&ch, 1);
}

View File

@ -973,7 +973,7 @@ int sftp_cmd_close(struct sftp_command *cmd)
if (backend_connected(backend)) {
char ch;
backend_special(backend, TS_EOF);
backend_special(backend, SS_EOF, 0);
sent_eof = TRUE;
sftp_recvdata(&ch, 1);
}
@ -2355,7 +2355,7 @@ void do_sftp_cleanup()
{
char ch;
if (backend) {
backend_special(backend, TS_EOF);
backend_special(backend, SS_EOF, 0);
sent_eof = TRUE;
sftp_recvdata(&ch, 1);
backend_free(backend);
@ -2965,7 +2965,7 @@ int psftp_main(int argc, char *argv[])
if (backend && backend_connected(backend)) {
char ch;
backend_special(backend, TS_EOF);
backend_special(backend, SS_EOF, 0);
sent_eof = TRUE;
sftp_recvdata(&ch, 1);
}

89
putty.h
View File

@ -172,34 +172,67 @@ struct unicode_data {
#define LGTYP_PACKETS 3 /* logmode: SSH data packets */
#define LGTYP_SSHRAW 4 /* logmode: SSH raw data */
/*
* Enumeration of 'special commands' that can be sent during a
* session, separately from the byte stream of ordinary session data.
*/
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_AO, TS_IP, TS_SUSP, TS_EOR, TS_EOF, TS_LECHO, TS_RECHO, TS_PING,
TS_EOL,
/* Special command for SSH. */
TS_REKEY,
/* 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 */
/* Starting point for protocols to invent special-action codes
* that can't live in this enum at all, e.g. because they change
* with every session.
*
* Of course, this must remain the last value in this
* enumeration. */
TS_LOCALSTART
} Telnet_Special;
/*
* Commands that are generally useful in multiple backends.
*/
SS_BRK, /* serial-line break */
SS_EOF, /* end-of-file on session input */
SS_NOP, /* transmit data with no effect */
SS_PING, /* try to keep the session alive (probably, but not
* necessarily, implemented as SS_NOP) */
struct telnet_special {
/*
* Commands specific to Telnet.
*/
SS_AYT, /* Are You There */
SS_SYNCH, /* Synch */
SS_EC, /* Erase Character */
SS_EL, /* Erase Line */
SS_GA, /* Go Ahead */
SS_ABORT, /* Abort Process */
SS_AO, /* Abort Output */
SS_IP, /* Interrupt Process */
SS_SUSP, /* Suspend Process */
SS_EOR, /* End Of Record */
SS_EOL, /* Telnet end-of-line sequence (CRLF, as opposed to CR
* NUL that escapes a literal CR) */
/*
* Commands specific to SSH.
*/
SS_REKEY, /* trigger an immediate repeat key exchange */
SS_XCERT, /* cross-certify another host key ('arg' indicates which) */
/*
* Send a POSIX-style signal. (Useful in SSH and also pterm.)
*/
SS_SIGABRT, SS_SIGALRM, SS_SIGFPE, SS_SIGHUP, SS_SIGILL,
SS_SIGINT, SS_SIGKILL, SS_SIGPIPE, SS_SIGQUIT, SS_SIGSEGV,
SS_SIGTERM, SS_SIGUSR1, SS_SIGUSR2,
/*
* These aren't really special commands, but they appear in the
* enumeration because the list returned from
* backend_get_specials() will use them to specify the structure
* of the GUI specials menu.
*/
SS_SEP, /* Separator */
SS_SUBMENU, /* Start a new submenu with specified name */
SS_EXITMENU, /* Exit current submenu, or end of entire specials list */
} SessionSpecialCode;
/*
* The structure type returned from backend_get_specials.
*/
struct SessionSpecial {
const char *name;
int code;
SessionSpecialCode code;
int arg;
};
typedef enum {
@ -457,8 +490,8 @@ struct Backend_vtable {
/* sendbuffer() does the same thing but without attempting a send */
int (*sendbuffer) (Backend *be);
void (*size) (Backend *be, int width, int height);
void (*special) (Backend *be, Telnet_Special code);
const struct telnet_special *(*get_specials) (Backend *be);
void (*special) (Backend *be, SessionSpecialCode code, int arg);
const SessionSpecial *(*get_specials) (Backend *be);
int (*connected) (Backend *be);
int (*exitcode) (Backend *be);
/* If back->sendok() returns FALSE, the backend doesn't currently
@ -488,7 +521,7 @@ struct Backend_vtable {
#define backend_send(be, buf, len) ((be)->vt->send(be, buf, len))
#define backend_sendbuffer(be) ((be)->vt->sendbuffer(be))
#define backend_size(be, w, h) ((be)->vt->size(be, w, h))
#define backend_special(be, code) ((be)->vt->special(be, code))
#define backend_special(be, code, arg) ((be)->vt->special(be, code, arg))
#define backend_get_specials(be) ((be)->vt->get_specials(be))
#define backend_connected(be) ((be)->vt->connected(be))
#define backend_exitcode(be) ((be)->vt->exitcode(be))

6
raw.c
View File

@ -231,10 +231,10 @@ static void raw_size(Backend *be, int width, int height)
/*
* Send raw special codes. We only handle outgoing EOF here.
*/
static void raw_special(Backend *be, Telnet_Special code)
static void raw_special(Backend *be, SessionSpecialCode code, int arg)
{
Raw raw = FROMFIELD(be, struct raw_backend_data, backend);
if (code == TS_EOF && raw->s) {
if (code == SS_EOF && raw->s) {
sk_write_eof(raw->s);
raw->sent_socket_eof= TRUE;
raw_check_close(raw);
@ -247,7 +247,7 @@ static void raw_special(Backend *be, Telnet_Special code)
* Return a list of the special codes that make sense in this
* protocol.
*/
static const struct telnet_special *raw_get_specials(Backend *be)
static const SessionSpecial *raw_get_specials(Backend *be)
{
return NULL;
}

View File

@ -328,7 +328,7 @@ static void rlogin_size(Backend *be, int width, int height)
/*
* Send rlogin special codes.
*/
static void rlogin_special(Backend *be, Telnet_Special code)
static void rlogin_special(Backend *be, SessionSpecialCode code, int arg)
{
/* Do nothing! */
return;
@ -338,7 +338,7 @@ static void rlogin_special(Backend *be, Telnet_Special code)
* Return a list of the special codes that make sense in this
* protocol.
*/
static const struct telnet_special *rlogin_get_specials(Backend *be)
static const SessionSpecial *rlogin_get_specials(Backend *be)
{
return NULL;
}

119
ssh.c
View File

@ -313,7 +313,7 @@ static void ssh1_protocol_setup(Ssh ssh);
static void ssh2_protocol_setup(Ssh ssh);
static void ssh2_bare_connection_protocol_setup(Ssh ssh);
static void ssh_size(Backend *be, int width, int height);
static void ssh_special(Backend *be, Telnet_Special);
static void ssh_special(Backend *be, SessionSpecialCode, int arg);
static int ssh2_try_send(struct ssh_channel *c);
static int ssh_send_channel_data(struct ssh_channel *c,
const char *buf, int len);
@ -592,7 +592,7 @@ struct ssh_tag {
/*
* The last list returned from get_specials.
*/
struct telnet_special *specials;
SessionSpecial *specials;
/*
* List of host key algorithms for which we _don't_ have a stored
@ -3243,7 +3243,7 @@ static void do_ssh1_connection(void *vctx)
if (ssh->size_needed)
backend_size(&ssh->backend, ssh->term_width, ssh->term_height);
if (ssh->eof_needed)
backend_special(&ssh->backend, TS_EOF);
backend_special(&ssh->backend, SS_EOF, 0);
if (ssh->ldisc)
ldisc_echoedit_update(ssh->ldisc); /* cause ldisc to notice changes */
@ -8524,7 +8524,7 @@ static void do_ssh2_connection(void *vctx)
if (ssh->size_needed)
backend_size(&ssh->backend, ssh->term_width, ssh->term_height);
if (ssh->eof_needed)
backend_special(&ssh->backend, TS_EOF);
backend_special(&ssh->backend, SS_EOF, 0);
/*
* Transfer data!
@ -9514,40 +9514,40 @@ static void ssh_size(Backend *be, int width, int height)
* Return a list of the special codes that make sense in this
* protocol.
*/
static const struct telnet_special *ssh_get_specials(Backend *be)
static const SessionSpecial *ssh_get_specials(Backend *be)
{
static const struct telnet_special ssh1_ignore_special[] = {
{"IGNORE message", TS_NOP}
static const SessionSpecial ssh1_ignore_special[] = {
{"IGNORE message", SS_NOP}
};
static const struct telnet_special ssh2_ignore_special[] = {
{"IGNORE message", TS_NOP},
static const SessionSpecial ssh2_ignore_special[] = {
{"IGNORE message", SS_NOP},
};
static const struct telnet_special ssh2_rekey_special[] = {
{"Repeat key exchange", TS_REKEY},
static const SessionSpecial ssh2_rekey_special[] = {
{"Repeat key exchange", SS_REKEY},
};
static const struct telnet_special ssh2_session_specials[] = {
{NULL, TS_SEP},
{"Break", TS_BRK},
static const SessionSpecial ssh2_session_specials[] = {
{NULL, SS_SEP},
{"Break", SS_BRK},
/* These are the signal names defined by RFC 4254.
* 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}
{"SIGINT (Interrupt)", SS_SIGINT},
{"SIGTERM (Terminate)", SS_SIGTERM},
{"SIGKILL (Kill)", SS_SIGKILL},
{"SIGQUIT (Quit)", SS_SIGQUIT},
{"SIGHUP (Hangup)", SS_SIGHUP},
{"More signals", SS_SUBMENU},
{"SIGABRT", SS_SIGABRT}, {"SIGALRM", SS_SIGALRM},
{"SIGFPE", SS_SIGFPE}, {"SIGILL", SS_SIGILL},
{"SIGPIPE", SS_SIGPIPE}, {"SIGSEGV", SS_SIGSEGV},
{"SIGUSR1", SS_SIGUSR1}, {"SIGUSR2", SS_SIGUSR2},
{NULL, SS_EXITMENU}
};
static const struct telnet_special specials_end[] = {
{NULL, TS_EXITMENU}
static const SessionSpecial specials_end[] = {
{NULL, SS_EXITMENU}
};
struct telnet_special *specials = NULL;
SessionSpecial *specials = NULL;
int nspecials = 0, specialsize = 0;
Ssh ssh = FROMFIELD(be, struct ssh_tag, backend);
@ -9559,9 +9559,9 @@ static const struct telnet_special *ssh_get_specials(Backend *be)
int len = lenof(name); \
if (nspecials + len > specialsize) { \
specialsize = (nspecials + len) * 5 / 4 + 32; \
specials = sresize(specials, specialsize, struct telnet_special); \
specials = sresize(specials, specialsize, SessionSpecial); \
} \
memcpy(specials+nspecials, name, len*sizeof(struct telnet_special)); \
memcpy(specials+nspecials, name, len*sizeof(SessionSpecial)); \
nspecials += len; \
} while (0)
@ -9580,22 +9580,23 @@ static const struct telnet_special *ssh_get_specials(Backend *be)
ADD_SPECIALS(ssh2_session_specials);
if (ssh->n_uncert_hostkeys) {
static const struct telnet_special uncert_start[] = {
{NULL, TS_SEP},
{"Cache new host key type", TS_SUBMENU},
static const SessionSpecial uncert_start[] = {
{NULL, SS_SEP},
{"Cache new host key type", SS_SUBMENU},
};
static const struct telnet_special uncert_end[] = {
{NULL, TS_EXITMENU},
static const SessionSpecial uncert_end[] = {
{NULL, SS_EXITMENU},
};
int i;
ADD_SPECIALS(uncert_start);
for (i = 0; i < ssh->n_uncert_hostkeys; i++) {
struct telnet_special uncert[1];
SessionSpecial uncert[1];
const ssh_keyalg *alg =
hostkey_algs[ssh->uncert_hostkeys[i]].alg;
uncert[0].name = alg->ssh_id;
uncert[0].code = TS_LOCALSTART + ssh->uncert_hostkeys[i];
uncert[0].code = SS_XCERT;
uncert[0].arg = ssh->uncert_hostkeys[i];
ADD_SPECIALS(uncert);
}
ADD_SPECIALS(uncert_end);
@ -9616,22 +9617,22 @@ static const struct telnet_special *ssh_get_specials(Backend *be)
}
/*
* Send special codes. TS_EOF is useful for `plink', so you
* Send special codes. SS_EOF is useful for `plink', so you
* can send an EOF and collect resulting output (e.g. `plink
* hostname sort').
*/
static void ssh_special(Backend *be, Telnet_Special code)
static void ssh_special(Backend *be, SessionSpecialCode code, int arg)
{
Ssh ssh = FROMFIELD(be, struct ssh_tag, backend);
PktOut *pktout;
if (code == TS_EOF) {
if (code == SS_EOF) {
if (ssh->state != SSH_STATE_SESSION) {
/*
* Buffer the EOF in case we are pre-SESSION, so we can
* send it as soon as we reach SESSION.
*/
if (code == TS_EOF)
if (code == SS_EOF)
ssh->eof_needed = TRUE;
return;
}
@ -9643,7 +9644,7 @@ static void ssh_special(Backend *be, Telnet_Special code)
ssh->send_ok = 0; /* now stop trying to read from stdin */
}
logevent("Sent EOF message");
} else if (code == TS_PING || code == TS_NOP) {
} else if (code == SS_PING || code == SS_NOP) {
if (ssh->state == SSH_STATE_CLOSED
|| ssh->state == SSH_STATE_PREPACKET) return;
if (ssh->version == 1) {
@ -9659,15 +9660,15 @@ static void ssh_special(Backend *be, Telnet_Special code)
ssh_pkt_write(ssh, pktout);
}
}
} else if (code == TS_REKEY) {
} else if (code == SS_REKEY) {
if (!ssh->kex_in_progress && !ssh->bare_connection &&
ssh->version == 2) {
ssh->rekey_reason = "at user request";
ssh->rekey_class = RK_NORMAL;
queue_idempotent_callback(&ssh->ssh2_transport_icb);
}
} else if (code >= TS_LOCALSTART) {
ssh->hostkey_alg = hostkey_algs[code - TS_LOCALSTART].alg;
} else if (code == SS_XCERT) {
ssh->hostkey_alg = hostkey_algs[arg].alg;
ssh->cross_certifying = TRUE;
if (!ssh->kex_in_progress && !ssh->bare_connection &&
ssh->version == 2) {
@ -9675,7 +9676,7 @@ static void ssh_special(Backend *be, Telnet_Special code)
ssh->rekey_class = RK_NORMAL;
queue_idempotent_callback(&ssh->ssh2_transport_icb);
}
} else if (code == TS_BRK) {
} else if (code == SS_BRK) {
if (ssh->state == SSH_STATE_CLOSED
|| ssh->state == SSH_STATE_PREPACKET) return;
if (ssh->version == 1) {
@ -9688,19 +9689,19 @@ static void ssh_special(Backend *be, Telnet_Special code)
} else {
/* Is is a POSIX signal? */
const 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";
if (code == SS_SIGABRT) signame = "ABRT";
if (code == SS_SIGALRM) signame = "ALRM";
if (code == SS_SIGFPE) signame = "FPE";
if (code == SS_SIGHUP) signame = "HUP";
if (code == SS_SIGILL) signame = "ILL";
if (code == SS_SIGINT) signame = "INT";
if (code == SS_SIGKILL) signame = "KILL";
if (code == SS_SIGPIPE) signame = "PIPE";
if (code == SS_SIGQUIT) signame = "QUIT";
if (code == SS_SIGSEGV) signame = "SEGV";
if (code == SS_SIGTERM) signame = "TERM";
if (code == SS_SIGUSR1) signame = "USR1";
if (code == SS_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) {

View File

@ -914,7 +914,7 @@ static void telnet_size(Backend *be, int width, int height)
/*
* Send Telnet special codes.
*/
static void telnet_special(Backend *be, Telnet_Special code)
static void telnet_special(Backend *be, SessionSpecialCode code, int arg)
{
Telnet telnet = FROMFIELD(be, struct telnet_tag, backend);
unsigned char b[2];
@ -924,55 +924,55 @@ static void telnet_special(Backend *be, Telnet_Special code)
b[0] = IAC;
switch (code) {
case TS_AYT:
case SS_AYT:
b[1] = AYT;
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_BRK:
case SS_BRK:
b[1] = BREAK;
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_EC:
case SS_EC:
b[1] = EC;
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_EL:
case SS_EL:
b[1] = EL;
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_GA:
case SS_GA:
b[1] = GA;
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_NOP:
case SS_NOP:
b[1] = NOP;
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_ABORT:
case SS_ABORT:
b[1] = ABORT;
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_AO:
case SS_AO:
b[1] = AO;
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_IP:
case SS_IP:
b[1] = IP;
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_SUSP:
case SS_SUSP:
b[1] = SUSP;
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_EOR:
case SS_EOR:
b[1] = EOR;
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_EOF:
case SS_EOF:
b[1] = xEOF;
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_EOL:
case SS_EOL:
/* In BINARY mode, CR-LF becomes just CR -
* and without the NUL suffix too. */
if (telnet->opt_states[o_we_bin.index] == ACTIVE)
@ -980,25 +980,12 @@ static void telnet_special(Backend *be, Telnet_Special code)
else
telnet->bufsize = sk_write(telnet->s, "\r\n", 2);
break;
case TS_SYNCH:
case SS_SYNCH:
b[1] = DM;
telnet->bufsize = sk_write(telnet->s, b, 1);
telnet->bufsize = sk_write_oob(telnet->s, b + 1, 1);
break;
case TS_RECHO:
if (telnet->opt_states[o_echo.index] == INACTIVE ||
telnet->opt_states[o_echo.index] == REALLY_INACTIVE) {
telnet->opt_states[o_echo.index] = REQUESTED;
send_opt(telnet, o_echo.send, o_echo.option);
}
break;
case TS_LECHO:
if (telnet->opt_states[o_echo.index] == ACTIVE) {
telnet->opt_states[o_echo.index] = REQUESTED;
send_opt(telnet, o_echo.nsend, o_echo.option);
}
break;
case TS_PING:
case SS_PING:
if (telnet->opt_states[o_they_sga.index] == ACTIVE) {
b[1] = NOP;
telnet->bufsize = sk_write(telnet->s, b, 2);
@ -1009,25 +996,25 @@ static void telnet_special(Backend *be, Telnet_Special code)
}
}
static const struct telnet_special *telnet_get_specials(Backend *be)
static const SessionSpecial *telnet_get_specials(Backend *be)
{
static const struct telnet_special specials[] = {
{"Are You There", TS_AYT},
{"Break", TS_BRK},
{"Synch", TS_SYNCH},
{"Erase Character", TS_EC},
{"Erase Line", TS_EL},
{"Go Ahead", TS_GA},
{"No Operation", TS_NOP},
{NULL, TS_SEP},
{"Abort Process", TS_ABORT},
{"Abort Output", TS_AO},
{"Interrupt Process", TS_IP},
{"Suspend Process", TS_SUSP},
{NULL, TS_SEP},
{"End Of Record", TS_EOR},
{"End Of File", TS_EOF},
{NULL, TS_EXITMENU}
static const SessionSpecial specials[] = {
{"Are You There", SS_AYT},
{"Break", SS_BRK},
{"Synch", SS_SYNCH},
{"Erase Character", SS_EC},
{"Erase Line", SS_EL},
{"Go Ahead", SS_GA},
{"No Operation", SS_NOP},
{NULL, SS_SEP},
{"Abort Process", SS_ABORT},
{"Abort Output", SS_AO},
{"Interrupt Process", SS_IP},
{"Suspend Process", SS_SUSP},
{NULL, SS_SEP},
{"End Of Record", SS_EOR},
{"End Of File", SS_EOF},
{NULL, SS_EXITMENU}
};
return specials;
}

View File

@ -43,8 +43,8 @@ static int null_send(Backend *, const char *, int);
static int loop_send(Backend *, const char *, int);
static int null_sendbuffer(Backend *);
static void null_size(Backend *, int, int);
static void null_special(Backend *, Telnet_Special);
static const struct telnet_special *null_get_specials(Backend *);
static void null_special(Backend *, SessionSpecialCode, int);
static const SessionSpecial *null_get_specials(Backend *);
static int null_connected(Backend *);
static int null_exitcode(Backend *);
static int null_sendok(Backend *);
@ -126,11 +126,11 @@ static void null_size(Backend *be, int width, int height) {
}
static void null_special(Backend *be, Telnet_Special code) {
static void null_special(Backend *be, SessionSpecialCode code, int arg) {
}
static const struct telnet_special *null_get_specials (Backend *be) {
static const SessionSpecial *null_get_specials (Backend *be) {
return NULL;
}

View File

@ -33,6 +33,7 @@
#define g_signal_handler_disconnect gtk_signal_disconnect
#define g_object_get_data gtk_object_get_data
#define g_object_set_data gtk_object_set_data
#define g_object_set_data_full gtk_object_set_data_full
#define g_object_ref_sink gtk_object_sink
#define GDK_GRAB_SUCCESS GrabSuccess

View File

@ -1573,10 +1573,10 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
if (event->keyval == GDK_KEY_Break &&
(event->state & GDK_CONTROL_MASK)) {
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - Ctrl-Break special case, sending TS_BRK\n"));
debug((" - Ctrl-Break special case, sending SS_BRK\n"));
#endif
if (inst->backend)
backend_special(inst->backend, TS_BRK);
backend_special(inst->backend, SS_BRK, 0);
return TRUE;
}
@ -4414,11 +4414,10 @@ void copy_all_menuitem(GtkMenuItem *item, gpointer data)
void special_menuitem(GtkMenuItem *item, gpointer data)
{
Frontend *inst = (Frontend *)data;
int code = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item),
"user-data"));
SessionSpecial *sc = g_object_get_data(G_OBJECT(item), "user-data");
if (inst->backend)
backend_special(inst->backend, code);
backend_special(inst->backend, sc->code, sc->arg);
}
void about_menuitem(GtkMenuItem *item, gpointer data)
@ -4915,9 +4914,11 @@ void set_window_icon(GtkWidget *window, const char *const *const *icon,
#endif
}
static void free_special_cmd(gpointer data) { sfree(data); }
void update_specials_menu(Frontend *inst)
{
const struct telnet_special *specials;
const SessionSpecial *specials;
if (inst->backend)
specials = backend_get_specials(inst->backend);
@ -4936,7 +4937,7 @@ void update_specials_menu(Frontend *inst)
for (i = 0; nesting > 0; i++) {
GtkWidget *menuitem = NULL;
switch (specials[i].code) {
case TS_SUBMENU:
case SS_SUBMENU:
assert (nesting < 2);
saved_menu = menu; /* XXX lame stacking */
menu = gtk_menu_new();
@ -4947,20 +4948,24 @@ void update_specials_menu(Frontend *inst)
menuitem = NULL;
nesting++;
break;
case TS_EXITMENU:
case SS_EXITMENU:
nesting--;
if (nesting) {
menu = saved_menu; /* XXX lame stacking */
saved_menu = NULL;
}
break;
case TS_SEP:
case SS_SEP:
menuitem = gtk_menu_item_new();
break;
default:
menuitem = gtk_menu_item_new_with_label(specials[i].name);
g_object_set_data(G_OBJECT(menuitem), "user-data",
GINT_TO_POINTER(specials[i].code));
{
SessionSpecial *sc = snew(SessionSpecial);
*sc = specials[i]; /* structure copy */
g_object_set_data_full(G_OBJECT(menuitem), "user-data",
sc, free_special_cmd);
}
g_signal_connect(G_OBJECT(menuitem), "activate",
G_CALLBACK(special_menuitem), inst);
break;

View File

@ -464,7 +464,7 @@ static void from_tty(void *vbuf, unsigned len)
break;
case FF00:
if (*p == '\0') {
backend_special(backend, TS_BRK);
backend_special(backend, SS_BRK, 0);
} else {
/*
* Pretend that PARMRK wasn't set. This involves
@ -991,7 +991,7 @@ int main(int argc, char **argv)
perror("stdin: read");
exit(1);
} else if (ret == 0) {
backend_special(backend, TS_EOF);
backend_special(backend, SS_EOF, 0);
sending = FALSE; /* send nothing further after this */
} else {
if (local_tty)

View File

@ -1159,7 +1159,7 @@ static void pty_size(Backend *be, int width, int height)
/*
* Send special codes.
*/
static void pty_special(Backend *be, Telnet_Special code)
static void pty_special(Backend *be, SessionSpecialCode code, int arg)
{
/* Pty pty = FROMFIELD(be, struct pty_tag, backend); */
/* Do nothing! */
@ -1170,7 +1170,7 @@ static void pty_special(Backend *be, Telnet_Special code)
* Return a list of the special codes that make sense in this
* protocol.
*/
static const struct telnet_special *pty_get_specials(Backend *be)
static const SessionSpecial *pty_get_specials(Backend *be)
{
/* Pty pty = FROMFIELD(be, struct pty_tag, backend); */
/*

View File

@ -496,11 +496,11 @@ static void serial_size(Backend *be, int width, int height)
/*
* Send serial special codes.
*/
static void serial_special(Backend *be, Telnet_Special code)
static void serial_special(Backend *be, SessionSpecialCode code, int arg)
{
Serial serial = FROMFIELD(be, struct serial_backend_data, backend);
if (serial->fd >= 0 && code == TS_BRK) {
if (serial->fd >= 0 && code == SS_BRK) {
tcsendbreak(serial->fd, 0);
logevent(serial->frontend, "Sending serial break at user request");
}
@ -512,11 +512,11 @@ static void serial_special(Backend *be, Telnet_Special code)
* Return a list of the special codes that make sense in this
* protocol.
*/
static const struct telnet_special *serial_get_specials(Backend *be)
static const SessionSpecial *serial_get_specials(Backend *be)
{
static const struct telnet_special specials[] = {
{"Break", TS_BRK},
{NULL, TS_EXITMENU}
static const struct SessionSpecial specials[] = {
{"Break", SS_BRK},
{NULL, SS_EXITMENU}
};
return specials;
}

View File

@ -132,7 +132,7 @@ static struct unicode_data ucsdata;
static int session_closed;
static int reconfiguring = FALSE;
static const struct telnet_special *specials = NULL;
static const SessionSpecial *specials = NULL;
static HMENU specials_menu = NULL;
static int n_specials = 0;
@ -965,10 +965,10 @@ void update_specials_menu(Frontend *frontend)
for (i = 0; nesting > 0; i++) {
assert(IDM_SPECIAL_MIN + 0x10 * i < IDM_SPECIAL_MAX);
switch (specials[i].code) {
case TS_SEP:
case SS_SEP:
AppendMenu(new_menu, MF_SEPARATOR, 0, 0);
break;
case TS_SUBMENU:
case SS_SUBMENU:
assert(nesting < 2);
nesting++;
saved_menu = new_menu; /* XXX lame stacking */
@ -976,7 +976,7 @@ void update_specials_menu(Frontend *frontend)
AppendMenu(saved_menu, MF_POPUP | MF_ENABLED,
(UINT_PTR) new_menu, specials[i].name);
break;
case TS_EXITMENU:
case SS_EXITMENU:
nesting--;
if (nesting) {
new_menu = saved_menu; /* XXX lame stacking */
@ -2415,7 +2415,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
if (i >= n_specials)
break;
if (backend)
backend_special(backend, specials[i].code);
backend_special(
backend, specials[i].code, specials[i].arg);
}
}
break;
@ -4406,7 +4407,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
}
if (wParam == VK_CANCEL && shift_state == 2) { /* Ctrl-Break */
if (backend)
backend_special(backend, TS_BRK);
backend_special(backend, SS_BRK, 0);
return 0;
}
if (wParam == VK_PAUSE) { /* Break/Pause */

View File

@ -247,7 +247,7 @@ int stdin_gotdata(struct handle *h, void *data, int len)
if (len > 0) {
return backend_send(backend, data, len);
} else {
backend_special(backend, TS_EOF);
backend_special(backend, SS_EOF, 0);
return 0;
}
} else

View File

@ -348,11 +348,11 @@ static void serbreak_timer(void *ctx, unsigned long now)
/*
* Send serial special codes.
*/
static void serial_special(Backend *be, Telnet_Special code)
static void serial_special(Backend *be, SessionSpecialCode code, int arg)
{
Serial serial = FROMFIELD(be, struct serial_backend_data, backend);
if (serial->port && code == TS_BRK) {
if (serial->port && code == SS_BRK) {
logevent(serial->frontend, "Starting serial break at user request");
SetCommBreak(serial->port);
/*
@ -377,11 +377,11 @@ static void serial_special(Backend *be, Telnet_Special code)
* Return a list of the special codes that make sense in this
* protocol.
*/
static const struct telnet_special *serial_get_specials(Backend *be)
static const SessionSpecial *serial_get_specials(Backend *be)
{
static const struct telnet_special specials[] = {
{"Break", TS_BRK},
{NULL, TS_EXITMENU}
static const SessionSpecial specials[] = {
{"Break", SS_BRK},
{NULL, SS_EXITMENU}
};
return specials;
}