]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
Turned the old `Telnet Command' System-submenu into a more general
authorSimon Tatham <anakin@pobox.com>
Fri, 4 Apr 2003 20:21:05 +0000 (20:21 +0000)
committerSimon Tatham <anakin@pobox.com>
Fri, 4 Apr 2003 20:21:05 +0000 (20:21 +0000)
`Special Command' menu, in which any backend can place its own list
of magical things the user might want to ask the backend to do. In
particular I've implemented the recently proposed "break" extension
in SSH2 using this mechanism.
NB this checkin slightly breaks the Mac build, since it needs to
provide at least a stub form of update_specials_menu().

[originally from svn r3054]

console.c
putty.h
raw.c
rlogin.c
ssh.c
telnet.c
unix/pterm.c
unix/pty.c
unix/uxcons.c
window.c

index b51e7e77126870071d026ce8ef1b6a626b349a80..90b5fa4e3d60ca4f4b9f960c07b2c15445f7a469 100644 (file)
--- a/console.c
+++ b/console.c
@@ -137,6 +137,10 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
     }
 }
 
+void update_specials_menu(void *frontend)
+{
+}
+
 /*
  * Ask whether the selected cipher is acceptable (since it was
  * below the configured 'warn' threshold).
diff --git a/putty.h b/putty.h
index 0717f96b2fc114cd4a9f3ad64c96fadbecea2922..d1c89a257bd5f3bb257034514be5f74e0147259f 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -134,6 +134,11 @@ typedef enum {
     TS_EOL
 } Telnet_Special;
 
+struct telnet_special {
+    const char *name;                 /* NULL==end, ""==separator */
+    int code;
+};
+
 typedef enum {
     MBT_NOTHING,
     MBT_LEFT, MBT_MIDDLE, MBT_RIGHT,   /* `raw' button designations */
@@ -272,6 +277,7 @@ struct backend_tag {
     int (*sendbuffer) (void *handle);
     void (*size) (void *handle, int width, int height);
     void (*special) (void *handle, Telnet_Special code);
+    const struct telnet_special *(*get_specials) (void *handle);
     Socket(*socket) (void *handle);
     int (*exitcode) (void *handle);
     int (*sendok) (void *handle);
@@ -519,6 +525,7 @@ void sys_cursor(void *frontend, int x, int y);
 void request_paste(void *frontend);
 void frontend_keypress(void *frontend);
 void ldisc_update(void *frontend, int echo, int edit);
+void update_specials_menu(void *frontend);
 #define OPTIMISE_IS_SCROLL 1
 
 void set_iconic(void *frontend, int iconic);
diff --git a/raw.c b/raw.c
index 9eb2286c9276e087bde6452c11cfbe3ac2a30f08..10e9ce64cf5ca320e83e4a7550d3d1bf84ca8b55 100644 (file)
--- a/raw.c
+++ b/raw.c
@@ -181,6 +181,15 @@ static void raw_special(void *handle, Telnet_Special code)
     return;
 }
 
+/*
+ * Return a list of the special codes that make sense in this
+ * protocol.
+ */
+static const struct telnet_special *raw_get_specials(void *handle)
+{
+    return NULL;
+}
+
 static Socket raw_socket(void *handle)
 {
     Raw raw = (Raw) handle;
@@ -233,6 +242,7 @@ Backend raw_backend = {
     raw_sendbuffer,
     raw_size,
     raw_special,
+    raw_get_specials,
     raw_socket,
     raw_exitcode,
     raw_sendok,
index 8e73ec91650eac30937af218dffef0f8cf2ad6e9..c12a0802e6f54f422b541a1e04432a9ffdb7ec87 100644 (file)
--- a/rlogin.c
+++ b/rlogin.c
@@ -248,6 +248,15 @@ static void rlogin_special(void *handle, Telnet_Special code)
     return;
 }
 
+/*
+ * Return a list of the special codes that make sense in this
+ * protocol.
+ */
+static const struct telnet_special *rlogin_get_specials(void *handle)
+{
+    return NULL;
+}
+
 static Socket rlogin_socket(void *handle)
 {
     Rlogin rlogin = (Rlogin) handle;
@@ -300,6 +309,7 @@ Backend rlogin_backend = {
     rlogin_sendbuffer,
     rlogin_size,
     rlogin_special,
+    rlogin_get_specials,
     rlogin_socket,
     rlogin_exitcode,
     rlogin_sendok,
diff --git a/ssh.c b/ssh.c
index b2abec47f88d9c5f3892676512804f1e2a67f724..b696e46ab8b3ecda39b8d5f1a434bf4fdeb59560 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -1983,6 +1983,7 @@ static int do_ssh_init(Ssh ssh, unsigned char c)
        ssh->version = 1;
        ssh->s_rdpkt = ssh1_rdpkt;
     }
+    update_specials_menu(ssh->frontend);
     ssh->state = SSH_STATE_BEFORE_SIZE;
 
     sfree(s->vstring);
@@ -5967,6 +5968,7 @@ static char *ssh_init(void *frontend_handle, void **backend_handle,
 
     ssh = snew(struct ssh_tag);
     ssh->cfg = *cfg;                  /* STRUCTURE COPY */
+    ssh->version = 0;                 /* when not ready yet */
     ssh->s = NULL;
     ssh->cipher = NULL;
     ssh->v1_cipher_ctx = NULL;
@@ -6212,6 +6214,31 @@ static void ssh_size(void *handle, 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(void *handle)
+{
+    Ssh ssh = (Ssh) handle;
+
+    if (ssh->version == 1) {
+       static const struct telnet_special ssh1_specials[] = {
+           {"IGNORE message", TS_NOP},
+           {NULL, 0}
+       };
+       return ssh1_specials;
+    } 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
+       return NULL;
+}
+
 /*
  * Send Telnet special codes. TS_EOF is useful for `plink', so you
  * can send an EOF and collect resulting output (e.g. `plink
@@ -6239,7 +6266,7 @@ static void ssh_special(void *handle, Telnet_Special code)
            ssh2_pkt_send(ssh);
        }
        logevent("Sent EOF message");
-    } else if (code == TS_PING) {
+    } else if (code == TS_PING || code == TS_NOP) {
        if (ssh->state == SSH_STATE_CLOSED
            || ssh->state == SSH_STATE_PREPACKET) return;
        if (ssh->version == 1) {
@@ -6250,6 +6277,19 @@ static void ssh_special(void *handle, Telnet_Special code)
            ssh2_pkt_addstring_start(ssh);
            ssh2_pkt_send(ssh);
        }
+    } else if (code == TS_BRK) {
+       if (ssh->state == SSH_STATE_CLOSED
+           || ssh->state == SSH_STATE_PREPACKET) return;
+       if (ssh->version == 1) {
+           logevent("Unable to send BREAK signal in SSH1");
+       } else {
+           ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_REQUEST);
+           ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid);
+           ssh2_pkt_addstring(ssh, "break");
+           ssh2_pkt_addbool(ssh, 0);
+           ssh2_pkt_adduint32(ssh, 0);   /* default break length */
+           ssh2_pkt_send(ssh);
+       }
     } else {
        /* do nothing */
     }
@@ -6390,6 +6430,7 @@ Backend ssh_backend = {
     ssh_sendbuffer,
     ssh_size,
     ssh_special,
+    ssh_get_specials,
     ssh_socket,
     ssh_return_exitcode,
     ssh_sendok,
index 6f6deaea754551ff1c5af92d7791f48ae7cd5c6e..e3fff49f9e3cf94cd3055a88fe227e3b43c1285a 100644 (file)
--- a/telnet.c
+++ b/telnet.c
@@ -955,6 +955,29 @@ static void telnet_special(void *handle, Telnet_Special code)
     }
 }
 
+static const struct telnet_special *telnet_get_specials(void *handle)
+{
+    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},
+       {"", 0},
+       {"Abort Process", TS_ABORT},
+       {"Abort Output", TS_AO},
+       {"Interrupt Process", TS_IP},
+       {"Suspend Process", TS_SUSP},
+       {"", 0},
+       {"End Of Record", TS_EOR},
+       {"End Of File", TS_EOF},
+       {NULL, 0}
+    };
+    return specials;
+}
+
 static Socket telnet_socket(void *handle)
 {
     Telnet telnet = (Telnet) handle;
@@ -1012,6 +1035,7 @@ Backend telnet_backend = {
     telnet_sendbuffer,
     telnet_size,
     telnet_special,
+    telnet_get_specials,
     telnet_socket,
     telnet_exitcode,
     telnet_sendok,
index 00ce217e33f2cd39c28094eb21a234833137c7bd..57c8d0280da321598f3b232577657edd8760a3fe 100644 (file)
@@ -148,6 +148,14 @@ void ldisc_update(void *frontend, int echo, int edit)
      */
 }
 
+void update_specials_menu(void *frontend)
+{
+    /*
+     * When I implement a context menu in pterm, I will need to
+     * support this function properly.
+     */
+}
+
 int askappend(void *frontend, Filename filename)
 {
     /*
index 1c9763a094b4acf6bbfc4e9e5abdfb0a1bbc1eca..dac67364f97b561fea3e786a7c2322ab24b0cf76 100644 (file)
@@ -704,6 +704,21 @@ static void pty_special(void *handle, Telnet_Special code)
     return;
 }
 
+/*
+ * Return a list of the special codes that make sense in this
+ * protocol.
+ */
+static const struct telnet_special *pty_get_specials(void *handle)
+{
+    /*
+     * Hmm. When I get round to having this actually usable, it
+     * might be quite nice to have the ability to deliver a few
+     * well chosen signals to the child process - SIGINT, SIGTERM,
+     * SIGKILL at least.
+     */
+    return NULL;
+}
+
 static Socket pty_socket(void *handle)
 {
     return NULL;                      /* shouldn't ever be needed */
@@ -750,6 +765,7 @@ Backend pty_backend = {
     pty_sendbuffer,
     pty_size,
     pty_special,
+    pty_get_specials,
     pty_socket,
     pty_exitcode,
     pty_sendok,
index 2375a63ea9d7880b8aec03e9fcea9ba4f3260a8b..4877089765e0af017e4bb2ac2ab0a459bd3db595 100644 (file)
@@ -29,6 +29,10 @@ void cleanup_exit(int code)
     exit(code);
 }
 
+void update_specials_menu(void *frontend)
+{
+}
+
 void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
                         char *keystr, char *fingerprint)
 {
index 326d19c9fa1eef221f2986a0e86c7c0860bc95a7..96ce4adbd5b85ee09beb894b7907f79ff52696e8 100644 (file)
--- a/window.c
+++ b/window.c
 #define IDM_RECONF    0x0040
 #define IDM_CLRSB     0x0050
 #define IDM_RESET     0x0060
-#define IDM_TEL_AYT   0x0070
-#define IDM_TEL_BRK   0x0080
-#define IDM_TEL_SYNCH 0x0090
-#define IDM_TEL_EC    0x00a0
-#define IDM_TEL_EL    0x00b0
-#define IDM_TEL_GA    0x00c0
-#define IDM_TEL_NOP   0x00d0
-#define IDM_TEL_ABORT 0x00e0
-#define IDM_TEL_AO    0x00f0
-#define IDM_TEL_IP    0x0100
-#define IDM_TEL_SUSP  0x0110
-#define IDM_TEL_EOR   0x0120
-#define IDM_TEL_EOF   0x0130
 #define IDM_HELP      0x0140
 #define IDM_ABOUT     0x0150
 #define IDM_SAVEDSESS 0x0160
 #define IDM_SESSLGP   0x0250          /* log type printable */
 #define IDM_SESSLGA   0x0260          /* log type all chars */
 #define IDM_SESSLGE   0x0270          /* log end */
+
+#define IDM_SPECIAL_MIN 0x0400
+#define IDM_SPECIAL_MAX 0x0800
+
 #define IDM_SAVED_MIN 0x1000
 #define IDM_SAVED_MAX 0x2000
 
@@ -124,6 +115,9 @@ static void *backhandle;
 static struct unicode_data ucsdata;
 static int session_closed;
 
+static const struct telnet_special *specials;
+static int specials_menu_position;
+
 Config cfg;                           /* exported to windlg.c */
 
 extern struct sesslist sesslist;       /* imported from windlg.c */
@@ -675,32 +669,12 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
      */
     {
        HMENU m = GetSystemMenu(hwnd, FALSE);
-       HMENU p, s;
+       HMENU s;
        int i;
 
        AppendMenu(m, MF_SEPARATOR, 0, 0);
-       if (cfg.protocol == PROT_TELNET) {
-           p = CreateMenu();
-           AppendMenu(p, MF_ENABLED, IDM_TEL_AYT, "Are You There");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_BRK, "Break");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_SYNCH, "Synch");
-           AppendMenu(p, MF_SEPARATOR, 0, 0);
-           AppendMenu(p, MF_ENABLED, IDM_TEL_EC, "Erase Character");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_EL, "Erase Line");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_GA, "Go Ahead");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_NOP, "No Operation");
-           AppendMenu(p, MF_SEPARATOR, 0, 0);
-           AppendMenu(p, MF_ENABLED, IDM_TEL_ABORT, "Abort Process");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_AO, "Abort Output");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_IP, "Interrupt Process");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_SUSP, "Suspend Process");
-           AppendMenu(p, MF_SEPARATOR, 0, 0);
-           AppendMenu(p, MF_ENABLED, IDM_TEL_EOR, "End Of Record");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_EOF, "End Of File");
-           AppendMenu(m, MF_POPUP | MF_ENABLED, (UINT) p,
-                      "Telnet Command");
-           AppendMenu(m, MF_SEPARATOR, 0, 0);
-       }
+       specials_menu_position = GetMenuItemCount(m);
+       debug(("specials_menu_position = %d\n", specials_menu_position));
        AppendMenu(m, MF_ENABLED, IDM_SHOWLOG, "&Event Log");
        AppendMenu(m, MF_SEPARATOR, 0, 0);
        AppendMenu(m, MF_ENABLED, IDM_NEWSESS, "Ne&w Session...");
