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