mostly reindents.
[apps/madmutt.git] / gnupgparse.c
1 /*
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>
5  *
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.
9  */
10
11 /*
12  * NOTE
13  * 
14  * This code used to be the parser for GnuPG's output.
15  * 
16  * Nowadays, we are using an external pubring lister with PGP which mimics 
17  * gpg's output format.
18  * 
19  */
20
21 #if HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <time.h>
34 #include <ctype.h>
35
36 #include <lib-lib/mem.h>
37 #include <lib-lib/str.h>
38
39 #include <lib-mime/mime.h>
40
41 #include "mutt.h"
42 #include "pgp.h"
43 #include "charset.h"
44
45 #include "lib/debug.h"
46
47 /****************
48  * Read the GNUPG keys.  For now we read the complete keyring by
49  * calling gnupg in a special mode.
50  *
51  * The output format of gpgm is colon delimited with these fields:
52  *   - record type ("pub","uid","sig","rev" etc.)
53  *   - trust info
54  *   - key length
55  *   - pubkey algo
56  *   - 16 hex digits with the long keyid.
57  *   - timestamp (1998-02-28)
58  *   - Local id
59  *   - ownertrust
60  *   - name
61  *   - signature class
62  */
63
64 /* decode the backslash-escaped user ids. */
65
66 static char *_chs = 0;
67
68 static void fix_uid (char *uid)
69 {
70   char *s, *d;
71   iconv_t cd;
72
73   for (s = d = uid; *s;) {
74     if (*s == '\\' && *(s + 1) == 'x' && isxdigit ((unsigned char) *(s + 2))
75         && isxdigit ((unsigned char) *(s + 3))) {
76       *d++ = hexval (*(s + 2)) << 4 | hexval (*(s + 3));
77       s += 4;
78     }
79     else
80       *d++ = *s++;
81   }
82   *d = '\0';
83
84   if (_chs && (cd = mutt_iconv_open (_chs, "utf-8", 0)) != (iconv_t) - 1) {
85     int n = s - uid + 1;        /* chars available in original buffer */
86     char *buf;
87     const char *ib;
88     char *ob;
89     ssize_t ibl, obl;
90
91     buf = p_new(char, n + 1);
92     ib = uid, ibl = d - uid + 1, ob = buf, obl = n;
93     my_iconv(cd, &ib, &ibl, &ob, &obl);
94     if (!ibl) {
95       if (ob - buf < n) {
96         memcpy (uid, buf, ob - buf);
97         uid[ob - buf] = '\0';
98       }
99       else if (ob - buf == n && (buf[n] = 0, m_strlen(buf) < n))
100         memcpy (uid, buf, n);
101     }
102     p_delete(&buf);
103     iconv_close (cd);
104   }
105 }
106
107 static pgp_key_t parse_pub_line (char *buf, int *is_subkey, pgp_key_t k)
108 {
109   pgp_uid_t *uid = NULL;
110   int field = 0, is_uid = 0;
111   char *pend, *p;
112   int trust = 0;
113   int flags = 0;
114
115   *is_subkey = 0;
116   if (!*buf)
117     return NULL;
118
119   debug_print (2, ("buf = `%s'\n", buf));
120
121   for (p = buf; p; p = pend) {
122     if ((pend = strchr (p, ':')))
123       *pend++ = 0;
124     field++;
125     if (field > 1 && !*p)
126       continue;
127
128     switch (field) {
129     case 1:                    /* record type */
130       {
131         debug_print (2, ("record type: %s\n", p));
132
133         if (!m_strcmp(p, "pub"));
134         else if (!m_strcmp(p, "sub"))
135           *is_subkey = 1;
136         else if (!m_strcmp(p, "sec"));
137         else if (!m_strcmp(p, "ssb"))
138           *is_subkey = 1;
139         else if (!m_strcmp(p, "uid"))
140           is_uid = 1;
141         else
142           return NULL;
143
144         if (!(is_uid || (*is_subkey && option (OPTPGPIGNORESUB))))
145           k = pgp_new_keyinfo();
146
147         break;
148       }
149     case 2:                    /* trust info */
150       {
151         debug_print (2, ("trust info: %s\n", p));
152
153         switch (*p) {           /* look only at the first letter */
154         case 'e':
155           flags |= KEYFLAG_EXPIRED;
156           break;
157         case 'r':
158           flags |= KEYFLAG_REVOKED;
159           break;
160         case 'd':
161           flags |= KEYFLAG_DISABLED;
162           break;
163         case 'n':
164           trust = 1;
165           break;
166         case 'm':
167           trust = 2;
168           break;
169         case 'f':
170           trust = 3;
171           break;
172         case 'u':
173           trust = 3;
174           break;
175         }
176
177         if (!is_uid && !(*is_subkey && option (OPTPGPIGNORESUB)))
178           k->flags |= flags;
179
180         break;
181       }
182     case 3:                    /* key length  */
183       {
184
185         debug_print (2, ("key len: %s\n", p));
186
187         if (!(*is_subkey && option (OPTPGPIGNORESUB)))
188           k->keylen = atoi (p); /* fixme: add validation checks */
189         break;
190       }
191     case 4:                    /* pubkey algo */
192       {
193
194         debug_print (2, ("pubkey algorithm: %s\n", p));
195
196         if (!(*is_subkey && option (OPTPGPIGNORESUB))) {
197           k->numalg = atoi (p);
198           k->algorithm = pgp_pkalgbytype (atoi (p));
199         }
200         break;
201       }
202     case 5:                    /* 16 hex digits with the long keyid. */
203       {
204         debug_print (2, ("key id: %s\n", p));
205
206         if (!(*is_subkey && option (OPTPGPIGNORESUB)))
207           m_strreplace(&k->keyid, p);
208         break;
209
210       }
211     case 6:                    /* timestamp (1998-02-28) */
212       {
213         char tstr[11];
214         struct tm st_time;
215
216         debug_print (2, ("time stamp: %s\n", p));
217
218         if (!p)
219           break;
220         st_time.tm_sec = 0;
221         st_time.tm_min = 0;
222         st_time.tm_hour = 12;
223         m_strcpy(tstr, sizeof(tstr), p);
224         tstr[4] = '\0';
225         st_time.tm_year = atoi (tstr) - 1900;
226         tstr[7] = '\0';
227         st_time.tm_mon = (atoi (tstr + 5)) - 1;
228         st_time.tm_mday = atoi (tstr + 8);
229         k->gen_time = mutt_mktime (&st_time, 0);
230         break;
231       }
232     case 7:                    /* valid for n days */
233       break;
234     case 8:                    /* Local id         */
235       break;
236     case 9:                    /* ownertrust       */
237       break;
238     case 10:                   /* name             */
239       {
240         if (!pend || !*p)
241           break;                /* empty field or no trailing colon */
242
243         /* ignore user IDs on subkeys */
244         if (!is_uid && (*is_subkey && option (OPTPGPIGNORESUB)))
245           break;
246
247         debug_print (2, ("user ID: %s\n", p));
248
249         uid = p_new(pgp_uid_t, 1);
250         fix_uid (p);
251         uid->addr = m_strdup(p);
252         uid->trust = trust;
253         uid->flags |= flags;
254         uid->parent = k;
255         uid->next = k->address;
256         k->address = uid;
257
258         if (strstr (p, "ENCR"))
259           k->flags |= KEYFLAG_PREFER_ENCRYPTION;
260         if (strstr (p, "SIGN"))
261           k->flags |= KEYFLAG_PREFER_SIGNING;
262
263         break;
264       }
265     case 11:                   /* signature class  */
266       break;
267     case 12:                   /* key capabilities */
268       debug_print (2, ("capabilities info: %s\n", p));
269
270       while (*p) {
271         switch (*p++) {
272         case 'D':
273           flags |= KEYFLAG_DISABLED;
274           break;
275
276         case 'e':
277           flags |= KEYFLAG_CANENCRYPT;
278           break;
279
280         case 's':
281           flags |= KEYFLAG_CANSIGN;
282           break;
283         }
284       }
285
286       if (!is_uid && (!*is_subkey || !option (OPTPGPIGNORESUB)
287                       || !((flags & KEYFLAG_DISABLED)
288                            || (flags & KEYFLAG_REVOKED)
289                            || (flags & KEYFLAG_EXPIRED))))
290         k->flags |= flags;
291
292       break;
293
294     default:
295       break;
296     }
297   }
298   return k;
299 }
300
301 pgp_key_t pgp_get_candidates (pgp_ring_t keyring, LIST * hints)
302 {
303   FILE *fp;
304   pid_t thepid;
305   char buf[LONG_STRING];
306   pgp_key_t db = NULL, *kend, k = NULL, kk, mainkey = NULL;
307   int is_sub;
308   int devnull;
309
310   if ((devnull = open ("/dev/null", O_RDWR)) == -1)
311     return NULL;
312
313   m_strreplace(&_chs, Charset);
314
315   thepid = pgp_invoke_list_keys (NULL, &fp, NULL, -1, -1, devnull,
316                                  keyring, hints);
317   if (thepid == -1) {
318     close (devnull);
319     return NULL;
320   }
321
322   kend = &db;
323   k = NULL;
324   while (fgets (buf, sizeof (buf) - 1, fp)) {
325     if (!(kk = parse_pub_line (buf, &is_sub, k)))
326       continue;
327
328     /* Only append kk to the list if it's new. */
329     if (kk != k) {
330       if (k)
331         kend = &k->next;
332       *kend = k = kk;
333
334       if (is_sub) {
335         pgp_uid_t **l;
336
337         k->flags |= KEYFLAG_SUBKEY;
338         k->parent = mainkey;
339         for (l = &k->address; *l; l = &(*l)->next);
340         *l = pgp_copy_uids (mainkey->address, k);
341       }
342       else
343         mainkey = k;
344     }
345   }
346
347   if (ferror (fp))
348     mutt_perror ("fgets");
349
350   fclose (fp);
351   mutt_wait_filter (thepid);
352
353   close (devnull);
354
355   return db;
356 }