📄 pgpkey.c
字号:
/* * Copyright (C) 1996,1997 Michael R. Elkins <me@mutt.org> * Copyright (c) 1998,1999 Thomas Roessler <roessler@does-not-exist.org> * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */#if HAVE_CONFIG_H# include "config.h"#endif#include "mutt.h"#include "mutt_curses.h"#include "mutt_menu.h"#include "mime.h"#include "pgp.h"#include "pager.h"#include "sort.h"#include <string.h>#include <ctype.h>#include <stdlib.h>#include <unistd.h>#include <sys/stat.h>#include <sys/wait.h>#include <locale.h>#ifdef CRYPT_BACKEND_CLASSIC_PGPstruct 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{ size_t num; pgp_uid_t *uid;} pgp_entry_t;static const char *pgp_entry_fmt (char *dest, size_t destlen, char op, const char *src, const char *prefix, const char *ifstring, const char *elsestring, unsigned long 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 = (pgp_entry_t *) data; 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[SHORT_STRING], *p; int do_locales; struct tm *tm; size_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 (optional) mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0); else if (flags & M_FORMAT_OPTIONAL) mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0); return (src);} static void pgp_entry (char *s, size_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; mutt_FormatString (s, l, NONULL (PgpEntryFormat), pgp_entry_fmt, (unsigned long) &entry, M_FORMAT_ARROWCURSOR);}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 = mutt_strcasecmp ((*s)->addr, (*t)->addr))) return r > 0; else return (mutt_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 = mutt_strcasecmp (_pgp_keyid ((*s)->parent), _pgp_keyid ((*t)->parent)))) return r > 0; else return (mutt_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 (mutt_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 = mutt_strcasecmp ((*s)->addr, (*t)->addr))) return r > 0; return (mutt_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 *addr, ADDRESS *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 && mutt_strcasecmp (addr->mailbox, u_addr->mailbox) == 0) rv |= PGP_KV_ADDR; if (addr->personal && u_addr->personal && mutt_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 * p, const char *s){ int keymax; pgp_uid_t **KeyTable; MUTTMENU *menu; int i, done = 0; char helpstr[SHORT_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; safe_realloc (&KeyTable, sizeof (pgp_uid_t *) * 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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -