Nico Golde:
[apps/madmutt.git] / keymap.c
index 665a5fc..e41d6d7 100644 (file)
--- a/keymap.c
+++ b/keymap.c
  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  */ 
 
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
 #include "mutt.h"
 #include "mutt_menu.h"
 #include "mutt_curses.h"
 #include "functions.h"
 
 struct mapping_t Menus[] = {
- { "alias",    MENU_ALIAS },
- { "attach",   MENU_ATTACH },
- { "browser",  MENU_FOLDER },
- { "compose",  MENU_COMPOSE },
- { "editor",   MENU_EDITOR },
- { "index",    MENU_MAIN },
- { "pager",    MENU_PAGER },
- { "postpone", MENU_POST },
- { "pgp",      MENU_PGP },
- { "smime",    MENU_SMIME },
+ { "alias",        MENU_ALIAS },
+ { "attach",        MENU_ATTACH },
+ { "browser",        MENU_FOLDER },
+ { "compose",        MENU_COMPOSE },
+ { "editor",        MENU_EDITOR },
+ { "index",        MENU_MAIN },
+ { "pager",        MENU_PAGER },
+ { "postpone",        MENU_POST },
+ { "pgp",        MENU_PGP },
+ { "smime",        MENU_SMIME },
+
+#ifdef HAVE_GPGME
+ { "key_select_pgp",   MENU_KEY_SELECT_PGP },
+ { "key_select_smime", MENU_KEY_SELECT_SMIME },
+#endif
+
  
 #ifdef MIXMASTER
-  { "mix",     MENU_MIX },
+  { "mix",         MENU_MIX },
 #endif
   
 
- { "query",    MENU_QUERY },
- { "generic",  MENU_GENERIC },
- { NULL,       0 }
+ { "query",        MENU_QUERY },
+ { "generic",        MENU_GENERIC },
+ { NULL,        0 }
 };
 
 #define mutt_check_menu(s) mutt_getvaluebyname(s, Menus)
 
 static struct mapping_t KeyNames[] = {
-  { "<PageUp>",        KEY_PPAGE },
-  { "<PageDown>",      KEY_NPAGE },
-  { "<Up>",    KEY_UP },
-  { "<Down>",  KEY_DOWN },
-  { "<Right>", KEY_RIGHT },
-  { "<Left>",  KEY_LEFT },
-  { "<Delete>",        KEY_DC },
+  { "<PageUp>",        KEY_PPAGE },
+  { "<PageDown>",        KEY_NPAGE },
+  { "<Up>",        KEY_UP },
+  { "<Down>",        KEY_DOWN },
+  { "<Right>",        KEY_RIGHT },
+  { "<Left>",        KEY_LEFT },
+  { "<Delete>",        KEY_DC },
   { "<BackSpace>",KEY_BACKSPACE },
-  { "<Insert>",        KEY_IC },
-  { "<Home>",  KEY_HOME },
-  { "<End>",   KEY_END },
+  { "<Insert>",        KEY_IC },
+  { "<Home>",        KEY_HOME },
+  { "<End>",        KEY_END },
 #ifdef KEY_ENTER
-  { "<Enter>", KEY_ENTER },
+  { "<Enter>",        KEY_ENTER },
 #endif
-  { "<Return>",        M_ENTER_C },
-  { "<Esc>",   '\033' },
-  { "<Tab>",   '\t' },
-  { "<Space>", ' ' },
+  { "<Return>",        M_ENTER_C },
+  { "<Esc>",        '\033' },
+  { "<Tab>",        '\t' },
+  { "<Space>",        ' ' },
 #ifdef KEY_BTAB
   { "<BackTab>", KEY_BTAB },
 #endif
-  { NULL,      0 }
+  { NULL,        0 }
 };
 
 /* contains the last key the user pressed */
