* key.h (subkey_s): New member expires_at.
[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: /* expiration time (seconds) */
304               key->keys.expires_at = parse_timestamp (p);
305               break;
306             case 8: /* X.509 serial number */
307               /* fixme: store it */
308               break;
309             case 9: /* ownertrust */
310               break;
311             case 10: /* not used for gpg due to --fixed-list-mode option 
312                         but gpgsm stores the issuer name */
313               /* fixme: store issuer name */
314               break;
315             case 11: /* signature class  */
316               break;
317             case 12: /* capabilities */
318               set_mainkey_capability (key, p);
319               break;
320             case 13:
321               pend = NULL;  /* we can stop here */
322               break;
323             }
324           }
325         else if ((rectype == RT_SUB || rectype== RT_SSB) && sk)
326           {
327             switch (field)
328               {
329               case 2: /* trust info */
330                 set_subkey_trust_info (sk, p);
331                 break;
332               case 3: /* key length */
333                 i = atoi (p); 
334                 if (i > 1) /* ignore invalid values */
335                   sk->key_len = i; 
336                 break;
337               case 4: /* pubkey algo */
338                 i = atoi (p);
339                 if (i > 1 && i < 128)
340                   sk->key_algo = i;
341                 break;
342               case 5: /* long keyid */
343                 if (strlen (p) == DIM(sk->keyid) - 1)
344                   strcpy (sk->keyid, p);
345                 break;
346               case 6: /* timestamp (seconds) */
347                 sk->timestamp = parse_timestamp (p);
348                 break;
349               case 7: /* expiration time (seconds) */
350                 break;
351               case 8: /* reserved (LID) */
352                 break;
353               case 9: /* ownertrust */
354                 break;
355               case 10:/* user ID n/a for a subkey */
356                 break;
357               case 11:  /* signature class  */
358                 break;
359               case 12: /* capability */
360                 set_subkey_capability (sk, p);
361                 break;
362               case 13:
363                 pend = NULL;  /* we can stop here */
364                 break;
365             }
366         }
367       else if (rectype == RT_UID)
368         {
369           switch (field)
370             {
371             case 2: /* trust info */
372               trust_info = p;  /*save for later */
373               break;
374             case 10: /* user ID */
375               if (_gpgme_key_append_name (key, p))
376                 ctx->error = mk_error (Out_Of_Core);  /* The only kind of error we can get*/
377               else
378                 {
379                   if (trust_info)
380                   set_userid_flags (key, trust_info);
381                 }
382               pend = NULL;  /* we can stop here */
383               break;
384             }
385         }
386       else if (rectype == RT_FPR)
387         {
388           switch (field)
389             {
390             case 10: /* fingerprint (take only the first one)*/
391               if (!key->keys.fingerprint && *p)
392                 {
393                   key->keys.fingerprint = xtrystrdup (p);
394                   if (!key->keys.fingerprint)
395                     ctx->error = mk_error (Out_Of_Core);
396                 }
397               pend = NULL; /* that is all we want */
398               break;
399             }
400         }
401     }
402 }
403
404
405 /*
406  * We have read an entire key into ctx->tmp_key and should now finish
407  * it.  It is assumed that this releases ctx->tmp_key.
408  */
409 static void
410 finish_key (GpgmeCtx ctx)
411 {
412   GpgmeKey key = ctx->tmp_key;
413   struct key_queue_item_s *q, *q2;
414
415   if (key)
416     {
417       ctx->tmp_key = NULL;
418         
419       _gpgme_key_cache_add (key);
420         
421       q = xtrymalloc (sizeof *q);
422       if (!q)
423         {
424           gpgme_key_release (key);
425           ctx->error = mk_error (Out_Of_Core);
426           return;
427         }
428       q->key = key;
429       q->next = NULL;
430       /* FIXME: Lock queue.  Use a tail pointer?  */
431       if (!(q2 = ctx->key_queue))
432         ctx->key_queue = q;
433       else
434         {
435           for (; q2->next; q2 = q2->next)
436             ;
437           q2->next = q;
438         }
439       ctx->key_cond = 1;
440       /* FIXME: Unlock queue.  */
441     }
442 }
443
444
445 /**
446  * gpgme_op_keylist_start:
447  * @c: context 
448  * @pattern: a GnuPG user ID or NULL for all
449  * @secret_only: List only keys where the secret part is available
450  * 
451  * Note that this function also cancels a pending key listing
452  * operaton. To actually retrieve the key, use
453  * gpgme_op_keylist_next().
454  * 
455  * Return value:  0 on success or an errorcode. 
456  **/
457 GpgmeError
458 gpgme_op_keylist_start (GpgmeCtx ctx, const char *pattern, int secret_only)
459 {
460   GpgmeError err = 0;
461
462   if (!ctx)
463     return mk_error (Invalid_Value);
464   ctx->pending = 1;
465
466   _gpgme_release_result (ctx);
467
468   if (ctx->engine)
469     {
470       _gpgme_engine_release (ctx->engine); 
471       ctx->engine = NULL;
472     }
473   gpgme_key_release (ctx->tmp_key);
474   ctx->tmp_key = NULL;
475   /* Fixme: Release key_queue.  */
476     
477   err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
478                            : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
479   if (err)
480     goto leave;
481
482   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
483   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
484                                               keylist_colon_handler, ctx);
485   if (err)
486     goto leave;
487
488   /* We don't want to use the verbose mode as this will also print 
489      the key signatures which is in most cases not needed and furthermore we 
490      just ignore those lines - This should speed up things */
491   _gpgme_engine_set_verbosity (ctx->engine, 0);
492
493   err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only, ctx->keylist_mode);
494
495   if (!err)     /* And kick off the process.  */
496     err = _gpgme_engine_start (ctx->engine, ctx);
497
498  leave:
499   if (err)
500     {
501       ctx->pending = 0; 
502       _gpgme_engine_release (ctx->engine);
503       ctx->engine = NULL;
504     }
505   return err;
506 }
507
508
509 /**
510  * gpgme_op_keylist_ext_start:
511  * @c: context 
512  * @pattern: a NULL terminated array of search patterns
513  * @secret_only: List only keys where the secret part is available
514  * @reserved: Should be 0.
515  * 
516  * Note that this function also cancels a pending key listing
517  * operaton. To actually retrieve the key, use
518  * gpgme_op_keylist_next().
519  * 
520  * Return value:  0 on success or an errorcode. 
521  **/
522 GpgmeError
523 gpgme_op_keylist_ext_start (GpgmeCtx ctx, const char *pattern[],
524                             int secret_only, int reserved)
525 {
526   GpgmeError err = 0;
527
528   if (!ctx)
529     return mk_error (Invalid_Value);
530   ctx->pending = 1;
531
532   _gpgme_release_result (ctx);
533
534   if (ctx->engine)
535     {
536       _gpgme_engine_release (ctx->engine); 
537       ctx->engine = NULL;
538     }
539   gpgme_key_release (ctx->tmp_key);
540   ctx->tmp_key = NULL;
541   /* Fixme: Release key_queue.  */
542     
543   err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
544                            : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
545   if (err)
546     goto leave;
547
548   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
549   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
550                                               keylist_colon_handler, ctx);
551   if (err)
552     goto leave;
553
554   /* We don't want to use the verbose mode as this will also print 
555      the key signatures which is in most cases not needed and furthermore we 
556      just ignore those lines - This should speed up things */
557   _gpgme_engine_set_verbosity (ctx->engine, 0);
558
559   err = _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only,
560                                       reserved, ctx->keylist_mode);
561
562   if (!err)     /* And kick off the process.  */
563     err = _gpgme_engine_start (ctx->engine, ctx);
564
565  leave:
566   if (err)
567     {
568       ctx->pending = 0; 
569       _gpgme_engine_release (ctx->engine);
570       ctx->engine = NULL;
571     }
572   return err;
573 }
574
575
576 /**
577  * gpgme_op_keylist_next:
578  * @c: Context
579  * @r_key: Returned key object
580  * 
581  * Return the next key from the key listing started with
582  * gpgme_op_keylist_start().  The caller must free the key using
583  * gpgme_key_release().  If the last key has already been returned the
584  * last time the function was called, %GPGME_EOF is returned and the
585  * operation is finished.
586  * 
587  * Return value: 0 on success, %GPGME_EOF or another error code.
588  **/
589 GpgmeError
590 gpgme_op_keylist_next (GpgmeCtx ctx, GpgmeKey *r_key)
591 {
592   struct key_queue_item_s *queue_item;
593
594   if (!r_key)
595     return mk_error (Invalid_Value);
596   *r_key = NULL;
597   if (!ctx)
598     return mk_error (Invalid_Value);
599   if (!ctx->pending)
600     return mk_error (No_Request);
601   if (ctx->error)
602     return ctx->error;
603
604   if (!ctx->key_queue)
605     {
606       _gpgme_wait_on_condition (ctx, 1, &ctx->key_cond);
607       if (ctx->error)
608         return ctx->error;
609       if (!ctx->key_cond)
610         {
611           ctx->pending = 0;
612           return mk_error (EOF);
613         }
614       ctx->key_cond = 0; 
615       assert (ctx->key_queue);
616     }
617   queue_item = ctx->key_queue;
618   ctx->key_queue = queue_item->next;
619   if (!ctx->key_queue)
620     ctx->key_cond = 0;
621   
622   *r_key = queue_item->key;
623   xfree (queue_item);
624   return 0;
625 }
626
627
628 /**
629  * gpgme_op_keylist_end:
630  * @c: Context
631  * 
632  * Ends the keylist operation and allows to use the context for some
633  * other operation next.
634  **/
635 GpgmeError
636 gpgme_op_keylist_end (GpgmeCtx ctx)
637 {
638   if (!ctx)
639     return mk_error (Invalid_Value);
640   if (!ctx->pending)
641     return mk_error (No_Request);
642   if (ctx->error)
643     return ctx->error;
644
645   ctx->pending = 0;
646   return 0;
647 }