@@ -727,6 +701,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
        AppendMenu(m, MF_ENABLED, IDM_ABOUT, "&About PuTTY");
     }
 
+    update_specials_menu(NULL);
+
     /*
      * Set up the initial input locale.
      */
@@ -887,6 +863,37 @@ char *do_select(SOCKET skt, int startup)
     return NULL;
 }
 
+/*
+ * Update the Special Commands submenu.
+ */
+void update_specials_menu(void *frontend)
+{
+    HMENU m = GetSystemMenu(hwnd, FALSE);
+    int menu_already_exists = (specials != NULL);
+    int i;
+
+    specials = back->get_specials(backhandle);
+    if (specials) {
+       HMENU p = CreateMenu();
+       for (i = 0; specials[i].name; i++) {
+           assert(IDM_SPECIAL_MIN + 0x10 * i < IDM_SPECIAL_MAX);
+           if (*specials[i].name)
+               AppendMenu(p, MF_ENABLED, IDM_SPECIAL_MIN + 0x10 * i,
+                          specials[i].name);
+           else
+               AppendMenu(p, MF_SEPARATOR, 0, 0);
+       }
+       if (menu_already_exists)
+           DeleteMenu(m, specials_menu_position, MF_BYPOSITION);
+       else
+           InsertMenu(m, specials_menu_position,
+                      MF_BYPOSITION | MF_SEPARATOR, 0, 0);
+       InsertMenu(m, specials_menu_position,
+                  MF_BYPOSITION | MF_POPUP | MF_ENABLED,
+                  (UINT) p, "Special Command");
+    }
+}
+
 /*
  * set or clear the "raw mouse message" mode
  */