@@ -149,18 +159,18 @@ static int parsekeys (char *str, keycode_t *d, int max)
       
       if ((n = mutt_getvaluebyname (s, KeyNames)) != -1)
       {
-       s = t;
-       *d = n;
+        s = t;
+        *d = n;
       }
       else if ((n = parse_fkey(s)) > 0)
       {
-       s = t;
-       *d = KEY_F (n);
+        s = t;
+        *d = KEY_F (n);
       }
       else if ((n = parse_keycode(s)) > 0)
       {
-       s = t;
-       *d = n;
+        s = t;
+        *d = n;
       }
       
       *t = c;
@@ -203,13 +213,13 @@ void km_bind (char *s, int menu, int op, char *macro, char *descr)
       /* map and tmp match, but have different lengths, so overwrite */
       do
       {
-       len = tmp->eq;
-       next = tmp->next;
-       FREE (&tmp->macro);
-       FREE (&tmp->keys);
-       FREE (&tmp->descr);
-       FREE (&tmp);
-       tmp = next;
+        len = tmp->eq;
+        next = tmp->next;
+        FREE (&tmp->macro);
+        FREE (&tmp->keys);
+        FREE (&tmp->descr);
+        FREE (&tmp);
+        tmp = next;
       }
       while (tmp && len >= pos);
       map->eq = len;
@@ -228,7 +238,7 @@ void km_bind (char *s, int menu, int op, char *macro, char *descr)
       last = tmp;
       lastpos = pos;
       if (pos > tmp->eq)
-       pos = tmp->eq;
+        pos = tmp->eq;
       tmp = tmp->next;
     }
   }
@@ -255,7 +265,7 @@ static int get_op (struct binding_t *bindings, const char *start, size_t len)
   for (i = 0; bindings[i].name; i++)
   {
     if (!ascii_strncasecmp (start, bindings[i].name, len) &&   
-       mutt_strlen (bindings[i].name) == len)
+        mutt_strlen (bindings[i].name) == len)
       return bindings[i].op;
   }
 
@@ -268,8 +278,9 @@ static char *get_func (struct binding_t *bindings, int op)
 
   for (i = 0; bindings[i].name; i++)
   {
-    if (bindings[i].op == op)
+    if (bindings[i].op == op) {
       return bindings[i].name;
+    }
   }
 
   return NULL;
@@ -288,49 +299,49 @@ static void push_string (char *s)
     if (*p == '>')
     {
       for (pp = p - 1; pp >= s && *pp != '<'; pp--)
-       ;
+        ;
       if (pp >= s)
       {
-       if ((i = parse_fkey (pp)) > 0)
-       {
-         mutt_ungetch (KEY_F (i), 0);
-         p = pp - 1;
-         continue;
-       }
-
-       l = p - pp + 1;
-       for (i = 0; KeyNames[i].name; i++)
-       {
-         if (!ascii_strncasecmp (pp, KeyNames[i].name, l))
-           break;
-       }
-       if (KeyNames[i].name)
-       {
-         /* found a match */
-         mutt_ungetch (KeyNames[i].value, 0);
-         p = pp - 1;
-         continue;
-       }
-
-       /* See if it is a valid command
-        * skip the '<' and the '>' when comparing */
-       for (i = 0; Menus[i].name; i++)
-       {
-         struct binding_t *binding = km_get_table (Menus[i].value);
-         if (binding)
-         {
-           op = get_op (binding, pp + 1, l - 2);
-           if (op != OP_NULL)
-             break;
-         }
-       }
-
-       if (op != OP_NULL)
-       {
-         mutt_ungetch (0, op);
-         p = pp - 1;
-         continue;
-       }
+        if ((i = parse_fkey (pp)) > 0)
+        {
+          mutt_ungetch (KEY_F (i), 0);
+          p = pp - 1;
+          continue;
+        }
+
+        l = p - pp + 1;
+        for (i = 0; KeyNames[i].name; i++)
+        {
+          if (!ascii_strncasecmp (pp, KeyNames[i].name, l))
+            break;
+        }
+        if (KeyNames[i].name)
+        {
+          /* found a match */
+          mutt_ungetch (KeyNames[i].value, 0);
+          p = pp - 1;
+          continue;
+        }
+
+        /* See if it is a valid command
+         * skip the '<' and the '>' when comparing */
+        for (i = 0; Menus[i].name; i++)
+        {
+          struct binding_t *binding = km_get_table (Menus[i].value);
+          if (binding)
+          {
+            op = get_op (binding, pp + 1, l - 2);
+            if (op != OP_NULL)
+              break;
+          }
+        }
+
+        if (op != OP_NULL)
+        {
+          mutt_ungetch (0, op);
+          p = pp - 1;
+          continue;
+        }
       }
     }
     mutt_ungetch (*p--, 0);
