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