ssh->mainchan->v.v2.remmaxpkt = ssh_pkt_getuint32(ssh);
bufchain_init(&ssh->mainchan->v.v2.outbuffer);
add234(ssh->channels, ssh->mainchan);
+ update_specials_menu(ssh->frontend);
logevent("Opened channel for session");
} else
ssh->mainchan = NULL;
/* Do pre-close processing on the channel. */
switch (c->type) {
case CHAN_MAINSESSION:
- break; /* nothing to see here, move along */
+ ssh->mainchan = NULL;
+ update_specials_menu(ssh->frontend);
+ break;
case CHAN_X11:
if (c->u.x11.s != NULL)
x11_close(c->u.x11.s);
*/
static const struct telnet_special *ssh_get_specials(void *handle)
{
+ static const struct telnet_special ignore_special[] = {
+ {"IGNORE message", TS_NOP},
+ };
+ static const struct telnet_special ssh2_session_specials[] = {
+ {NULL, TS_SEP},
+ {"Break", TS_BRK},
+ /* 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[] = {
+ {NULL, TS_EXITMENU}
+ };
+ static struct telnet_special ssh_specials[lenof(ignore_special) +
+ lenof(ssh2_session_specials) +
+ lenof(specials_end)];
Ssh ssh = (Ssh) handle;
+ int i = 0;
+#define ADD_SPECIALS(name) \
+ do { \
+ assert((i + lenof(name)) <= lenof(ssh_specials)); \
+ memcpy(&ssh_specials[i], name, sizeof name); \
+ i += lenof(name); \
+ } while(0)
if (ssh->version == 1) {
- static const struct telnet_special ssh1_specials[] = {
- {"IGNORE message", TS_NOP},
- {NULL, 0}
- };
- return ssh1_specials;
+ /* Don't bother offering IGNORE if we've decided the remote
+ * won't cope with it, since we wouldn't bother sending it if
+ * asked anyway. */
+ if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE))
+ ADD_SPECIALS(ignore_special);
} else if (ssh->version == 2) {
- static const struct telnet_special ssh2_specials[] = {
- {"Break", TS_BRK},
- {"IGNORE message", TS_NOP},
- {NULL, 0}
- };
- return ssh2_specials;
- } else
+ /* XXX add rekey, when implemented */
+ ADD_SPECIALS(ignore_special);
+ if (ssh->mainchan)
+ ADD_SPECIALS(ssh2_session_specials);
+ } /* else we're not ready yet */
+
+ if (i) {
+ ADD_SPECIALS(specials_end);
+ return ssh_specials;
+ } else {
return NULL;
+ }
+#undef ADD_SPECIALS
}
/*
ssh2_pkt_send(ssh);
}
} 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 */
+ }
}
}