@@ -356,9 +367,9 @@ static int retry_generic (int menu, keycode_t *keys, int keyslen, int lastkey)
 }
 
 /* return values:
- *     >0              function to execute
- *     OP_NULL         no function bound to key sequence
- *     -1              error occured while reading input
+ *        >0                function to execute
+ *        OP_NULL                no function bound to key sequence
+ *        -1                error occured while reading input
  */
 int km_dokey (int menu)
 {
@@ -368,6 +379,7 @@ int km_dokey (int menu)
   int n = 0;
   int i;
 
+
   if (!map)
     return (retry_generic (menu, NULL, 0, 0));
 
@@ -394,49 +406,49 @@ int km_dokey (int menu)
 
       /* is this a valid op for this menu? */
       if ((bindings = km_get_table (menu)) &&
-         (func = get_func (bindings, tmp.op)))
-       return tmp.op;
+          (func = get_func (bindings, tmp.op)))
+        return tmp.op;
 
       if (menu == MENU_EDITOR && get_func (OpEditor, tmp.op))
-       return tmp.op;
+        return tmp.op;
 
       if (menu != MENU_EDITOR && menu != MENU_PAGER)
       {
-       /* check generic menu */
-       bindings = OpGeneric; 
-       if ((func = get_func (bindings, tmp.op)))
-         return tmp.op;
+        /* check generic menu */
+        bindings = OpGeneric; 
+        if ((func = get_func (bindings, tmp.op)))
+          return tmp.op;
       }
 
       /* Sigh. Valid function but not in this context.
        * Find the literal string and push it back */
       for (i = 0; Menus[i].name; i++)
       {
-       bindings = km_get_table (Menus[i].value);
-       if (bindings)
-       {
-         func = get_func (bindings, tmp.op);
-         if (func)
-         {
-           /* careful not to feed the <..> as one token. otherwise 
-           * push_string() will push the bogus op right back! */
-           mutt_ungetch ('>', 0);
-           push_string (func);
-           mutt_ungetch ('<', 0);
-           break;
-         }
-       }
+        bindings = km_get_table (Menus[i].value);
+        if (bindings)
+        {
+          func = get_func (bindings, tmp.op);
+          if (func)
+          {
+            /* careful not to feed the <..> as one token. otherwise 
+            * push_string() will push the bogus op right back! */
+            mutt_ungetch ('>', 0);
+            push_string (func);
+            mutt_ungetch ('<', 0);
+            break;
+          }
+        }
       }
       /* continue to chew */
       if (func)
-       continue;
+        continue;
     }
 
     /* Nope. Business as usual */
     while (LastKey > map->keys[pos])
     {
       if (pos > map->eq || !map->next)
-       return (retry_generic (menu, map->keys, pos, LastKey));
+        return (retry_generic (menu, map->keys, pos, LastKey));
       map = map->next;
     }
 
