2009-11-10 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / src / keylist.c
1 /* keylist.c - Listing keys.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007,
4                  2008, 2009  g10 Code GmbH
5
6    This file is part of GPGME.
7  
8    GPGME is free software; you can redistribute it and/or modify it
9    under the terms of the GNU Lesser General Public License as
10    published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12    
13    GPGME is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17    
18    You should have received a copy of the GNU Lesser General Public
19    License along with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #if HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 /* Solaris 8 needs sys/types.h before time.h.  */
29 #include <sys/types.h>
30 #include <time.h>
31 #include <assert.h>
32 #include <ctype.h>
33 #include <errno.h>
34
35 /* Suppress warning for accessing deprecated member "class".  */
36 #define _GPGME_IN_GPGME
37 #include "gpgme.h"
38 #include "util.h"
39 #include "context.h"
40 #include "ops.h"
41 #include "debug.h"
42
43 \f
44 struct key_queue_item_s
45 {
46   struct key_queue_item_s *next;
47   gpgme_key_t key;
48 };
49
50 typedef struct
51 {
52   struct _gpgme_op_keylist_result result;
53
54   gpgme_key_t tmp_key;
55
56   /* This points to the last uid in tmp_key.  */
57   gpgme_user_id_t tmp_uid;
58
59   /* This points to the last sig in tmp_uid.  */
60   gpgme_key_sig_t tmp_keysig;
61
62   /* Something new is available.  */
63   int key_cond;
64   struct key_queue_item_s *key_queue;
65 } *op_data_t;
66
67
68 static void
69 release_op_data (void *hook)
70 {
71   op_data_t opd = (op_data_t) hook;
72   struct key_queue_item_s *key = opd->key_queue;
73
74   if (opd->tmp_key)
75     gpgme_key_unref (opd->tmp_key);
76
77   /* opd->tmp_uid and opd->tmp_keysig are actually part of opd->tmp_key,
78      so we do not need to release them here.  */
79
80   while (key)
81     {
82       struct key_queue_item_s *next = key->next;
83
84       gpgme_key_unref (key->key);
85       key = next;
86     }
87 }
88
89
90 gpgme_keylist_result_t
91 gpgme_op_keylist_result (gpgme_ctx_t ctx)
92 {
93   void *hook;
94   op_data_t opd;
95   gpgme_error_t err;
96
97   TRACE_BEG (DEBUG_CTX, "gpgme_op_keylist_result", ctx);
98
99   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
100   opd = hook;
101   if (err || !opd)
102     {
103       TRACE_SUC0 ("result=(null)");
104       return NULL;
105     }
106
107   TRACE_LOG1 ("truncated = %i", opd->result.truncated);
108
109   TRACE_SUC1 ("result=%p", &opd->result);
110   return &opd->result;
111 }
112
113 \f
114 static gpgme_error_t
115 keylist_status_handler (void *priv, gpgme_status_code_t code, char *args)
116 {
117   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
118   gpgme_error_t err;
119   void *hook;
120   op_data_t opd;
121
122   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
123   opd = hook;
124   if (err)
125     return err;
126
127   switch (code)
128     {
129     case GPGME_STATUS_TRUNCATED:
130       opd->result.truncated = 1;
131       break;
132
133     default:
134       break;
135     }
136   return 0;
137 }
138
139 \f
140 static void
141 set_subkey_trust_info (gpgme_subkey_t subkey, const char *src)
142 {
143   while (*src && !isdigit (*src))
144     {
145       switch (*src)
146         {
147         case 'e':
148           subkey->expired = 1;
149           break;
150
151         case 'r':
152           subkey->revoked = 1;
153           break;
154
155         case 'd':
156           /* Note that gpg 1.3 won't print that anymore but only uses
157              the capabilities field. */
158           subkey->disabled = 1;
159           break;
160
161         case 'i':
162           subkey->invalid = 1;
163           break;
164         }
165       src++;
166     }
167 }
168
169
170 static void
171 set_mainkey_trust_info (gpgme_key_t key, const char *src)
172 {
173   /* First set the trust info of the main key (the first subkey).  */
174   set_subkey_trust_info (key->subkeys, src);
175
176   /* Now set the summarized trust info.  */
177   while (*src && !isdigit (*src))
178     {
179       switch (*src)
180         {
181         case 'e':
182           key->expired = 1;
183           break;
184
185         case 'r':
186           key->revoked = 1;
187           break;
188
189         case 'd':
190           /* Note that gpg 1.3 won't print that anymore but only uses
191              the capabilities field.  However, it is still used for
192              external key listings.  */
193           key->disabled = 1;
194           break;
195
196         case 'i':
197           key->invalid = 1;
198           break;
199         }
200       src++;
201     }
202 }
203
204
205 static void
206 set_userid_flags (gpgme_key_t key, const char *src)
207 {
208   gpgme_user_id_t uid = key->_last_uid;
209
210   assert (uid);
211   /* Look at letters and stop at the first digit.  */
212   while (*src && !isdigit (*src))
213     {
214       switch (*src)
215         {
216         case 'r':
217           uid->revoked = 1;
218           break;
219           
220         case 'i':
221           uid->invalid = 1;
222           break;
223
224         case 'n':
225           uid->validity = GPGME_VALIDITY_NEVER;
226           break;
227
228         case 'm':
229           uid->validity = GPGME_VALIDITY_MARGINAL;
230           break;
231
232         case 'f':
233           uid->validity = GPGME_VALIDITY_FULL;
234           break;
235
236         case 'u':
237           uid->validity = GPGME_VALIDITY_ULTIMATE;
238           break;
239         }
240       src++;
241     }
242 }
243
244
245 static void
246 set_subkey_capability (gpgme_subkey_t subkey, const char *src)
247 {
248   while (*src)
249     {
250       switch (*src)
251         {
252         case 'e':
253           subkey->can_encrypt = 1;
254           break;
255
256         case 's':
257           subkey->can_sign = 1;
258           break;
259
260         case 'c':
261           subkey->can_certify = 1;
262           break;
263
264         case 'a':
265           subkey->can_authenticate = 1;
266           break;
267
268         case 'q':
269           subkey->is_qualified = 1;
270           break;
271
272         case 'd':
273           subkey->disabled = 1;
274           break;
275         }
276       src++;
277     }
278 }
279
280
281 static void
282 set_mainkey_capability (gpgme_key_t key, const char *src)
283 {
284   /* First set the capabilities of the main key (the first subkey).  */
285   set_subkey_capability (key->subkeys, src);
286
287   while (*src)
288     {
289       switch (*src)
290         {
291         case 'd':
292         case 'D':
293           /* Note, that this flag is also set using the key validity
294              field for backward compatibility with gpg 1.2.  We use d
295              and D, so that a future gpg version will be able to
296              disable certain subkeys. Currently it is expected that
297              gpg sets this for the primary key. */
298           key->disabled = 1;
299           break;
300
301         case 'e':
302         case 'E':
303           key->can_encrypt = 1;
304           break;
305
306         case 's':
307         case 'S':
308           key->can_sign = 1;
309           break;
310
311         case 'c':
312         case 'C':
313           key->can_certify = 1;
314           break;
315
316         case 'a':
317         case 'A':
318           key->can_authenticate = 1;
319           break;
320
321         case 'q':
322         case 'Q':
323           key->is_qualified = 1;
324           break;
325         }
326       src++;
327     }
328 }
329
330
331 static void
332 set_ownertrust (gpgme_key_t key, const char *src)
333 {
334   /* Look at letters and stop at the first digit.  */
335   while (*src && !isdigit (*src))
336     {
337       switch (*src)
338         {
339         case 'n':
340           key->owner_trust = GPGME_VALIDITY_NEVER;
341           break;
342
343         case 'm':
344           key->owner_trust = GPGME_VALIDITY_MARGINAL;
345           break;
346
347         case 'f':
348           key->owner_trust = GPGME_VALIDITY_FULL;
349           break;
350
351         case 'u':
352           key->owner_trust = GPGME_VALIDITY_ULTIMATE;
353           break;
354
355         default:
356           key->owner_trust = GPGME_VALIDITY_UNKNOWN;
357           break;
358         }
359       src++;
360     }
361 }
362
363
364 /* Parse field 15 of a secret key or subkey.  This fields holds a
365    reference to smartcards.  FIELD is the content of the field and we
366    are allowed to modify it.  */
367 static gpg_error_t
368 parse_sec_field15 (gpgme_subkey_t subkey, char *field)
369 {
370   if (!*field)
371     ; /* Empty.  */
372   else if (*field == '#')
373     {
374       /* This is a stub for an offline key.  We reset the SECRET flag
375          of the subkey here.  Note that the secret flag of the entire
376          key will be true even then.  */
377       subkey->secret = 0;
378     }
379   else if (strchr ("01234567890ABCDEFabcdef", *field))
380     {
381       /* Fields starts with a hex digit; thus it is a serial number.  */
382       subkey->is_cardkey = 1;
383       subkey->card_number = strdup (field);
384       if (!subkey->card_number)
385         return gpg_error_from_syserror ();
386     }
387   else
388     {
389       /* RFU.  */
390     }
391
392   return 0;
393 }
394
395
396 /* We have read an entire key into tmp_key and should now finish it.
397    It is assumed that this releases tmp_key.  */
398 static void
399 finish_key (gpgme_ctx_t ctx, op_data_t opd)
400 {
401   gpgme_key_t key = opd->tmp_key;
402
403   opd->tmp_key = NULL;
404   opd->tmp_uid = NULL;
405   opd->tmp_keysig = NULL;
406
407   if (key)
408     _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_KEY, key);
409 }
410
411
412 /* Note: We are allowed to modify LINE.  */
413 static gpgme_error_t
414 keylist_colon_handler (void *priv, char *line)
415 {
416   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
417   enum
418     {
419       RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR,
420       RT_SSB, RT_SEC, RT_CRT, RT_CRS, RT_REV, RT_SPK
421     }
422   rectype = RT_NONE;
423 #define NR_FIELDS 16
424   char *field[NR_FIELDS];
425   int fields = 0;
426   void *hook;
427   op_data_t opd;
428   gpgme_error_t err;
429   gpgme_key_t key;
430   gpgme_subkey_t subkey = NULL;
431   gpgme_key_sig_t keysig = NULL;
432
433   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
434   opd = hook;
435   if (err)
436     return err;
437
438   key = opd->tmp_key;
439
440   TRACE2 (DEBUG_CTX, "gpgme:keylist_colon_handler", ctx,
441           "key = %p, line = %s", key, line ? line : "(null)");
442
443   if (!line)
444     {
445       /* End Of File.  */
446       finish_key (ctx, opd);
447       return 0;
448     }
449
450   while (line && fields < NR_FIELDS)
451     {
452       field[fields++] = line;
453       line = strchr (line, ':');
454       if (line)
455         *(line++) = '\0';
456     }
457
458   if (!strcmp (field[0], "sig"))
459     rectype = RT_SIG;
460   else if (!strcmp (field[0], "rev"))
461     rectype = RT_REV;
462   else if (!strcmp (field[0], "pub"))
463     rectype = RT_PUB;
464   else if (!strcmp (field[0], "sec"))
465     rectype = RT_SEC;
466   else if (!strcmp (field[0], "crt"))
467     rectype = RT_CRT;
468   else if (!strcmp (field[0], "crs"))
469     rectype = RT_CRS;
470   else if (!strcmp (field[0], "fpr") && key) 
471     rectype = RT_FPR;
472   else if (!strcmp (field[0], "uid") && key)
473     rectype = RT_UID;
474   else if (!strcmp (field[0], "sub") && key)
475     rectype = RT_SUB; 
476   else if (!strcmp (field[0], "ssb") && key)
477     rectype = RT_SSB;
478   else if (!strcmp (field[0], "spk") && key)
479     rectype = RT_SPK;
480   else 
481     rectype = RT_NONE;
482
483   /* Only look at signatures immediately following a user ID.  For
484      this, clear the user ID pointer when encountering anything but a
485      signature.  */
486   if (rectype != RT_SIG && rectype != RT_REV)
487     opd->tmp_uid = NULL;
488
489   /* Only look at subpackets immediately following a signature.  For
490      this, clear the signature pointer when encountering anything but
491      a subpacket.  */
492   if (rectype != RT_SPK)
493     opd->tmp_keysig = NULL;
494
495   switch (rectype)
496     {
497     case RT_PUB:
498     case RT_SEC:
499     case RT_CRT:
500     case RT_CRS:
501       /* Start a new keyblock.  */
502       err = _gpgme_key_new (&key);
503       if (err)
504         return err;
505       key->keylist_mode = ctx->keylist_mode;
506       err = _gpgme_key_add_subkey (key, &subkey);
507       if (err)
508         {
509           gpgme_key_unref (key);
510           return err;
511         }
512
513       if (rectype == RT_SEC || rectype == RT_CRS)
514         key->secret = subkey->secret = 1;
515       if (rectype == RT_CRT || rectype == RT_CRS)
516         key->protocol = GPGME_PROTOCOL_CMS;
517       finish_key (ctx, opd);
518       opd->tmp_key = key;
519
520       /* Field 2 has the trust info.  */
521       if (fields >= 2)
522         set_mainkey_trust_info (key, field[1]);
523
524       /* Field 3 has the key length.  */
525       if (fields >= 3)
526         {
527           int i = atoi (field[2]);
528           /* Ignore invalid values.  */
529           if (i > 1)
530             subkey->length = i; 
531         }
532
533       /* Field 4 has the public key algorithm.  */
534       if (fields >= 4)
535         {
536           int i = atoi (field[3]);
537           if (i >= 1 && i < 128)
538             subkey->pubkey_algo = i;
539         }
540
541       /* Field 5 has the long keyid.  Allow short key IDs for the
542          output of an external keyserver listing.  */
543       if (fields >= 5 && strlen (field[4]) <= DIM(subkey->_keyid) - 1)
544         strcpy (subkey->_keyid, field[4]);
545
546       /* Field 6 has the timestamp (seconds).  */
547       if (fields >= 6)
548         subkey->timestamp = _gpgme_parse_timestamp (field[5], NULL);
549
550       /* Field 7 has the expiration time (seconds).  */
551       if (fields >= 7)
552         subkey->expires = _gpgme_parse_timestamp (field[6], NULL);
553
554       /* Field 8 has the X.509 serial number.  */
555       if (fields >= 8 && (rectype == RT_CRT || rectype == RT_CRS))
556         {
557           key->issuer_serial = strdup (field[7]);
558           if (!key->issuer_serial)
559             return gpg_error_from_errno (errno);
560         }
561           
562       /* Field 9 has the ownertrust.  */
563       if (fields >= 9)
564         set_ownertrust (key, field[8]);
565
566       /* Field 10 is not used for gpg due to --fixed-list-mode option
567          but GPGSM stores the issuer name.  */
568       if (fields >= 10 && (rectype == RT_CRT || rectype == RT_CRS))
569         if (_gpgme_decode_c_string (field[9], &key->issuer_name, 0))
570           return gpg_error (GPG_ERR_ENOMEM);    /* FIXME */
571
572       /* Field 11 has the signature class.  */
573
574       /* Field 12 has the capabilities.  */
575       if (fields >= 12)
576         set_mainkey_capability (key, field[11]);
577
578       /* Field 15 carries special flags of a secret key.  */
579       if (fields >= 15 && key->secret)
580         {
581           err = parse_sec_field15 (subkey, field[14]);
582           if (err)
583             return err;
584         }
585       break;
586
587     case RT_SUB:
588     case RT_SSB:
589       /* Start a new subkey.  */
590       err = _gpgme_key_add_subkey (key, &subkey);
591       if (err)
592         return err;
593
594       if (rectype == RT_SSB)
595         subkey->secret = 1;
596
597       /* Field 2 has the trust info.  */
598       if (fields >= 2)
599         set_subkey_trust_info (subkey, field[1]);
600
601       /* Field 3 has the key length.  */
602       if (fields >= 3)
603         {
604           int i = atoi (field[2]);
605           /* Ignore invalid values.  */
606           if (i > 1)
607             subkey->length = i;
608         }
609
610       /* Field 4 has the public key algorithm.  */
611       if (fields >= 4)
612         {
613           int i = atoi (field[3]);
614           if (i >= 1 && i < 128)
615             subkey->pubkey_algo = i;
616         }
617
618       /* Field 5 has the long keyid.  */
619       if (fields >= 5 && strlen (field[4]) == DIM(subkey->_keyid) - 1)
620         strcpy (subkey->_keyid, field[4]);
621
622       /* Field 6 has the timestamp (seconds).  */
623       if (fields >= 6)
624         subkey->timestamp = _gpgme_parse_timestamp (field[5], NULL);
625
626       /* Field 7 has the expiration time (seconds).  */
627       if (fields >= 7)
628         subkey->expires = _gpgme_parse_timestamp (field[6], NULL);
629
630       /* Field 8 is reserved (LID).  */
631       /* Field 9 has the ownertrust.  */
632       /* Field 10, the user ID, is n/a for a subkey.  */
633       
634       /* Field 11 has the signature class.  */
635
636       /* Field 12 has the capabilities.  */
637       if (fields >= 12)
638         set_subkey_capability (subkey, field[11]);
639
640       /* Field 15 carries special flags of a secret key. */
641       if (fields >= 15 && key->secret)
642         {
643           err = parse_sec_field15 (subkey, field[14]);
644           if (err)
645             return err;
646         }
647       break;
648
649     case RT_UID:
650       /* Field 2 has the trust info, and field 10 has the user ID.  */
651       if (fields >= 10)
652         {
653           if (_gpgme_key_append_name (key, field[9], 1))
654             return gpg_error_from_errno (GPG_ERR_ENOMEM);       /* FIXME */
655           else
656             {
657               if (field[1])
658                 set_userid_flags (key, field[1]);
659               opd->tmp_uid = key->_last_uid;
660             }
661         }
662       break;
663
664     case RT_FPR:
665       /* Field 10 has the fingerprint (take only the first one).  */
666       if (fields >= 10 && field[9] && *field[9])
667         {
668           /* Need to apply it to the last subkey because all subkeys
669              do have fingerprints. */
670           subkey = key->_last_subkey;
671           if (!subkey->fpr)
672             {
673               subkey->fpr = strdup (field[9]);
674               if (!subkey->fpr)
675                 return gpg_error_from_errno (errno);
676             }
677         }
678
679       /* Field 13 has the gpgsm chain ID (take only the first one).  */
680       if (fields >= 13 && !key->chain_id && *field[12])
681         {
682           key->chain_id = strdup (field[12]);
683           if (!key->chain_id)
684             return gpg_error_from_errno (errno);
685         }
686       break;
687
688     case RT_SIG:
689     case RT_REV:
690       if (!opd->tmp_uid)
691         return 0;
692
693       /* Start a new (revoked) signature.  */
694       assert (opd->tmp_uid == key->_last_uid);
695       keysig = _gpgme_key_add_sig (key, (fields >= 10) ? field[9] : NULL);
696       if (!keysig)
697         return gpg_error (GPG_ERR_ENOMEM);      /* FIXME */
698
699       /* Field 2 has the calculated trust ('!', '-', '?', '%').  */
700       if (fields >= 2)
701         switch (field[1][0])
702           {
703           case '!':
704             keysig->status = gpg_error (GPG_ERR_NO_ERROR);
705             break;
706
707           case '-':
708             keysig->status = gpg_error (GPG_ERR_BAD_SIGNATURE);
709             break;
710
711           case '?':
712             keysig->status = gpg_error (GPG_ERR_NO_PUBKEY);
713             break;
714
715           case '%':
716             keysig->status = gpg_error (GPG_ERR_GENERAL);
717             break;
718
719           default:
720             keysig->status = gpg_error (GPG_ERR_NO_ERROR);
721             break;
722           }
723
724       /* Field 4 has the public key algorithm.  */
725       if (fields >= 4)
726         {
727           int i = atoi (field[3]);
728           if (i >= 1 && i < 128)
729             keysig->pubkey_algo = i;
730         }
731       
732       /* Field 5 has the long keyid.  */
733       if (fields >= 5 && strlen (field[4]) == DIM(keysig->_keyid) - 1)
734         strcpy (keysig->_keyid, field[4]);
735       
736       /* Field 6 has the timestamp (seconds).  */
737       if (fields >= 6)
738         keysig->timestamp = _gpgme_parse_timestamp (field[5], NULL);
739
740       /* Field 7 has the expiration time (seconds).  */
741       if (fields >= 7)
742         keysig->expires = _gpgme_parse_timestamp (field[6], NULL);
743
744       /* Field 11 has the signature class (eg, 0x30 means revoked).  */
745       if (fields >= 11)
746         if (field[10][0] && field[10][1])
747           {
748             int sig_class = _gpgme_hextobyte (field[10]);
749             if (sig_class >= 0)
750               {
751                 keysig->sig_class = sig_class;
752                 keysig->class = keysig->sig_class;
753                 if (sig_class == 0x30)
754                   keysig->revoked = 1;
755               }
756             if (field[10][2] == 'x')
757               keysig->exportable = 1;
758           }
759
760       opd->tmp_keysig = keysig;
761       break;
762
763     case RT_SPK:
764       if (!opd->tmp_keysig)
765         return 0;
766       assert (opd->tmp_keysig == key->_last_uid->_last_keysig);
767
768       if (fields >= 4)
769         {
770           /* Field 2 has the subpacket type.  */
771           int type = atoi (field[1]);
772
773           /* Field 3 has the flags.  */
774           int flags = atoi (field[2]);
775
776           /* Field 4 has the length.  */
777           int len = atoi (field[3]);
778
779           /* Field 5 has the data.  */
780           char *data = field[4];
781
782           /* Type 20: Notation data.  */
783           /* Type 26: Policy URL.  */
784           if (type == 20 || type == 26)
785             {
786               gpgme_sig_notation_t notation;
787
788               keysig = opd->tmp_keysig;
789
790               /* At this time, any error is serious.  */
791               err = _gpgme_parse_notation (&notation, type, flags, len, data);
792               if (err)
793                 return err;
794
795               /* Add a new notation.  FIXME: Could be factored out.  */
796               if (!keysig->notations)
797                 keysig->notations = notation;
798               if (keysig->_last_notation)
799                 keysig->_last_notation->next = notation;
800               keysig->_last_notation = notation;
801             }
802         }
803     
804     case RT_NONE:
805       /* Unknown record.  */
806       break;
807     }
808   return 0;
809 }
810
811
812 void
813 _gpgme_op_keylist_event_cb (void *data, gpgme_event_io_t type, void *type_data)
814 {
815   gpgme_error_t err;
816   gpgme_ctx_t ctx = (gpgme_ctx_t) data;
817   gpgme_key_t key = (gpgme_key_t) type_data;
818   void *hook;
819   op_data_t opd;
820   struct key_queue_item_s *q, *q2;
821
822   assert (type == GPGME_EVENT_NEXT_KEY);
823
824   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
825   opd = hook;
826   if (err)
827     return;
828
829   q = malloc (sizeof *q);
830   if (!q)
831     {
832       gpgme_key_unref (key);
833       /* FIXME       return GPGME_Out_Of_Core; */
834       return;
835     }
836   q->key = key;
837   q->next = NULL;
838   /* FIXME: Use a tail pointer?  */
839   if (!(q2 = opd->key_queue))
840     opd->key_queue = q;
841   else
842     {
843       for (; q2->next; q2 = q2->next)
844         ;
845       q2->next = q;
846     }
847   opd->key_cond = 1;
848 }
849
850
851 /* Start a keylist operation within CTX, searching for keys which
852    match PATTERN.  If SECRET_ONLY is true, only secret keys are
853    returned.  */
854 gpgme_error_t
855 gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern, int secret_only)
856 {
857   gpgme_error_t err;
858   void *hook;
859   op_data_t opd;
860
861   TRACE_BEG2 (DEBUG_CTX, "gpgme_op_keylist_start", ctx,
862               "pattern=%s, secret_only=%i", pattern, secret_only);
863
864   err = _gpgme_op_reset (ctx, 2);
865   if (err)
866     return TRACE_ERR (err);
867
868   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook,
869                                sizeof (*opd), release_op_data);
870   opd = hook;
871   if (err)
872     return TRACE_ERR (err);
873
874   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
875
876   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
877                                               keylist_colon_handler, ctx);
878   if (err)
879     return TRACE_ERR (err);
880
881   err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only,
882                                   ctx->keylist_mode);
883   return TRACE_ERR (err);
884 }
885
886
887 /* Start a keylist operation within CTX, searching for keys which
888    match PATTERN.  If SECRET_ONLY is true, only secret keys are
889    returned.  */
890 gpgme_error_t
891 gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, const char *pattern[],
892                             int secret_only, int reserved)
893 {
894   gpgme_error_t err;
895   void *hook;
896   op_data_t opd;
897
898   TRACE_BEG2 (DEBUG_CTX, "gpgme_op_keylist_ext_start", ctx,
899               "secret_only=%i, reserved=0x%x", secret_only, reserved);
900
901   err = _gpgme_op_reset (ctx, 2);
902   if (err)
903     return TRACE_ERR (err);
904
905   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook,
906                                sizeof (*opd), release_op_data);
907   opd = hook;
908   if (err)
909     return TRACE_ERR (err);
910
911   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
912   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
913                                               keylist_colon_handler, ctx);
914   if (err)
915     return TRACE_ERR (err);
916
917   err = _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only,
918                                       reserved, ctx->keylist_mode);
919   return TRACE_ERR (err);
920 }
921
922
923 /* Return the next key from the keylist in R_KEY.  */
924 gpgme_error_t
925 gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key)
926 {
927   gpgme_error_t err;
928   struct key_queue_item_s *queue_item;
929   void *hook;
930   op_data_t opd;
931
932   TRACE_BEG (DEBUG_CTX, "gpgme_op_keylist_next", ctx);
933
934   if (!ctx || !r_key)
935     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
936   *r_key = NULL;
937   if (!ctx)
938     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
939
940   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
941   opd = hook;
942   if (err)
943     return TRACE_ERR (err);
944   if (opd == NULL)
945     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
946
947   if (!opd->key_queue)
948     {
949       err = _gpgme_wait_on_condition (ctx, &opd->key_cond, NULL);
950       if (err)
951         return TRACE_ERR (err);
952
953       if (!opd->key_cond)
954         return TRACE_ERR (gpg_error (GPG_ERR_EOF));
955
956       opd->key_cond = 0; 
957       assert (opd->key_queue);
958     }
959   queue_item = opd->key_queue;
960   opd->key_queue = queue_item->next;
961   if (!opd->key_queue)
962     opd->key_cond = 0;
963   
964   *r_key = queue_item->key;
965   free (queue_item);
966
967   return TRACE_SUC2 ("key=%p (%s)", *r_key,
968                      ((*r_key)->subkeys && (*r_key)->subkeys->fpr) ? 
969                      (*r_key)->subkeys->fpr : "invalid");
970 }
971
972
973 /* Terminate a pending keylist operation within CTX.  */
974 gpgme_error_t
975 gpgme_op_keylist_end (gpgme_ctx_t ctx)
976 {
977   TRACE (DEBUG_CTX, "gpgme_op_keylist_end", ctx);
978   
979   if (!ctx)
980     return gpg_error (GPG_ERR_INV_VALUE);
981
982   return 0;
983 }
984
985 \f
986 /* Get the key with the fingerprint FPR from the crypto backend.  If
987    SECRET is true, get the secret key.  */
988 gpgme_error_t
989 gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
990                int secret)
991 {
992   gpgme_ctx_t listctx;
993   gpgme_error_t err;
994   gpgme_key_t key;
995
996   TRACE_BEG2 (DEBUG_CTX, "gpgme_get_key", ctx,
997               "fpr=%s, secret=%i", fpr, secret);
998
999   if (!ctx || !r_key || !fpr)
1000     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
1001   
1002   if (strlen (fpr) < 8) /* We have at least a key ID.  */
1003     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
1004
1005   /* FIXME: We use our own context because we have to avoid the user's
1006      I/O callback handlers.  */
1007   err = gpgme_new (&listctx);
1008   if (err)
1009     return TRACE_ERR (err);
1010   {
1011     gpgme_protocol_t proto;
1012     gpgme_engine_info_t info;
1013
1014     /* Clone the relevant state.  */
1015     proto = gpgme_get_protocol (ctx);
1016     gpgme_set_protocol (listctx, proto);
1017     gpgme_set_keylist_mode (listctx, gpgme_get_keylist_mode (ctx));
1018     info = gpgme_ctx_get_engine_info (ctx);
1019     while (info && info->protocol != proto)
1020       info = info->next;
1021     if (info)
1022       gpgme_ctx_set_engine_info (listctx, proto,
1023                                  info->file_name, info->home_dir);
1024   }
1025
1026   err = gpgme_op_keylist_start (listctx, fpr, secret);
1027   if (!err)
1028     err = gpgme_op_keylist_next (listctx, r_key);
1029   if (!err)
1030     {
1031     try_next_key:
1032       err = gpgme_op_keylist_next (listctx, &key);
1033       if (gpgme_err_code (err) == GPG_ERR_EOF)
1034         err = 0;
1035       else
1036         {
1037           if (!err
1038               && *r_key && (*r_key)->subkeys && (*r_key)->subkeys->fpr
1039               && key && key->subkeys && key->subkeys->fpr
1040               && !strcmp ((*r_key)->subkeys->fpr, key->subkeys->fpr))
1041             {
1042               /* The fingerprint is identical.  We assume that this is
1043                  the same key and don't mark it as an ambiguous.  This
1044                  problem may occur with corrupted keyrings and has
1045                  been noticed often with gpgsm.  In fact gpgsm uses a
1046                  similar hack to sort out such duplicates but it can't
1047                  do that while listing keys.  */
1048               gpgme_key_unref (key);
1049               goto try_next_key;
1050             }
1051           if (!err)
1052             {
1053               gpgme_key_unref (key);
1054               err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
1055             }
1056           gpgme_key_unref (*r_key);
1057         }
1058     }
1059   gpgme_release (listctx);
1060   if (! err)
1061     {
1062       TRACE_LOG2 ("key=%p (%s)", *r_key,
1063                   ((*r_key)->subkeys && (*r_key)->subkeys->fpr) ? 
1064                   (*r_key)->subkeys->fpr : "invalid");
1065     }
1066   return TRACE_ERR (err);
1067 }