* keylist.c (gpgme_op_keylist_start): Do not use a verbose listing.
[gpgme.git] / gpgme / keylist.c
1 /* keylist.c -  key listing
2  *      Copyright (C) 2000 Werner Koch (dd9jn)
3  *      Copyright (C) 2001, 2002 g10 Code GmbH
4  *
5  * This file is part of GPGME.
6  *
7  * GPGME is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GPGME is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 #include <assert.h>
28
29 #include "util.h"
30 #include "context.h"
31 #include "ops.h"
32 #include "key.h"
33
34 #define my_isdigit(a) ( (a) >='0' && (a) <= '9' )
35
36 static void finish_key ( GpgmeCtx ctx );
37
38
39 static void
40 keylist_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
41 {
42   if (ctx->error)
43     return;
44
45   switch (code)
46     {
47     case STATUS_EOF:
48       finish_key (ctx);
49       break;
50
51     default:
52       /* Ignore all other codes.  */
53       break;
54     }
55 }
56
57
58 static time_t
59 parse_timestamp (char *p)
60 {
61   if (!*p)
62     return 0;
63
64   return (time_t)strtoul (p, NULL, 10);
65 }
66
67
68 static void
69 set_mainkey_trust_info (GpgmeKey key, const char *s)
70 {
71   /* Look at letters and stop at the first digit.  */
72   for (; *s && !my_isdigit (*s); s++)
73     {
74       switch (*s)
75         {
76         case 'e': key->keys.flags.expired = 1; break;
77         case 'r': key->keys.flags.revoked = 1; break;
78         case 'd': key->keys.flags.disabled = 1; break;
79         case 'i': key->keys.flags.invalid = 1; break;
80         }
81     }
82 }
83
84
85 static void
86 set_userid_flags (GpgmeKey key, const char *s)
87 {
88   /* Look at letters and stop at the first digit.  */
89   for (; *s && !my_isdigit (*s); s++)
90     {
91       switch (*s)
92         {
93         case 'r': key->uids->revoked  = 1; break;
94         case 'i': key->uids->invalid  = 1; break;
95
96         case 'n': key->uids->validity = GPGME_VALIDITY_NEVER; break;
97         case 'm': key->uids->validity = GPGME_VALIDITY_MARGINAL; break;
98         case 'f': key->uids->validity = GPGME_VALIDITY_FULL; break;
99         case 'u': key->uids->validity = GPGME_VALIDITY_ULTIMATE; break;
100         }
101     }
102 }
103
104
105 static void
106 set_subkey_trust_info (struct subkey_s *k, const char *s)
107 {
108   /* Look at letters and stop at the first digit.  */
109   for (; *s && !my_isdigit (*s); s++)
110     {
111       switch (*s)
112         {
113         case 'e': k->flags.expired = 1; break;
114         case 'r': k->flags.revoked = 1; break;
115         case 'd': k->flags.disabled = 1; break;
116         case 'i': k->flags.invalid = 1; break;
117         }
118     }
119 }
120
121
122 static void
123 set_mainkey_capability (GpgmeKey key, const char *s)
124 {
125   for (; *s ; s++)
126     {
127       switch (*s)
128         {
129         case 'e': key->keys.flags.can_encrypt = 1; break;
130         case 's': key->keys.flags.can_sign = 1; break;
131         case 'c': key->keys.flags.can_certify = 1; break;
132         case 'E': key->gloflags.can_encrypt = 1; break;
133         case 'S': key->gloflags.can_sign = 1; break;
134         case 'C': key->gloflags.can_certify = 1; break;
135         }
136     }
137 }
138
139
140 static void
141 set_subkey_capability ( struct subkey_s *k, const char *s)
142 {
143   for (; *s; s++)
144     {
145       switch (*s)
146         {
147         case 'e': k->flags.can_encrypt = 1; break;
148         case 's': k->flags.can_sign = 1; break;
149         case 'c': k->flags.can_certify = 1; break;
150         }
151     }
152 }
153
154
155 /* Note: We are allowed to modify LINE.  */
156 static void
157 keylist_colon_handler (GpgmeCtx ctx, char *line)
158 {
159   char *p, *pend;
160   int field = 0;
161   enum
162     {
163       RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR, RT_SSB, RT_SEC,
164       RT_CRT, RT_CRS
165     }
166   rectype = RT_NONE;
167   GpgmeKey key = ctx->tmp_key;
168   int i;
169   const char *trust_info = NULL;
170   struct subkey_s *sk = NULL;
171
172   if (ctx->error)
173     return;
174   if (!line)
175     {
176       /* EOF */
177       finish_key (ctx);
178       return; 
179     }
180   
181   for (p = line; p; p = pend)
182     {
183       field++;
184       pend = strchr (p, ':');
185       if (pend) 
186         *pend++ = 0;
187
188       if (field == 1)
189         {
190           if (!strcmp (p, "sig"))
191             rectype = RT_SIG;
192           else if (!strcmp (p, "uid") && key)
193             {
194               rectype = RT_UID;
195               key = ctx->tmp_key;
196             }
197           else if (!strcmp (p, "sub") && key)
198             {
199               /* Start a new subkey.  */
200               rectype = RT_SUB; 
201               if (!(sk = _gpgme_key_add_subkey (key)))
202                 {
203                   ctx->error = mk_error (Out_Of_Core);
204                   return;
205                 }
206             }
207           else if (!strcmp (p, "ssb") && key)
208             {
209               /* Start a new secret subkey.  */
210               rectype = RT_SSB;
211               if (!(sk = _gpgme_key_add_secret_subkey (key)))
212                 {
213                   ctx->error = mk_error (Out_Of_Core);
214                   return;
215                 }
216             }
217           else if (!strcmp (p, "pub"))
218             {
219               /* Start a new keyblock.  */
220               if (_gpgme_key_new (&key))
221                 {
222                   ctx->error = mk_error (Out_Of_Core);  /* the only kind of error we can get*/
223                   return;
224                 }
225                 rectype = RT_PUB;
226                 finish_key (ctx);
227                 assert (!ctx->tmp_key);
228                 ctx->tmp_key = key;
229             }
230             else if (!strcmp (p, "sec"))
231               {
232                 /* Start a new keyblock,  */
233                 if (_gpgme_key_new_secret (&key))
234                   {
235                     ctx->error = mk_error (Out_Of_Core);  /* The only kind of error we can get*/
236                     return;
237                 }
238                 rectype = RT_SEC;
239                 finish_key (ctx);
240                 assert (!ctx->tmp_key);
241                 ctx->tmp_key = key;
242             }
243             else if (!strcmp (p, "crt"))
244               {
245                 /* Start a new certificate. */
246                 if (_gpgme_key_new (&key))
247                   {
248                     ctx->error = mk_error (Out_Of_Core);  /* The only kind of error we can get*/
249                     return;
250                 }
251                 key->x509 = 1;
252                 rectype = RT_CRT;
253                 finish_key (ctx);
254                 assert (!ctx->tmp_key);
255                 ctx->tmp_key = key;
256             }
257           else if (!strcmp (p, "crs"))
258             {
259               /* Start a new certificate.  */
260               if (_gpgme_key_new_secret (&key))
261                 {
262                   ctx->error = mk_error (Out_Of_Core);  /* The only kind of error we can get*/
263                   return;
264                 }
265               key->x509 = 1;
266               rectype = RT_CRS;
267               finish_key (ctx);
268               assert (!ctx->tmp_key);
269               ctx->tmp_key = key;
270             }
271           else if (!strcmp (p, "fpr") && key) 
272             rectype = RT_FPR;
273           else 
274             rectype = RT_NONE;
275             
276         }
277       else if (rectype == RT_PUB || rectype == RT_SEC
278                || rectype == RT_CRT || rectype == RT_CRS)
279         {
280           switch (field)
281             {
282             case 2: /* trust info */
283               trust_info = p; 
284               set_mainkey_trust_info (key, trust_info);
285               break;
286             case 3: /* key length */
287               i = atoi (p); 
288               if (i > 1) /* ignore invalid values */
289                 key->keys.key_len = i; 
290                 break;
291             case 4: /* pubkey algo */
292               i = atoi (p);
293               if (i > 1 && i < 128)
294                 key->keys.key_algo = i;
295               break;
296               case 5: /* long keyid */
297                 if (strlen (p) == DIM(key->keys.keyid) - 1)
298                   strcpy (key->keys.keyid, p);
299                 break;
300             case 6: /* timestamp (seconds) */
301               key->keys.timestamp = parse_timestamp (p);
302               break;
303             case 7: /* valid for n days */
304               break;
305             case 8: /* X.509 serial number */
306               /* fixme: store it */
307               break;
308             case 9: /* ownertrust */
309               break;
310             case 10: /* not used for gpg due to --fixed-list-mode option 
311                         but gpgsm stores the issuer name */
312               /* fixme: store issuer name */
313               break;
314             case 11: /* signature class  */
315               break;
316             case 12: /* capabilities */
317               set_mainkey_capability (key, p);
318               break;
319             case 13:
320               pend = NULL;  /* we can stop here */
321               break;
322             }
323           }
324         else if ((rectype == RT_SUB || rectype== RT_SSB) && sk)
325           {
326             switch (field)
327               {
328               case 2: /* trust info */
329                 set_subkey_trust_info (sk, p);
330                 break;
331               case 3: /* key length */
332                 i = atoi (p); 
333                 if (i > 1) /* ignore invalid values */
334                   sk->key_len = i; 
335                 break;
336               case 4: /* pubkey algo */
337                 i = atoi (p);
338                 if (i > 1 && i < 128)
339                   sk->key_algo = i;
340                 break;
341               case 5: /* long keyid */
342                 if (strlen (p) == DIM(sk->keyid) - 1)
343                   strcpy (sk->keyid, p);
344                 break;
345               case 6: /* timestamp (seconds) */
346                 sk->timestamp = parse_timestamp (p);
347                 break;
348               case 7: /* valid for n days */
349                 break;
350               case 8: /* reserved (LID) */
351                 break;
352               case 9: /* ownertrust */
353                 break;
354               case 10:/* user ID n/a for a subkey */
355                 break;
356               case 11:  /* signature class  */
357                 break;
358               case 12: /* capability */
359                 set_subkey_capability (sk, p);
360                 break;
361               case 13:
362                 pend = NULL;  /* we can stop here */
363                 break;
364             }
365         }
366       else if (rectype == RT_UID)
367         {
368           switch (field)
369             {
370             case 2: /* trust info */
371               trust_info = p;  /*save for later */
372               break;
373             case 10: /* user ID */
374               if (_gpgme_key_append_name (key, p))
375                 ctx->error = mk_error (Out_Of_Core);  /* The only kind of error we can get*/
376               else
377                 {
378                   if (trust_info)
379                   set_userid_flags (key, trust_info);
380                 }
381               pend = NULL;  /* we can stop here */
382               break;
383             }
384         }
385       else if (rectype == RT_FPR)
386         {
387           switch (field)
388             {
389             case 10: /* fingerprint (take only the first one)*/
390               if (!key->keys.fingerprint && *p)
391                 {
392                   key->keys.fingerprint = xtrystrdup (p);
393                   if (!key->keys.fingerprint)
394                     ctx->error = mk_error (Out_Of_Core);
395                 }
396               pend = NULL; /* that is all we want */
397               break;
398             }
399         }
400     }
401 }
402
403
404 /*
405  * We have read an entire key into ctx->tmp_key and should now finish
406  * it.  It is assumed that this releases ctx->tmp_key.
407  */
408 static void
409 finish_key (GpgmeCtx ctx)
410 {
411   GpgmeKey key = ctx->tmp_key;
412   struct key_queue_item_s *q, *q2;
413
414   if (key)
415     {
416       ctx->tmp_key = NULL;
417         
418       _gpgme_key_cache_add (key);
419         
420       q = xtrymalloc (sizeof *q);
421       if (!q)
422         {
423           gpgme_key_release (key);
424           ctx->error = mk_error (Out_Of_Core);
425           return;
426         }
427       q->key = key;
428       q->next = NULL;
429       /* FIXME: Lock queue.  Use a tail pointer?  */
430       if (!(q2 = ctx->key_queue))
431         ctx->key_queue = q;
432       else
433         {
434           for (; q2->next; q2 = q2->next)
435             ;
436           q2->next = q;
437         }
438       ctx->key_cond = 1;
439       /* FIXME: Unlock queue.  */
440     }
441 }
442
443
444 /**
445  * gpgme_op_keylist_start:
446  * @c: context 
447  * @pattern: a GnuPG user ID or NULL for all
448  * @secret_only: List only keys where the secret part is available
449  * 
450  * Note that this function also cancels a pending key listing
451  * operaton. To actually retrieve the key, use
452  * gpgme_op_keylist_next().
453  * 
454  * Return value:  0 on success or an errorcode. 
455  **/
456 GpgmeError
457 gpgme_op_keylist_start (GpgmeCtx ctx, const char *pattern, int secret_only)
458 {
459   GpgmeError err = 0;
460
461   if (!ctx)
462     return mk_error (Invalid_Value);
463   ctx->pending = 1;
464
465   _gpgme_release_result (ctx);
466
467   if (ctx->engine)
468     {
469       _gpgme_engine_release (ctx->engine); 
470       ctx->engine = NULL;
471     }
472   gpgme_key_release (ctx->tmp_key);
473   ctx->tmp_key = NULL;
474   /* Fixme: Release key_queue.  */
475     
476   err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
477                            : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
478   if (err)
479     goto leave;
480
481   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
482   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
483                                               keylist_colon_handler, ctx);
484   if (err)
485     goto leave;
486
487   /* We don't want to use the verbose mode as this will also print 
488      the key signatures which is in most cases not needed and furthermore we 
489      just ignore those lines - This should speed up things */
490   _gpgme_engine_set_verbosity (ctx->engine, 0);
491
492   err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only, ctx->keylist_mode);
493
494   if (!err)     /* And kick off the process.  */
495     err = _gpgme_engine_start (ctx->engine, ctx);
496
497  leave:
498   if (err)
499     {
500       ctx->pending = 0; 
501       _gpgme_engine_release (ctx->engine);
502       ctx->engine = NULL;
503     }
504   return err;
505 }
506
507
508 /**
509  * gpgme_op_keylist_next:
510  * @c: Context
511  * @r_key: Returned key object
512  * 
513  * Return the next key from the key listing started with
514  * gpgme_op_keylist_start().  The caller must free the key using
515  * gpgme_key_release().  If the last key has already been returned the
516  * last time the function was called, %GPGME_EOF is returned and the
517  * operation is finished.
518  * 
519  * Return value: 0 on success, %GPGME_EOF or another error code.
520  **/
521 GpgmeError
522 gpgme_op_keylist_next (GpgmeCtx ctx, GpgmeKey *r_key)
523 {
524   struct key_queue_item_s *queue_item;
525
526   if (!r_key)
527     return mk_error (Invalid_Value);
528   *r_key = NULL;
529   if (!ctx)
530     return mk_error (Invalid_Value);
531   if (!ctx->pending)
532     return mk_error (No_Request);
533   if (ctx->error)
534     return ctx->error;
535
536   if (!ctx->key_queue)
537     {
538       _gpgme_wait_on_condition (ctx, 1, &ctx->key_cond);
539       if (ctx->error)
540         return ctx->error;
541       if (!ctx->key_cond)
542         {
543           ctx->pending = 0;
544           return mk_error (EOF);
545         }
546       ctx->key_cond = 0; 
547       assert (ctx->key_queue);
548     }
549   queue_item = ctx->key_queue;
550   ctx->key_queue = queue_item->next;
551   if (!ctx->key_queue)
552     ctx->key_cond = 0;
553   
554   *r_key = queue_item->key;
555   xfree (queue_item);
556   return 0;
557 }
558
559
560 /**
561  * gpgme_op_keylist_end:
562  * @c: Context
563  * 
564  * Ends the keylist operation and allows to use the context for some
565  * other operation next.
566  **/
567 GpgmeError
568 gpgme_op_keylist_end (GpgmeCtx ctx)
569 {
570   if (!ctx)
571     return mk_error (Invalid_Value);
572   if (!ctx->pending)
573     return mk_error (No_Request);
574   if (ctx->error)
575     return ctx->error;
576
577   ctx->pending = 0;
578   return 0;
579 }