@@ -447,13 +459,13 @@ int km_dokey (int menu)
     {
 
       if (map->op != OP_MACRO)
-       return map->op;
+        return map->op;
 
       if (n++ == 10)
       {
-       mutt_flushinp ();
-       mutt_error _("Macro loop detected.");
-       return -1;
+        mutt_flushinp ();
+        mutt_error _("Macro loop detected.");
+        return -1;
       }
 
       push_string (map->macro);
@@ -557,6 +569,11 @@ void km_init (void)
   if ((WithCrypto & APPLICATION_SMIME))
     create_bindings (OpSmime, MENU_SMIME);
 
+#ifdef CRYPT_BACKEND_GPGME
+  create_bindings (OpPgp, MENU_KEY_SELECT_PGP);
+  create_bindings (OpSmime, MENU_KEY_SELECT_SMIME);
+#endif
+
 #ifdef MIXMASTER
   create_bindings (OpMix, MENU_MIX);
   
@@ -687,38 +704,53 @@ int mutt_parse_push (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
   return (r);
 }
 
-/* expects to see: <menu-string> <key-string> */
-char *parse_keymap (int *menu, BUFFER *s, BUFFER *err)
+/* expects to see: <menu-string>,<menu-string>,... <key-string> */
+static char *parse_keymap (int *menu, BUFFER *s, int maxmenus, int *nummenus, BUFFER *err)
 {
   BUFFER buf;
+  int i=0;
+  char *p, *q;
 
   memset (&buf, 0, sizeof (buf));
 
   /* menu name */
   mutt_extract_token (&buf, s, 0);
+  p = buf.data;
   if (MoreArgs (s))
   {
-    if ((*menu = mutt_check_menu (buf.data)) == -1)
-    {
-      snprintf (err->data, err->dsize, _("%s: no such menu"), buf.data);
-    }
-    else
+    while (i < maxmenus)
     {
-      /* key sequence */
-      mutt_extract_token (&buf, s, 0);
+      q = strchr(p,',');
+      if (q)
+        *q = '\0';
 
-      if (!*buf.data)
+      if ((menu[i] = mutt_check_menu (p)) == -1)
       {
-       strfcpy (err->data, _("null key sequence"), err->dsize);
+         snprintf (err->data, err->dsize, _("%s: no such menu"), p);
+         goto error;
       }
-      else if (MoreArgs (s))
-       return (buf.data);
+      ++i;
+      if (q)
+        p = q+1;
+      else
+        break;
     }
+    *nummenus=i;
+    /* key sequence */
+    mutt_extract_token (&buf, s, 0);
+
+    if (!*buf.data)
+    {
+      strfcpy (err->data, _("null key sequence"), err->dsize);
+    }
+    else if (MoreArgs (s))
+      return (buf.data);
   }
   else
   {
     strfcpy (err->data, _("too few arguments"), err->dsize);
   }
+error:
   FREE (&buf.data);
   return (NULL);
 }
@@ -765,6 +797,13 @@ struct binding_t *km_get_table (int menu)
     case MENU_PGP:
       return (WithCrypto & APPLICATION_PGP)? OpPgp:NULL;
 
+#ifdef CRYPT_BACKEND_GPGME
+    case MENU_KEY_SELECT_PGP:
+      return OpPgp;
+    case MENU_KEY_SELECT_SMIME:
+      return OpSmime;
+#endif
+
 #ifdef MIXMASTER
     case MENU_MIX:
       return OpMix;
@@ -779,9 +818,10 @@ int mutt_parse_bind (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
 {
   struct binding_t *bindings = NULL;
   char *key;
-  int menu, r = 0;
+  int menu[sizeof(Menus)/sizeof(struct mapping_t)-1], r = 0, nummenus, i;
 
-  if ((key = parse_keymap (&menu, s, err)) == NULL)
+  if ((key = parse_keymap (menu, s, sizeof (menu)/sizeof (menu[0]),
+                          &nummenus, err)) == NULL)
     return (-1);
 
   /* function to execute */
@@ -792,19 +832,28 @@ int mutt_parse_bind (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
     r = -1;
   }
   else if (ascii_strcasecmp ("noop", buf->data) == 0)
-    km_bindkey (key, menu, OP_NULL); /* the `unbind' command */
+  {
+    for (i = 0; i < nummenus; ++i)
+    {
+      km_bindkey (key, menu[i], OP_NULL); /* the `unbind' command */
+    }
+  }
   else
   {
-    /* First check the "generic" list of commands */
-    if (menu == MENU_PAGER || menu == MENU_EDITOR || menu == MENU_GENERIC ||
-       try_bind (key, menu, buf->data, OpGeneric) != 0)
+    for (i = 0; i < nummenus; ++i)
     {
-      /* Now check the menu-specific list of commands (if they exist) */
-      bindings = km_get_table (menu);
-      if (bindings && try_bind (key, menu, buf->data, bindings) != 0)
+      /* First check the "generic" list of commands */
+      if (menu[i] == MENU_PAGER || menu[i] == MENU_EDITOR ||
+      menu[i] == MENU_GENERIC ||
+         try_bind (key, menu[i], buf->data, OpGeneric) != 0)
       {
-       snprintf (err->data, err->dsize, _("%s: no such function in map"), buf->data);
-       r = -1;
+        /* Now check the menu-specific list of commands (if they exist) */
+        bindings = km_get_table (menu[i]);
+        if (bindings && try_bind (key, menu[i], buf->data, bindings) != 0)
+        {
+          snprintf (err->data, err->dsize, _("%s: no such function in map"), buf->data);
+          r = -1;
+        }
       }
     }
   }
@@ -815,11 +864,11 @@ int mutt_parse_bind (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
 /* macro <menu> <key> <macro> <description> */
 int mutt_parse_macro (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
 {
-  int menu, r = -1;
+  int menu[sizeof(Menus)/sizeof(struct mapping_t)-1], r = -1, nummenus, i;
   char *seq = NULL;
   char *key;
 
-  if ((key = parse_keymap (&menu, s, err)) == NULL)
+  if ((key = parse_keymap (menu, s, sizeof (menu) / sizeof (menu[0]), &nummenus, err)) == NULL)
     return (-1);
 
   mutt_extract_token (buf, s, M_TOKEN_CONDENSE);
@@ -837,20 +886,26 @@ int mutt_parse_macro (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
 
       if (MoreArgs (s))
       {
-       strfcpy (err->data, _("macro: too many arguments"), err->dsize);
+        strfcpy (err->data, _("macro: too many arguments"), err->dsize);
       }
       else
       {
-       km_bind (key, menu, OP_MACRO, seq, buf->data);
-       r = 0;
+        for (i = 0; i < nummenus; ++i)
+        {
+          km_bind (key, menu[i], OP_MACRO, seq, buf->data);
+          r = 0;
+        }
       }
 
       FREE (&seq);
     }
     else
     {
-      km_bind (key, menu, OP_MACRO, buf->data, NULL);
-      r = 0;
+      for (i = 0; i < nummenus; ++i)
+      {
+        km_bind (key, menu[i], OP_MACRO, buf->data, NULL);
+        r = 0;
+      }
     }
   }
   FREE (&key);
@@ -877,7 +932,7 @@ int mutt_parse_exec (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
     function = buf->data;
 
     if ((bindings = km_get_table (CurrentMenu)) == NULL 
-       && CurrentMenu != MENU_PAGER)
+        && CurrentMenu != MENU_PAGER)
       bindings = OpGeneric;
 
     ops[nops] = get_op (bindings, function, mutt_strlen(function));
@@ -914,7 +969,7 @@ void mutt_what_key (void)
     if (ch != ERR && ch != ctrl ('G'))
     {
       mutt_message(_("Char = %s, Octal = %o, Decimal = %d"),
-              km_keyname(ch), ch, ch);
+               km_keyname(ch), ch, ch);
     }
   }
   while (ch != ERR && ch != ctrl ('G'));