X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=lib-crypt%2Fpgpkey.c;fp=lib-crypt%2Fpgpkey.c;h=0000000000000000000000000000000000000000;hp=96db58a5cb0993f7b33eba080a93f6fe2eab3146;hb=777dc6d5374fd154ac626421c813961b8ab18f2d;hpb=678c4d550b27a06ba3c94ac5821fcf0291c33f8a diff --git a/lib-crypt/pgpkey.c b/lib-crypt/pgpkey.c deleted file mode 100644 index 96db58a..0000000 --- a/lib-crypt/pgpkey.c +++ /dev/null @@ -1,938 +0,0 @@ -/* - * Copyright notice from original mutt: - * Copyright (C) 1996,1997 Michael R. Elkins - * Copyright (c) 1998,1999 Thomas Roessler - * - * This file is part of mutt-ng, see http://www.muttng.org/. - * It's licensed under the GNU General Public License, - * please see the file GPL in the top level source directory. - */ - -#include - -#include -#include - -#include -#include -#include - -#include "recvattach.h" -#include "pgp.h" -#include "pager.h" -#include "sort.h" - -struct pgp_cache { - char *what; - char *dflt; - struct pgp_cache *next; -}; - -static struct pgp_cache *id_defaults = NULL; - -static char trust_flags[] = "?- +"; - -static char *pgp_key_abilities (int flags) -{ - static char buff[3]; - - if (!(flags & KEYFLAG_CANENCRYPT)) - buff[0] = '-'; - else if (flags & KEYFLAG_PREFER_SIGNING) - buff[0] = '.'; - else - buff[0] = 'e'; - - if (!(flags & KEYFLAG_CANSIGN)) - buff[1] = '-'; - else if (flags & KEYFLAG_PREFER_ENCRYPTION) - buff[1] = '.'; - else - buff[1] = 's'; - - buff[2] = '\0'; - - return buff; -} - -static char pgp_flags (int flags) -{ - if (flags & KEYFLAG_REVOKED) - return 'R'; - else if (flags & KEYFLAG_EXPIRED) - return 'X'; - else if (flags & KEYFLAG_DISABLED) - return 'd'; - else if (flags & KEYFLAG_CRITICAL) - return 'c'; - else - return ' '; -} - -static pgp_key_t pgp_principal_key (pgp_key_t key) -{ - if (key->flags & KEYFLAG_SUBKEY && key->parent) - return key->parent; - else - return key; -} - -/* - * Format an entry on the PGP key selection menu. - * - * %n number - * %k key id %K key id of the principal key - * %u user id - * %a algorithm %A algorithm of the princ. key - * %l length %L length of the princ. key - * %f flags %F flags of the princ. key - * %c capabilities %C capabilities of the princ. key - * %t trust/validity of the key-uid association - * %[...] date of key using strftime(3) - */ - -typedef struct pgp_entry { - ssize_t num; - pgp_uid_t *uid; -} pgp_entry_t; - -static const char * -pgp_entry_fmt (char *dest, ssize_t destlen, char op, - const char *src, const char *prefix, - const char *ifstr, const char *elstr, - anytype data, format_flag flags) -{ - char fmt[16]; - pgp_entry_t *entry; - pgp_uid_t *uid; - pgp_key_t key, pkey; - int kflags = 0; - int optional = (flags & M_FORMAT_OPTIONAL); - - entry = data.ptr; - uid = entry->uid; - key = uid->parent; - pkey = pgp_principal_key (key); - - if (isupper ((unsigned char) op)) - key = pkey; - - kflags = key->flags | (pkey->flags & KEYFLAG_RESTRICTIONS) - | uid->flags; - - switch (ascii_tolower (op)) { - case '[': - - { - const char *cp; - char buf2[STRING], *p; - int do_locales; - struct tm *tm; - ssize_t len; - - p = dest; - - cp = src; - if (*cp == '!') { - do_locales = 0; - cp++; - } - else - do_locales = 1; - - len = destlen - 1; - while (len > 0 && *cp != ']') { - if (*cp == '%') { - cp++; - if (len >= 2) { - *p++ = '%'; - *p++ = *cp; - len -= 2; - } - else - break; /* not enough space */ - cp++; - } - else { - *p++ = *cp++; - len--; - } - } - *p = 0; - - if (do_locales && Locale) - setlocale (LC_TIME, Locale); - - tm = localtime (&key->gen_time); - - strftime (buf2, sizeof (buf2), dest, tm); - - if (do_locales) - setlocale (LC_TIME, "C"); - - snprintf (fmt, sizeof (fmt), "%%%ss", prefix); - snprintf (dest, destlen, fmt, buf2); - if (len > 0) - src = cp + 1; - } - break; - case 'n': - if (!optional) { - snprintf (fmt, sizeof (fmt), "%%%sd", prefix); - snprintf (dest, destlen, fmt, entry->num); - } - break; - case 'k': - if (!optional) { - snprintf (fmt, sizeof (fmt), "%%%ss", prefix); - snprintf (dest, destlen, fmt, _pgp_keyid (key)); - } - break; - case 'u': - if (!optional) { - snprintf (fmt, sizeof (fmt), "%%%ss", prefix); - snprintf (dest, destlen, fmt, uid->addr); - } - break; - case 'a': - if (!optional) { - snprintf (fmt, sizeof (fmt), "%%%ss", prefix); - snprintf (dest, destlen, fmt, key->algorithm); - } - break; - case 'l': - if (!optional) { - snprintf (fmt, sizeof (fmt), "%%%sd", prefix); - snprintf (dest, destlen, fmt, key->keylen); - } - break; - case 'f': - if (!optional) { - snprintf (fmt, sizeof (fmt), "%%%sc", prefix); - snprintf (dest, destlen, fmt, pgp_flags (kflags)); - } - else if (!(kflags & (KEYFLAG_RESTRICTIONS))) - optional = 0; - break; - case 'c': - if (!optional) { - snprintf (fmt, sizeof (fmt), "%%%ss", prefix); - snprintf (dest, destlen, fmt, pgp_key_abilities (kflags)); - } - else if (!(kflags & (KEYFLAG_ABILITIES))) - optional = 0; - break; - case 't': - if (!optional) { - snprintf (fmt, sizeof (fmt), "%%%sc", prefix); - snprintf (dest, destlen, fmt, trust_flags[uid->trust & 0x03]); - } - else if (!(uid->trust & 0x03)) - /* undefined trust */ - optional = 0; - break; - default: - *dest = '\0'; - } - - if (flags & M_FORMAT_OPTIONAL) - m_strformat(dest, destlen, 0, optional ? ifstr : elstr, - mutt_attach_fmt, data, 0); - return src; -} - -static void pgp_entry (char *s, ssize_t l, MUTTMENU * menu, int num) -{ - pgp_uid_t **KeyTable = (pgp_uid_t **) menu->data; - pgp_entry_t entry; - - entry.uid = KeyTable[num]; - entry.num = num + 1; - - m_strformat(s, l, COLS - SW, PgpEntryFormat, pgp_entry_fmt, &entry, - option(OPTARROWCURSOR) ? M_FORMAT_ARROWCURSOR : 0); -} - -static int _pgp_compare_address (const void *a, const void *b) -{ - int r; - - pgp_uid_t **s = (pgp_uid_t **) a; - pgp_uid_t **t = (pgp_uid_t **) b; - - if ((r = m_strcasecmp((*s)->addr, (*t)->addr))) - return r > 0; - else - return (m_strcasecmp(_pgp_keyid ((*s)->parent), - _pgp_keyid ((*t)->parent)) > 0); -} - -static int pgp_compare_address (const void *a, const void *b) -{ - return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_address (a, b) - : _pgp_compare_address (a, b)); -} - - - -static int _pgp_compare_keyid (const void *a, const void *b) -{ - int r; - - pgp_uid_t **s = (pgp_uid_t **) a; - pgp_uid_t **t = (pgp_uid_t **) b; - - if ((r = m_strcasecmp(_pgp_keyid ((*s)->parent), - _pgp_keyid ((*t)->parent)))) - return r > 0; - else - return (m_strcasecmp((*s)->addr, (*t)->addr)) > 0; -} - -static int pgp_compare_keyid (const void *a, const void *b) -{ - return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_keyid (a, b) - : _pgp_compare_keyid (a, b)); -} - -static int _pgp_compare_date (const void *a, const void *b) -{ - int r; - pgp_uid_t **s = (pgp_uid_t **) a; - pgp_uid_t **t = (pgp_uid_t **) b; - - if ((r = ((*s)->parent->gen_time - (*t)->parent->gen_time))) - return r > 0; - return (m_strcasecmp((*s)->addr, (*t)->addr)) > 0; -} - -static int pgp_compare_date (const void *a, const void *b) -{ - return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_date (a, b) - : _pgp_compare_date (a, b)); -} - -static int _pgp_compare_trust (const void *a, const void *b) -{ - int r; - - pgp_uid_t **s = (pgp_uid_t **) a; - pgp_uid_t **t = (pgp_uid_t **) b; - - if ((r = (((*s)->parent->flags & (KEYFLAG_RESTRICTIONS)) - - ((*t)->parent->flags & (KEYFLAG_RESTRICTIONS))))) - return r > 0; - if ((r = ((*s)->trust - (*t)->trust))) - return r < 0; - if ((r = ((*s)->parent->keylen - (*t)->parent->keylen))) - return r < 0; - if ((r = ((*s)->parent->gen_time - (*t)->parent->gen_time))) - return r < 0; - if ((r = m_strcasecmp((*s)->addr, (*t)->addr))) - return r > 0; - return (m_strcasecmp(_pgp_keyid ((*s)->parent), - _pgp_keyid ((*t)->parent))) > 0; -} - -static int pgp_compare_trust (const void *a, const void *b) -{ - return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_trust (a, b) - : _pgp_compare_trust (a, b)); -} - -static int pgp_key_is_valid (pgp_key_t k) -{ - pgp_key_t pk = pgp_principal_key (k); - - if (k->flags & KEYFLAG_CANTUSE) - return 0; - if (pk->flags & KEYFLAG_CANTUSE) - return 0; - - return 1; -} - -static int pgp_id_is_strong (pgp_uid_t * uid) -{ - if ((uid->trust & 3) < 3) - return 0; - /* else */ - return 1; -} - -static int pgp_id_is_valid (pgp_uid_t * uid) -{ - if (!pgp_key_is_valid (uid->parent)) - return 0; - if (uid->flags & KEYFLAG_CANTUSE) - return 0; - /* else */ - return 1; -} - -#define PGP_KV_VALID 1 -#define PGP_KV_ADDR 2 -#define PGP_KV_STRING 4 -#define PGP_KV_STRONGID 8 - -#define PGP_KV_MATCH (PGP_KV_ADDR|PGP_KV_STRING) - -static int pgp_id_matches_addr (address_t * addr, address_t * u_addr, - pgp_uid_t * uid) -{ - int rv = 0; - - if (pgp_id_is_valid (uid)) - rv |= PGP_KV_VALID; - - if (pgp_id_is_strong (uid)) - rv |= PGP_KV_STRONGID; - - if (addr->mailbox && u_addr->mailbox - && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0) - rv |= PGP_KV_ADDR; - - if (addr->personal && u_addr->personal - && m_strcasecmp(addr->personal, u_addr->personal) == 0) - rv |= PGP_KV_STRING; - - return rv; -} - -static pgp_key_t pgp_select_key (pgp_key_t keys, address_t * p, const char *s) -{ - int keymax; - pgp_uid_t **KeyTable; - MUTTMENU *menu; - int i, done = 0; - char helpstr[STRING], buf[LONG_STRING], tmpbuf[STRING]; - char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX]; - FILE *fp, *devnull; - pid_t thepid; - pgp_key_t kp; - pgp_uid_t *a; - int (*f) (const void *, const void *); - - int unusable = 0; - - keymax = 0; - KeyTable = NULL; - - for (i = 0, kp = keys; kp; kp = kp->next) { - if (!option (OPTPGPSHOWUNUSABLE) && (kp->flags & KEYFLAG_CANTUSE)) { - unusable = 1; - continue; - } - - for (a = kp->address; a; a = a->next) { - if (!option (OPTPGPSHOWUNUSABLE) && (a->flags & KEYFLAG_CANTUSE)) { - unusable = 1; - continue; - } - - if (i == keymax) { - keymax += 5; - p_realloc(&KeyTable, keymax); - } - - KeyTable[i++] = a; - } - } - - if (!i && unusable) { - mutt_error _("All matching keys are expired, revoked, or disabled."); - - mutt_sleep (1); - return NULL; - } - - switch (PgpSortKeys & SORT_MASK) { - case SORT_DATE: - f = pgp_compare_date; - break; - case SORT_KEYID: - f = pgp_compare_keyid; - break; - case SORT_ADDRESS: - f = pgp_compare_address; - break; - case SORT_TRUST: - default: - f = pgp_compare_trust; - break; - } - qsort (KeyTable, i, sizeof (pgp_uid_t *), f); - - helpstr[0] = 0; - mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_PGP, OP_EXIT); - m_strcat(helpstr, sizeof(helpstr), buf); - mutt_make_help (buf, sizeof (buf), _("Select "), MENU_PGP, - OP_GENERIC_SELECT_ENTRY); - m_strcat(helpstr, sizeof(helpstr), buf); - mutt_make_help (buf, sizeof (buf), _("Check key "), MENU_PGP, - OP_VERIFY_KEY); - m_strcat(helpstr, sizeof(helpstr), buf); - mutt_make_help (buf, sizeof (buf), _("Help"), MENU_PGP, OP_HELP); - m_strcat(helpstr, sizeof(helpstr), buf); - - menu = mutt_new_menu (); - menu->max = i; - menu->make_entry = pgp_entry; - menu->menu = MENU_PGP; - menu->help = helpstr; - menu->data = KeyTable; - - if (p) - snprintf (buf, sizeof (buf), _("PGP keys matching <%s>."), p->mailbox); - else - snprintf (buf, sizeof (buf), _("PGP keys matching \"%s\"."), s); - - - menu->title = buf; - - kp = NULL; - - mutt_clear_error (); - - while (!done) { - switch (mutt_menuLoop (menu)) { - - case OP_VERIFY_KEY: - - if ((devnull = fopen("/dev/null", "w")) == NULL) { - mutt_perror (_("Can't open /dev/null")); - - break; - } - - fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL); - if (!fp) { - m_fclose(&devnull); - mutt_perror (_("Can't create temporary file")); - - break; - } - - mutt_message _("Invoking PGP..."); - - snprintf (tmpbuf, sizeof (tmpbuf), "0x%s", - pgp_keyid (pgp_principal_key - (KeyTable[menu->current]->parent))); - - if ((thepid = pgp_invoke_verify_key (NULL, NULL, NULL, -1, - fileno (fp), fileno (devnull), - tmpbuf)) == -1) { - mutt_perror (_("Can't create filter")); - - unlink (tempfile); - m_fclose(&fp); - m_fclose(&devnull); - } - - mutt_wait_filter (thepid); - m_fclose(&fp); - m_fclose(&devnull); - mutt_clear_error (); - snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), - pgp_keyid (pgp_principal_key - (KeyTable[menu->current]->parent))); - mutt_do_pager (cmd, tempfile, 0, NULL); - menu->redraw = REDRAW_FULL; - - break; - - case OP_VIEW_ID: - - mutt_message ("%s", KeyTable[menu->current]->addr); - break; - - case OP_GENERIC_SELECT_ENTRY: - - - /* XXX make error reporting more verbose */ - - if (option (OPTPGPCHECKTRUST)) - if (!pgp_key_is_valid (KeyTable[menu->current]->parent)) { - mutt_error _("This key can't be used: expired/disabled/revoked."); - - break; - } - - if (option (OPTPGPCHECKTRUST) && - (!pgp_id_is_valid (KeyTable[menu->current]) - || !pgp_id_is_strong (KeyTable[menu->current]))) { - const char *q = ""; - char buff[LONG_STRING]; - - if (KeyTable[menu->current]->flags & KEYFLAG_CANTUSE) - q = N_("ID is expired/disabled/revoked."); - else - switch (KeyTable[menu->current]->trust & 0x03) { - case 0: - q = N_("ID has undefined validity."); - break; - case 1: - q = N_("ID is not valid."); - break; - case 2: - q = N_("ID is only marginally valid."); - break; - } - - snprintf (buff, sizeof (buff), - _("%s Do you really want to use the key?"), _(q)); - - if (mutt_yesorno (buff, M_NO) != M_YES) { - mutt_clear_error (); - break; - } - } - -# if 0 - kp = pgp_principal_key (KeyTable[menu->current]->parent); -# else - kp = KeyTable[menu->current]->parent; -# endif - done = 1; - break; - - case OP_EXIT: - - kp = NULL; - done = 1; - break; - } - } - - mutt_menuDestroy (&menu); - p_delete(&KeyTable); - - set_option (OPTNEEDREDRAW); - - return (kp); -} - -pgp_key_t pgp_ask_for_key (char *tag, char *whatfor, - short abilities, pgp_ring_t keyring) -{ - pgp_key_t key; - char resp[STRING]; - struct pgp_cache *l = NULL; - - mutt_clear_error (); - - resp[0] = 0; - if (whatfor) { - - for (l = id_defaults; l; l = l->next) - if (!m_strcasecmp(whatfor, l->what)) { - m_strcpy(resp, sizeof(resp), NONULL(l->dflt)); - break; - } - } - - - for (;;) { - resp[0] = 0; - if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0) - return NULL; - - if (whatfor) { - if (l) - m_strreplace(&l->dflt, resp); - else { - l = p_new(struct pgp_cache, 1); - l->next = id_defaults; - id_defaults = l; - l->what = m_strdup(whatfor); - l->dflt = m_strdup(resp); - } - } - - if ((key = pgp_getkeybystr (resp, abilities, keyring))) - return key; - - BEEP (); - } - /* not reached */ -} - -/* generate a public key attachment */ - -BODY *pgp_make_key_attachment (char *tempf) -{ - BODY *att; - char buff[LONG_STRING]; - char tempfb[_POSIX_PATH_MAX], tmp[STRING]; - FILE *tempfp; - FILE *devnull; - struct stat sb; - pid_t thepid; - pgp_key_t key; - - unset_option (OPTPGPCHECKTRUST); - - key = - pgp_ask_for_key (_("Please enter the key ID: "), NULL, 0, PGP_PUBRING); - - if (!key) - return NULL; - - snprintf (tmp, sizeof (tmp), "0x%s", pgp_keyid (pgp_principal_key (key))); - pgp_free_key (&key); - - if (!tempf) { - tempfp = m_tempfile (tempfb, sizeof(tempfb), NONULL(MCore.tmpdir), NULL); - tempf = tempfb; - } else { - tempfp = safe_fopen(tempf, "a"); - } - - if (!tempfp) { - mutt_perror (_("Can't create temporary file")); - return NULL; - } - - if ((devnull = fopen("/dev/null", "w")) == NULL) { - mutt_perror (_("Can't open /dev/null")); - - m_fclose(&tempfp); - if (tempf == tempfb) - unlink (tempf); - return NULL; - } - - mutt_message _("Invoking pgp..."); - - - if ((thepid = - pgp_invoke_export (NULL, NULL, NULL, -1, - fileno (tempfp), fileno (devnull), tmp)) == -1) { - mutt_perror (_("Can't create filter")); - - unlink (tempf); - m_fclose(&tempfp); - m_fclose(&devnull); - return NULL; - } - - mutt_wait_filter (thepid); - - m_fclose(&tempfp); - m_fclose(&devnull); - - att = body_new(); - att->filename = m_strdup(tempf); - att->unlink = 1; - att->use_disp = 0; - att->type = TYPEAPPLICATION; - att->subtype = m_strdup("pgp-keys"); - snprintf (buff, sizeof (buff), _("PGP Key %s."), tmp); - att->description = m_strdup(buff); - mutt_update_encoding (att); - - stat (tempf, &sb); - att->length = sb.st_size; - - return att; -} - -static string_list_t *pgp_add_string_to_hints (string_list_t * hints, const char *str) -{ - char *scratch; - char *t; - - if ((scratch = m_strdup(str)) == NULL) - return hints; - - for (t = strtok (scratch, " ,.:\"()<>\n"); t; - t = strtok (NULL, " ,.:\"()<>\n")) { - if (m_strlen(t) > 3) - hints = mutt_add_list (hints, t); - } - - p_delete(&scratch); - return hints; -} - -static pgp_key_t *pgp_get_lastp (pgp_key_t p) -{ - for (; p; p = p->next) - if (!p->next) - return &p->next; - - return NULL; -} - -pgp_key_t pgp_getkeybyaddr (address_t * a, short abilities, pgp_ring_t keyring) -{ - address_t *r, *p; - string_list_t *hints = NULL; - - int weak = 0; - int invalid = 0; - int multi = 0; - int this_key_has_strong; - int this_key_has_weak; - int this_key_has_invalid; - int match; - - pgp_key_t keys, k, kn; - pgp_key_t the_valid_key = NULL; - pgp_key_t matches = NULL; - pgp_key_t *last = &matches; - pgp_uid_t *q; - - if (a && a->mailbox) - hints = pgp_add_string_to_hints (hints, a->mailbox); - if (a && a->personal) - hints = pgp_add_string_to_hints (hints, a->personal); - - mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox); - keys = pgp_get_candidates (keyring, hints); - - string_list_wipe(&hints); - - if (!keys) - return NULL; - - for (k = keys; k; k = kn) { - kn = k->next; - - if (abilities && !(k->flags & abilities)) { - continue; - } - - this_key_has_weak = 0; /* weak but valid match */ - this_key_has_invalid = 0; /* invalid match */ - this_key_has_strong = 0; /* strong and valid match */ - match = 0; /* any match */ - - for (q = k->address; q; q = q->next) { - r = rfc822_parse_adrlist (NULL, q->addr); - - for (p = r; p; p = p->next) { - int validity = pgp_id_matches_addr (a, p, q); - - if (validity & PGP_KV_MATCH) /* something matches */ - match = 1; - - /* is this key a strong candidate? */ - if ((validity & PGP_KV_VALID) && (validity & PGP_KV_STRONGID) - && (validity & PGP_KV_ADDR)) { - if (the_valid_key && the_valid_key != k) - multi = 1; - the_valid_key = k; - this_key_has_strong = 1; - } - else if ((validity & PGP_KV_MATCH) && !(validity & PGP_KV_VALID)) - this_key_has_invalid = 1; - else if ((validity & PGP_KV_MATCH) - && (!(validity & PGP_KV_STRONGID) - || !(validity & PGP_KV_ADDR))) - this_key_has_weak = 1; - } - - address_list_wipe(&r); - } - - if (match && !this_key_has_strong && this_key_has_invalid) - invalid = 1; - if (match && !this_key_has_strong && this_key_has_weak) - weak = 1; - - if (match) { - *last = pgp_principal_key (k); - kn = pgp_remove_key (&keys, *last); - last = pgp_get_lastp (k); - } - } - - pgp_free_key (&keys); - - if (matches) { - if (the_valid_key && !multi /* && !weak - && !(invalid && option (OPTPGPSHOWUNUSABLE)) */ ) { - /* - * There was precisely one strong match on a valid ID. - * - * Proceed without asking the user. - */ - pgp_remove_key (&matches, the_valid_key); - pgp_free_key (&matches); - k = the_valid_key; - } - else { - /* - * Else: Ask the user. - */ - if ((k = pgp_select_key (matches, a, NULL))) - pgp_remove_key (&matches, k); - pgp_free_key (&matches); - } - - return k; - } - - return NULL; -} - -pgp_key_t pgp_getkeybystr (const char *p, short abilities, pgp_ring_t keyring) -{ - string_list_t *hints = NULL; - pgp_key_t keys; - pgp_key_t matches = NULL; - pgp_key_t *last = &matches; - pgp_key_t k, kn; - pgp_uid_t *a; - short match; - - mutt_message (_("Looking for keys matching \"%s\"..."), p); - - hints = pgp_add_string_to_hints (hints, p); - keys = pgp_get_candidates (keyring, hints); - string_list_wipe(&hints); - - if (!keys) - return NULL; - - - for (k = keys; k; k = kn) { - kn = k->next; - if (abilities && !(k->flags & abilities)) - continue; - - match = 0; - - for (a = k->address; a; a = a->next) { - if (!*p || m_strcasecmp(p, pgp_keyid (k)) == 0 - || (!m_strncasecmp(p, "0x", 2) - && !m_strcasecmp(p + 2, pgp_keyid (k))) - || (option (OPTPGPLONGIDS) && !m_strncasecmp(p, "0x", 2) - && !m_strcasecmp(p + 2, k->keyid + 8)) - || m_stristr(a->addr, p)) { - match = 1; - break; - } - } - - if (match) { - *last = pgp_principal_key (k); - kn = pgp_remove_key (&keys, *last); - last = pgp_get_lastp (k); - } - } - - pgp_free_key (&keys); - - if (matches) { - if ((k = pgp_select_key (matches, NULL, p))) - pgp_remove_key (&matches, k); - - pgp_free_key (&matches); - return k; - } - - return NULL; -} -