@@ -1906,58 +1913,6 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            term_pwron(term);
            ldisc_send(ldisc, NULL, 0, 0);
            break;
-         case IDM_TEL_AYT:
-           back->special(backhandle, TS_AYT);
-           net_pending_errors();
-           break;
-         case IDM_TEL_BRK:
-           back->special(backhandle, TS_BRK);
-           net_pending_errors();
-           break;
-         case IDM_TEL_SYNCH:
-           back->special(backhandle, TS_SYNCH);
-           net_pending_errors();
-           break;
-         case IDM_TEL_EC:
-           back->special(backhandle, TS_EC);
-           net_pending_errors();
-           break;
-         case IDM_TEL_EL:
-           back->special(backhandle, TS_EL);
-           net_pending_errors();
-           break;
-         case IDM_TEL_GA:
-           back->special(backhandle, TS_GA);
-           net_pending_errors();
-           break;
-         case IDM_TEL_NOP:
-           back->special(backhandle, TS_NOP);
-           net_pending_errors();
-           break;
-         case IDM_TEL_ABORT:
-           back->special(backhandle, TS_ABORT);
-           net_pending_errors();
-           break;
-         case IDM_TEL_AO:
-           back->special(backhandle, TS_AO);
-           net_pending_errors();
-           break;
-         case IDM_TEL_IP:
-           back->special(backhandle, TS_IP);
-           net_pending_errors();
-           break;
-         case IDM_TEL_SUSP:
-           back->special(backhandle, TS_SUSP);
-           net_pending_errors();
-           break;
-         case IDM_TEL_EOR:
-           back->special(backhandle, TS_EOR);
-           net_pending_errors();
-           break;
-         case IDM_TEL_EOF:
-           back->special(backhandle, TS_EOF);
-           net_pending_errors();
-           break;
          case IDM_ABOUT:
            showabout(hwnd);
            break;
@@ -1992,6 +1947,22 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            if (wParam >= IDM_SAVED_MIN && wParam <= IDM_SAVED_MAX) {
                SendMessage(hwnd, WM_SYSCOMMAND, IDM_SAVEDSESS, wParam);
            }
+           if (wParam >= IDM_SPECIAL_MIN && wParam <= IDM_SPECIAL_MAX) {
+               int i = (wParam - IDM_SPECIAL_MIN) / 0x10;
+               int j;
+               /*
+                * Ensure we haven't been sent a bogus SYSCOMMAND
+                * which would cause us to reference invalid memory
+                * and crash. Perhaps I'm just too paranoid here.
+                */
+               for (j = 0; j < i; j++)
+                   if (!specials || !specials[j].name)
+                       break;
+               if (j == i) {
+                   back->special(backhandle, specials[i].code);
+                   net_pending_errors();
+               }
+           }
        }
        break;