2 * Copyright notice from original mutt:
3 * Copyright (C) 1998-2000 Werner Koch <werner.koch@guug.de>
4 * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.org>
6 * This file is part of mutt-ng, see http://www.muttng.org/.
7 * It's licensed under the GNU General Public License,
8 * please see the file GPL in the top level source directory.
14 * This code used to be the parser for GnuPG's output.
16 * Nowadays, we are using an external pubring lister with PGP which mimics
17 * gpg's output format.
29 #include <sys/types.h>
36 #include <lib-lib/mem.h>
37 #include <lib-lib/str.h>
38 #include <lib-lib/date.h>
40 #include <lib-mime/mime.h>
46 #include "lib/debug.h"
49 * Read the GNUPG keys. For now we read the complete keyring by
50 * calling gnupg in a special mode.
52 * The output format of gpgm is colon delimited with these fields:
53 * - record type ("pub","uid","sig","rev" etc.)
57 * - 16 hex digits with the long keyid.
58 * - timestamp (1998-02-28)
65 /* decode the backslash-escaped user ids. */
67 static char *_chs = 0;
69 static void fix_uid (char *uid)
74 for (s = d = uid; *s;) {
75 if (*s == '\\' && *(s + 1) == 'x' && isxdigit ((unsigned char) *(s + 2))
76 && isxdigit ((unsigned char) *(s + 3))) {
77 *d++ = hexval (*(s + 2)) << 4 | hexval (*(s + 3));
85 if (_chs && (cd = mutt_iconv_open (_chs, "utf-8", 0)) != (iconv_t) - 1) {
86 int n = s - uid + 1; /* chars available in original buffer */
92 buf = p_new(char, n + 1);
93 ib = uid, ibl = d - uid + 1, ob = buf, obl = n;
94 my_iconv(cd, &ib, &ibl, &ob, &obl);
97 memcpy (uid, buf, ob - buf);
100 else if (ob - buf == n && (buf[n] = 0, m_strlen(buf) < n))
101 memcpy (uid, buf, n);
108 static pgp_key_t parse_pub_line (char *buf, int *is_subkey, pgp_key_t k)
110 pgp_uid_t *uid = NULL;
111 int field = 0, is_uid = 0;
120 debug_print (2, ("buf = `%s'\n", buf));
122 for (p = buf; p; p = pend) {
123 if ((pend = strchr (p, ':')))
126 if (field > 1 && !*p)
130 case 1: /* record type */
132 debug_print (2, ("record type: %s\n", p));
134 if (!m_strcmp(p, "pub"));
135 else if (!m_strcmp(p, "sub"))
137 else if (!m_strcmp(p, "sec"));
138 else if (!m_strcmp(p, "ssb"))
140 else if (!m_strcmp(p, "uid"))
145 if (!(is_uid || (*is_subkey && option (OPTPGPIGNORESUB))))
146 k = pgp_new_keyinfo();
150 case 2: /* trust info */
152 debug_print (2, ("trust info: %s\n", p));
154 switch (*p) { /* look only at the first letter */
156 flags |= KEYFLAG_EXPIRED;
159 flags |= KEYFLAG_REVOKED;
162 flags |= KEYFLAG_DISABLED;
178 if (!is_uid && !(*is_subkey && option (OPTPGPIGNORESUB)))
183 case 3: /* key length */
186 debug_print (2, ("key len: %s\n", p));
188 if (!(*is_subkey && option (OPTPGPIGNORESUB)))
189 k->keylen = atoi (p); /* fixme: add validation checks */
192 case 4: /* pubkey algo */
195 debug_print (2, ("pubkey algorithm: %s\n", p));
197 if (!(*is_subkey && option (OPTPGPIGNORESUB))) {
198 k->numalg = atoi (p);
199 k->algorithm = pgp_pkalgbytype (atoi (p));
203 case 5: /* 16 hex digits with the long keyid. */
205 debug_print (2, ("key id: %s\n", p));
207 if (!(*is_subkey && option (OPTPGPIGNORESUB)))
208 m_strreplace(&k->keyid, p);
212 case 6: /* timestamp (1998-02-28) */
217 debug_print (2, ("time stamp: %s\n", p));
223 st_time.tm_hour = 12;
224 m_strcpy(tstr, sizeof(tstr), p);
226 st_time.tm_year = atoi (tstr) - 1900;
228 st_time.tm_mon = (atoi (tstr + 5)) - 1;
229 st_time.tm_mday = atoi (tstr + 8);
230 k->gen_time = mutt_mktime (&st_time, 0);
233 case 7: /* valid for n days */
235 case 8: /* Local id */
237 case 9: /* ownertrust */
242 break; /* empty field or no trailing colon */
244 /* ignore user IDs on subkeys */
245 if (!is_uid && (*is_subkey && option (OPTPGPIGNORESUB)))
248 debug_print (2, ("user ID: %s\n", p));
250 uid = p_new(pgp_uid_t, 1);
252 uid->addr = m_strdup(p);
256 uid->next = k->address;
259 if (strstr (p, "ENCR"))
260 k->flags |= KEYFLAG_PREFER_ENCRYPTION;
261 if (strstr (p, "SIGN"))
262 k->flags |= KEYFLAG_PREFER_SIGNING;
266 case 11: /* signature class */
268 case 12: /* key capabilities */
269 debug_print (2, ("capabilities info: %s\n", p));
274 flags |= KEYFLAG_DISABLED;
278 flags |= KEYFLAG_CANENCRYPT;
282 flags |= KEYFLAG_CANSIGN;
287 if (!is_uid && (!*is_subkey || !option (OPTPGPIGNORESUB)
288 || !((flags & KEYFLAG_DISABLED)
289 || (flags & KEYFLAG_REVOKED)
290 || (flags & KEYFLAG_EXPIRED))))
302 pgp_key_t pgp_get_candidates (pgp_ring_t keyring, LIST * hints)
306 char buf[LONG_STRING];
307 pgp_key_t db = NULL, *kend, k = NULL, kk, mainkey = NULL;
311 if ((devnull = open ("/dev/null", O_RDWR)) == -1)
314 m_strreplace(&_chs, Charset);
316 thepid = pgp_invoke_list_keys (NULL, &fp, NULL, -1, -1, devnull,
325 while (fgets (buf, sizeof (buf) - 1, fp)) {
326 if (!(kk = parse_pub_line (buf, &is_sub, k)))
329 /* Only append kk to the list if it's new. */
338 k->flags |= KEYFLAG_SUBKEY;
340 for (l = &k->address; *l; l = &(*l)->next);
341 *l = pgp_copy_uids (mainkey->address, k);
349 mutt_perror ("fgets");
352 mutt_wait_filter (thepid);