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