* gpgsm/t-encrypt.c (main): Add a simple option parser and allow
[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 static void
155 set_ownertrust (GpgmeKey key, const char *s)
156 {
157   /* Look at letters and stop at the first digit.  */
158   for (; *s && !my_isdigit (*s); s++)
159     {
160       switch (*s)
161         {
162         case 'n': key->otrust = GPGME_VALIDITY_NEVER; break;
163         case 'm': key->otrust = GPGME_VALIDITY_MARGINAL; break;
164         case 'f': key->otrust = GPGME_VALIDITY_FULL; break;
165         case 'u': key->otrust = GPGME_VALIDITY_ULTIMATE; break;
166         default : key->otrust = GPGME_VALIDITY_UNKNOWN; break;
167         }
168     }
169 }
170
171
172 /* Note: We are allowed to modify LINE.  */
173 static void
174 keylist_colon_handler (GpgmeCtx ctx, char *line)
175 {
176   char *p, *pend;
177   int field = 0;
178   enum
179     {
180       RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR, RT_SSB, RT_SEC,
181       RT_CRT, RT_CRS
182     }
183   rectype = RT_NONE;
184   GpgmeKey key = ctx->tmp_key;
185   int i;
186   const char *trust_info = NULL;
187   struct subkey_s *sk = NULL;
188
189   if (ctx->error)
190     return;
191   if (!line)
192     {
193       /* EOF */
194       finish_key (ctx);
195       return; 
196     }
197   
198   for (p = line; p; p = pend)
199     {
200       field++;
201       pend = strchr (p, ':');
202       if (pend) 
203         *pend++ = 0;
204
205       if (field == 1)
206         {
207           if (!strcmp (p, "sig"))
208             rectype = RT_SIG;
209           else if (!strcmp (p, "uid") && key)
210             {
211               rectype = RT_UID;
212               key = ctx->tmp_key;
213             }
214           else if (!strcmp (p, "sub") && key)
215             {
216               /* Start a new subkey.  */
217               rectype = RT_SUB; 
218               if (!(sk = _gpgme_key_add_subkey (key)))
219                 {
220                   ctx->error = mk_error (Out_Of_Core);
221                   return;
222                 }
223             }
224           else if (!strcmp (p, "ssb") && key)
225             {
226               /* Start a new secret subkey.  */
227               rectype = RT_SSB;
228               if (!(sk = _gpgme_key_add_secret_subkey (key)))
229                 {
230                   ctx->error = mk_error (Out_Of_Core);
231                   return;
232                 }
233             }
234           else if (!strcmp (p, "pub"))
235             {
236               /* Start a new keyblock.  */
237               if (_gpgme_key_new (&key))
238                 {
239                   ctx->error = mk_error (Out_Of_Core);  /* the only kind of error we can get*/
240                   return;
241                 }
242                 rectype = RT_PUB;
243                 finish_key (ctx);
244                 assert (!ctx->tmp_key);
245                 ctx->tmp_key = key;
246             }
247             else if (!strcmp (p, "sec"))
248               {
249                 /* Start a new keyblock,  */
250                 if (_gpgme_key_new_secret (&key))
251                   {
252                     ctx->error = mk_error (Out_Of_Core);  /* The only kind of error we can get*/
253                     return;
254                 }
255                 rectype = RT_SEC;
256                 finish_key (ctx);
257                 assert (!ctx->tmp_key);
258                 ctx->tmp_key = key;
259             }
260             else if (!strcmp (p, "crt"))
261               {
262                 /* Start a new certificate. */
263                 if (_gpgme_key_new (&key))
264                   {
265                     ctx->error = mk_error (Out_Of_Core);  /* The only kind of error we can get*/
266                     return;
267                 }
268                 key->x509 = 1;
269                 rectype = RT_CRT;
270                 finish_key (ctx);
271                 assert (!ctx->tmp_key);
272                 ctx->tmp_key = key;
273             }
274           else if (!strcmp (p, "crs"))
275             {
276               /* Start a new certificate.  */
277               if (_gpgme_key_new_secret (&key))
278                 {
279                   ctx->error = mk_error (Out_Of_Core);  /* The only kind of error we can get*/
280                   return;
281                 }
282               key->x509 = 1;
283               rectype = RT_CRS;
284               finish_key (ctx);
285               assert (!ctx->tmp_key);
286               ctx->tmp_key = key;
287             }
288           else if (!strcmp (p, "fpr") && key) 
289             rectype = RT_FPR;
290           else 
291             rectype = RT_NONE;
292             
293         }
294       else if (rectype == RT_PUB || rectype == RT_SEC
295                || rectype == RT_CRT || rectype == RT_CRS)
296         {
297           switch (field)
298             {
299             case 2: /* trust info */
300               trust_info = p; 
301               set_mainkey_trust_info (key, trust_info);
302               break;
303             case 3: /* key length */
304               i = atoi (p); 
305               if (i > 1) /* ignore invalid values */
306                 key->keys.key_len = i; 
307                 break;
308             case 4: /* pubkey algo */
309               i = atoi (p);
310               if (i > 1 && i < 128)
311                 key->keys.key_algo = i;
312               break;
313               case 5: /* long keyid */
314                 if (strlen (p) == DIM(key->keys.keyid) - 1)
315                   strcpy (key->keys.keyid, p);
316                 break;
317             case 6: /* timestamp (seconds) */
318               key->keys.timestamp = parse_timestamp (p);
319               break;
320             case 7: /* expiration time (seconds) */
321               key->keys.expires_at = parse_timestamp (p);
322               break;
323             case 8: /* X.509 serial number */
324               if (rectype == RT_CRT)
325                 {
326                   key->issuer_serial = xtrystrdup (p);
327                   if (!key->issuer_serial)
328                     ctx->error = mk_error (Out_Of_Core);
329                 }
330               break;
331             case 9: /* ownertrust */
332               set_ownertrust (key, p);
333               break;
334             case 10: /* not used for gpg due to --fixed-list-mode option 
335                         but gpgsm stores the issuer name */
336               if (rectype == RT_CRT)
337                 {
338                   key->issuer_name = xtrystrdup (p);
339                   if (!key->issuer_name)
340                     ctx->error = mk_error (Out_Of_Core);
341                 }
342               break;
343             case 11: /* signature class  */
344               break;
345             case 12: /* capabilities */
346               set_mainkey_capability (key, p);
347               break;
348             case 13:
349               pend = NULL;  /* we can stop here */
350               break;
351             }
352           }
353         else if ((rectype == RT_SUB || rectype== RT_SSB) && sk)
354           {
355             switch (field)
356               {
357               case 2: /* trust info */
358                 set_subkey_trust_info (sk, p);
359                 break;
360               case 3: /* key length */
361                 i = atoi (p); 
362                 if (i > 1) /* ignore invalid values */
363                   sk->key_len = i; 
364                 break;
365               case 4: /* pubkey algo */
366                 i = atoi (p);
367                 if (i > 1 && i < 128)
368                   sk->key_algo = i;
369                 break;
370               case 5: /* long keyid */
371                 if (strlen (p) == DIM(sk->keyid) - 1)
372                   strcpy (sk->keyid, p);
373                 break;
374               case 6: /* timestamp (seconds) */
375                 sk->timestamp = parse_timestamp (p);
376                 break;
377               case 7: /* expiration time (seconds) */
378                 break;
379               case 8: /* reserved (LID) */
380                 break;
381               case 9: /* ownertrust */
382                 break;
383               case 10:/* user ID n/a for a subkey */
384                 break;
385               case 11:  /* signature class  */
386                 break;
387               case 12: /* capability */
388                 set_subkey_capability (sk, p);
389                 break;
390               case 13:
391                 pend = NULL;  /* we can stop here */
392                 break;
393             }
394         }
395       else if (rectype == RT_UID)
396         {
397           switch (field)
398             {
399             case 2: /* trust info */
400               trust_info = p;  /*save for later */
401               break;
402             case 10: /* user ID */
403               if (_gpgme_key_append_name (key, p))
404                 ctx->error = mk_error (Out_Of_Core);  /* The only kind of error we can get*/
405               else
406                 {
407                   if (trust_info)
408                   set_userid_flags (key, trust_info);
409                 }
410               pend = NULL;  /* we can stop here */
411               break;
412             }
413         }
414       else if (rectype == RT_FPR)
415         {
416           switch (field)
417             {
418             case 10: /* fingerprint (take only the first one)*/
419               if (!key->keys.fingerprint && *p)
420                 {
421                   key->keys.fingerprint = xtrystrdup (p);
422                   if (!key->keys.fingerprint)
423                     ctx->error = mk_error (Out_Of_Core);
424                 }
425               break;
426             case 13: /* gpgsm chain ID (take only the first one)*/
427               if (!key->chain_id && *p)
428                 {
429                   key->chain_id = xtrystrdup (p);
430                   if (!key->chain_id)
431                     ctx->error = mk_error (Out_Of_Core);
432                 }
433               pend = NULL; /* that is all we want */
434               break;
435             }
436         }
437     }
438 }
439
440
441 /*
442  * We have read an entire key into ctx->tmp_key and should now finish
443  * it.  It is assumed that this releases ctx->tmp_key.
444  */
445 static void
446 finish_key (GpgmeCtx ctx)
447 {
448   GpgmeKey key = ctx->tmp_key;
449   struct key_queue_item_s *q, *q2;
450
451   if (key)
452     {
453       ctx->tmp_key = NULL;
454         
455       _gpgme_key_cache_add (key);
456         
457       q = xtrymalloc (sizeof *q);
458       if (!q)
459         {
460           gpgme_key_release (key);
461           ctx->error = mk_error (Out_Of_Core);
462           return;
463         }
464       q->key = key;
465       q->next = NULL;
466       /* FIXME: Lock queue.  Use a tail pointer?  */
467       if (!(q2 = ctx->key_queue))
468         ctx->key_queue = q;
469       else
470         {
471           for (; q2->next; q2 = q2->next)
472             ;
473           q2->next = q;
474         }
475       ctx->key_cond = 1;
476       /* FIXME: Unlock queue.  */
477     }
478 }
479
480
481 /**
482  * gpgme_op_keylist_start:
483  * @c: context 
484  * @pattern: a GnuPG user ID or NULL for all
485  * @secret_only: List only keys where the secret part is available
486  * 
487  * Note that this function also cancels a pending key listing
488  * operaton. To actually retrieve the key, use
489  * gpgme_op_keylist_next().
490  * 
491  * Return value:  0 on success or an errorcode. 
492  **/
493 GpgmeError
494 gpgme_op_keylist_start (GpgmeCtx ctx, const char *pattern, int secret_only)
495 {
496   GpgmeError err = 0;
497
498   if (!ctx)
499     return mk_error (Invalid_Value);
500   ctx->pending = 1;
501
502   _gpgme_release_result (ctx);
503
504   if (ctx->engine)
505     {
506       _gpgme_engine_release (ctx->engine); 
507       ctx->engine = NULL;
508     }
509   gpgme_key_release (ctx->tmp_key);
510   ctx->tmp_key = NULL;
511   /* Fixme: Release key_queue.  */
512     
513   err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
514                            : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
515   if (err)
516     goto leave;
517
518   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
519   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
520                                               keylist_colon_handler, ctx);
521   if (err)
522     goto leave;
523
524   /* We don't want to use the verbose mode as this will also print 
525      the key signatures which is in most cases not needed and furthermore we 
526      just ignore those lines - This should speed up things */
527   _gpgme_engine_set_verbosity (ctx->engine, 0);
528
529   err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only, ctx->keylist_mode);
530
531   if (!err)     /* And kick off the process.  */
532     err = _gpgme_engine_start (ctx->engine, ctx);
533
534  leave:
535   if (err)
536     {
537       ctx->pending = 0; 
538       _gpgme_engine_release (ctx->engine);
539       ctx->engine = NULL;
540     }
541   return err;
542 }
543
544
545 /**
546  * gpgme_op_keylist_ext_start:
547  * @c: context 
548  * @pattern: a NULL terminated array of search patterns
549  * @secret_only: List only keys where the secret part is available
550  * @reserved: Should be 0.
551  * 
552  * Note that this function also cancels a pending key listing
553  * operaton. To actually retrieve the key, use
554  * gpgme_op_keylist_next().
555  * 
556  * Return value:  0 on success or an errorcode. 
557  **/
558 GpgmeError
559 gpgme_op_keylist_ext_start (GpgmeCtx ctx, const char *pattern[],
560                             int secret_only, int reserved)
561 {
562   GpgmeError err = 0;
563
564   if (!ctx)
565     return mk_error (Invalid_Value);
566   ctx->pending = 1;
567
568   _gpgme_release_result (ctx);
569
570   if (ctx->engine)
571     {
572       _gpgme_engine_release (ctx->engine); 
573       ctx->engine = NULL;
574     }
575   gpgme_key_release (ctx->tmp_key);
576   ctx->tmp_key = NULL;
577   /* Fixme: Release key_queue.  */
578     
579   err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
580                            : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
581   if (err)
582     goto leave;
583
584   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
585   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
586                                               keylist_colon_handler, ctx);
587   if (err)
588     goto leave;
589
590   /* We don't want to use the verbose mode as this will also print 
591      the key signatures which is in most cases not needed and furthermore we 
592      just ignore those lines - This should speed up things */
593   _gpgme_engine_set_verbosity (ctx->engine, 0);
594
595   err = _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only,
596                                       reserved, ctx->keylist_mode);
597
598   if (!err)     /* And kick off the process.  */
599     err = _gpgme_engine_start (ctx->engine, ctx);
600
601  leave:
602   if (err)
603     {
604       ctx->pending = 0; 
605       _gpgme_engine_release (ctx->engine);
606       ctx->engine = NULL;
607     }
608   return err;
609 }
610
611
612 /**
613  * gpgme_op_keylist_next:
614  * @c: Context
615  * @r_key: Returned key object
616  * 
617  * Return the next key from the key listing started with
618  * gpgme_op_keylist_start().  The caller must free the key using
619  * gpgme_key_release().  If the last key has already been returned the
620  * last time the function was called, %GPGME_EOF is returned and the
621  * operation is finished.
622  * 
623  * Return value: 0 on success, %GPGME_EOF or another error code.
624  **/
625 GpgmeError
626 gpgme_op_keylist_next (GpgmeCtx ctx, GpgmeKey *r_key)
627 {
628   struct key_queue_item_s *queue_item;
629
630   if (!r_key)
631     return mk_error (Invalid_Value);
632   *r_key = NULL;
633   if (!ctx)
634     return mk_error (Invalid_Value);
635   if (!ctx->pending)
636     return mk_error (No_Request);
637   if (ctx->error)
638     return ctx->error;
639
640   if (!ctx->key_queue)
641     {
642       _gpgme_wait_on_condition (ctx, 1, &ctx->key_cond);
643       if (ctx->error)
644         return ctx->error;
645       if (!ctx->key_cond)
646         {
647           ctx->pending = 0;
648           return mk_error (EOF);
649         }
650       ctx->key_cond = 0; 
651       assert (ctx->key_queue);
652     }
653   queue_item = ctx->key_queue;
654   ctx->key_queue = queue_item->next;
655   if (!ctx->key_queue)
656     ctx->key_cond = 0;
657   
658   *r_key = queue_item->key;
659   xfree (queue_item);
660   return 0;
661 }
662
663
664 /**
665  * gpgme_op_keylist_end:
666  * @c: Context
667  * 
668  * Ends the keylist operation and allows to use the context for some
669  * other operation next.
670  **/
671 GpgmeError
672 gpgme_op_keylist_end (GpgmeCtx ctx)
673 {
674   if (!ctx)
675     return mk_error (Invalid_Value);
676   if (!ctx->pending)
677     return mk_error (No_Request);
678   if (ctx->error)
679     return ctx->error;
680
681   ctx->pending = 0;
682   return 0;
683 }