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