2004-09-30 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 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 void
120 set_subkey_trust_info (gpgme_subkey_t subkey, const char *src)
121 {
122   while (*src && !isdigit (*src))
123     {
124       switch (*src)
125         {
126         case 'e':
127           subkey->expired = 1;
128           break;
129
130         case 'r':
131           subkey->revoked = 1;
132           break;
133
134         case 'd':
135           /* Note that gpg 1.3 won't print that anymore but only uses
136              the capabilities field. */
137           subkey->disabled = 1;
138           break;
139
140         case 'i':
141           subkey->invalid = 1;
142           break;
143         }
144       src++;
145     }
146 }
147
148
149 static void
150 set_mainkey_trust_info (gpgme_key_t key, const char *src)
151 {
152   /* First set the trust info of the main key (the first subkey).  */
153   set_subkey_trust_info (key->subkeys, src);
154
155   /* Now set the summarized trust info.  */
156   while (*src && !isdigit (*src))
157     {
158       switch (*src)
159         {
160         case 'e':
161           key->expired = 1;
162           break;
163
164         case 'r':
165           key->revoked = 1;
166           break;
167
168         case 'd':
169           /* Note that gpg 1.3 won't print that anymore but only uses
170              the capabilities field. */
171           key->disabled = 1;
172           break;
173
174         case 'i':
175           key->invalid = 1;
176           break;
177         }
178       src++;
179     }
180 }
181
182
183 static void
184 set_userid_flags (gpgme_key_t key, const char *src)
185 {
186   gpgme_user_id_t uid = key->_last_uid;
187
188   assert (uid);
189   /* Look at letters and stop at the first digit.  */
190   while (*src && !isdigit (*src))
191     {
192       switch (*src)
193         {
194         case 'r':
195           uid->revoked = 1;
196           break;
197           
198         case 'i':
199           uid->invalid = 1;
200           break;
201
202         case 'n':
203           uid->validity = GPGME_VALIDITY_NEVER;
204           break;
205
206         case 'm':
207           uid->validity = GPGME_VALIDITY_MARGINAL;
208           break;
209
210         case 'f':
211           uid->validity = GPGME_VALIDITY_FULL;
212           break;
213
214         case 'u':
215           uid->validity = GPGME_VALIDITY_ULTIMATE;
216           break;
217         }
218       src++;
219     }
220 }
221
222
223 static void
224 set_subkey_capability (gpgme_subkey_t subkey, const char *src)
225 {
226   while (*src)
227     {
228       switch (*src)
229         {
230         case 'e':
231           subkey->can_encrypt = 1;
232           break;
233
234         case 's':
235           subkey->can_sign = 1;
236           break;
237
238         case 'c':
239           subkey->can_certify = 1;
240           break;
241
242         case 'a':
243           subkey->can_authenticate = 1;
244           break;
245
246         case 'd':
247           subkey->disabled = 1;
248           break;
249         }
250       src++;
251     }
252 }
253
254
255 static void
256 set_mainkey_capability (gpgme_key_t key, const char *src)
257 {
258   /* First set the capabilities of the main key (the first subkey).  */
259   set_subkey_capability (key->subkeys, src);
260
261   while (*src)
262     {
263       switch (*src)
264         {
265         case 'd':
266         case 'D':
267           /* Note, that this flag is also set using the key validity
268              field for backward compatibility with gpg 1.2.  We use d
269              and D, so that a future gpg version will be able to
270              disable certain subkeys. Currently it is expected that
271              gpg sets this for the primary key. */
272           key->disabled = 1;
273           break;
274
275         case 'e':
276         case 'E':
277           key->can_encrypt = 1;
278           break;
279
280         case 's':
281         case 'S':
282           key->can_sign = 1;
283           break;
284
285         case 'c':
286         case 'C':
287           key->can_certify = 1;
288           break;
289
290         case 'a':
291         case 'A':
292           key->can_authenticate = 1;
293           break;
294         }
295       src++;
296     }
297 }
298
299
300 static void
301 set_ownertrust (gpgme_key_t key, const char *src)
302 {
303   /* Look at letters and stop at the first digit.  */
304   while (*src && !isdigit (*src))
305     {
306       switch (*src)
307         {
308         case 'n':
309           key->owner_trust = GPGME_VALIDITY_NEVER;
310           break;
311
312         case 'm':
313           key->owner_trust = GPGME_VALIDITY_MARGINAL;
314           break;
315
316         case 'f':
317           key->owner_trust = GPGME_VALIDITY_FULL;
318           break;
319
320         case 'u':
321           key->owner_trust = GPGME_VALIDITY_ULTIMATE;
322           break;
323
324         default:
325           key->owner_trust = GPGME_VALIDITY_UNKNOWN;
326           break;
327         }
328       src++;
329     }
330 }
331
332
333 /* We have read an entire key into tmp_key and should now finish it.
334    It is assumed that this releases tmp_key.  */
335 static void
336 finish_key (gpgme_ctx_t ctx, op_data_t opd)
337 {
338   gpgme_key_t key = opd->tmp_key;
339
340   opd->tmp_key = NULL;
341   opd->tmp_uid = NULL;
342
343   if (key)
344     _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_KEY, key);
345 }
346
347
348 /* Note: We are allowed to modify LINE.  */
349 static gpgme_error_t
350 keylist_colon_handler (void *priv, char *line)
351 {
352   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
353   enum
354     {
355       RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR,
356       RT_SSB, RT_SEC, RT_CRT, RT_CRS, RT_REV
357     }
358   rectype = RT_NONE;
359 #define NR_FIELDS 13
360   char *field[NR_FIELDS];
361   int fields = 0;
362   void *hook;
363   op_data_t opd;
364   gpgme_error_t err;
365   gpgme_key_t key;
366   gpgme_subkey_t subkey = NULL;
367   gpgme_key_sig_t keysig = NULL;
368
369   DEBUG3 ("keylist_colon_handler ctx = %p, key = %p, line = %s\n",
370           ctx, key, line ? line : "(null)");
371
372   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
373   opd = hook;
374   if (err)
375     return err;
376
377   key = opd->tmp_key;
378
379   if (!line)
380     {
381       /* End Of File.  */
382       finish_key (ctx, opd);
383       return 0;
384     }
385
386   while (line && fields < NR_FIELDS)
387     {
388       field[fields++] = line;
389       line = strchr (line, ':');
390       if (line)
391         *(line++) = '\0';
392     }
393
394   if (!strcmp (field[0], "sig"))
395     rectype = RT_SIG;
396   else if (!strcmp (field[0], "rev"))
397     rectype = RT_REV;
398   else if (!strcmp (field[0], "pub"))
399     rectype = RT_PUB;
400   else if (!strcmp (field[0], "sec"))
401     rectype = RT_SEC;
402   else if (!strcmp (field[0], "crt"))
403     rectype = RT_CRT;
404   else if (!strcmp (field[0], "crs"))
405     rectype = RT_CRS;
406   else if (!strcmp (field[0], "fpr") && key) 
407     rectype = RT_FPR;
408   else if (!strcmp (field[0], "uid") && key)
409     rectype = RT_UID;
410   else if (!strcmp (field[0], "sub") && key)
411     rectype = RT_SUB; 
412   else if (!strcmp (field[0], "ssb") && key)
413     rectype = RT_SSB;
414   else 
415     rectype = RT_NONE;
416
417   /* Only look at signatures immediately following a user ID.  For
418      this, clear the user ID pointer when encountering anything but a
419      signature.  */
420   if (rectype != RT_SIG && rectype != RT_REV)
421     opd->tmp_uid = NULL;
422
423   switch (rectype)
424     {
425     case RT_PUB:
426     case RT_SEC:
427     case RT_CRT:
428     case RT_CRS:
429       /* Start a new keyblock.  */
430       err = _gpgme_key_new (&key);
431       if (err)
432         return err;
433       key->keylist_mode = ctx->keylist_mode;
434       err = _gpgme_key_add_subkey (key, &subkey);
435       if (err)
436         {
437           gpgme_key_unref (key);
438           return err;
439         }
440
441       if (rectype == RT_SEC || rectype == RT_CRS)
442         key->secret = 1;
443       if (rectype == RT_CRT || rectype == RT_CRS)
444         key->protocol = GPGME_PROTOCOL_CMS;
445       finish_key (ctx, opd);
446       opd->tmp_key = key;
447
448       /* Field 2 has the trust info.  */
449       if (fields >= 2)
450         set_mainkey_trust_info (key, field[1]);
451
452       /* Field 3 has the key length.  */
453       if (fields >= 3)
454         {
455           int i = atoi (field[2]);
456           /* Ignore invalid values.  */
457           if (i > 1)
458             subkey->length = i; 
459         }
460
461       /* Field 4 has the public key algorithm.  */
462       if (fields >= 4)
463         {
464           int i = atoi (field[3]);
465           if (i >= 1 && i < 128)
466             subkey->pubkey_algo = i;
467         }
468
469       /* Field 5 has the long keyid.  */
470       if (fields >= 5 && strlen (field[4]) == DIM(subkey->_keyid) - 1)
471         strcpy (subkey->_keyid, field[4]);
472
473       /* Field 6 has the timestamp (seconds).  */
474       if (fields >= 6)
475         subkey->timestamp = _gpgme_parse_timestamp (field[5], NULL);
476
477       /* Field 7 has the expiration time (seconds).  */
478       if (fields >= 7)
479         subkey->expires = _gpgme_parse_timestamp (field[6], NULL);
480
481       /* Field 8 has the X.509 serial number.  */
482       if (fields >= 8 && (rectype == RT_CRT || rectype == RT_CRS))
483         {
484           key->issuer_serial = strdup (field[7]);
485           if (!key->issuer_serial)
486             return gpg_error_from_errno (errno);
487         }
488           
489       /* Field 9 has the ownertrust.  */
490       if (fields >= 9)
491         set_ownertrust (key, field[8]);
492
493       /* Field 10 is not used for gpg due to --fixed-list-mode option
494          but GPGSM stores the issuer name.  */
495       if (fields >= 10 && (rectype == RT_CRT || rectype == RT_CRS))
496         if (_gpgme_decode_c_string (field[9], &key->issuer_name, 0))
497           return gpg_error (GPG_ERR_ENOMEM);    /* FIXME */
498
499       /* Field 11 has the signature class.  */
500
501       /* Field 12 has the capabilities.  */
502       if (fields >= 12)
503         set_mainkey_capability (key, field[11]);
504       break;
505
506     case RT_SUB:
507     case RT_SSB:
508       /* Start a new subkey.  */
509       err = _gpgme_key_add_subkey (key, &subkey);
510       if (err)
511         return err;
512
513       if (rectype == RT_SSB)
514         subkey->secret = 1;
515
516       /* Field 2 has the trust info.  */
517       if (fields >= 2)
518         set_subkey_trust_info (subkey, field[1]);
519
520       /* Field 3 has the key length.  */
521       if (fields >= 3)
522         {
523           int i = atoi (field[2]);
524           /* Ignore invalid values.  */
525           if (i > 1)
526             subkey->length = i;
527         }
528
529       /* Field 4 has the public key algorithm.  */
530       if (fields >= 4)
531         {
532           int i = atoi (field[3]);
533           if (i >= 1 && i < 128)
534             subkey->pubkey_algo = i;
535         }
536
537       /* Field 5 has the long keyid.  */
538       if (fields >= 5 && strlen (field[4]) == DIM(subkey->_keyid) - 1)
539         strcpy (subkey->_keyid, field[4]);
540
541       /* Field 6 has the timestamp (seconds).  */
542       if (fields >= 6)
543         subkey->timestamp = _gpgme_parse_timestamp (field[5], NULL);
544
545       /* Field 7 has the expiration time (seconds).  */
546       if (fields >= 7)
547         subkey->expires = _gpgme_parse_timestamp (field[6], NULL);
548
549       /* Field 8 is reserved (LID).  */
550       /* Field 9 has the ownertrust.  */
551       /* Field 10, the user ID, is n/a for a subkey.  */
552       
553       /* Field 11 has the signature class.  */
554
555       /* Field 12 has the capabilities.  */
556       if (fields >= 12)
557         set_subkey_capability (subkey, field[11]);
558       break;
559
560     case RT_UID:
561       /* Field 2 has the trust info, and field 10 has the user ID.  */
562       if (fields >= 10)
563         {
564           if (_gpgme_key_append_name (key, field[9]))
565             return gpg_error_from_errno (GPG_ERR_ENOMEM);       /* FIXME */
566           else
567             {
568               if (field[1])
569                 set_userid_flags (key, field[1]);
570               opd->tmp_uid = key->_last_uid;
571             }
572         }
573       break;
574
575     case RT_FPR:
576       /* Field 10 has the fingerprint (take only the first one).  */
577       if (fields >= 10 && !key->subkeys->fpr && field[9] && *field[9])
578         {
579           key->subkeys->fpr = strdup (field[9]);
580           if (!key->subkeys->fpr)
581             return gpg_error_from_errno (errno);
582         }
583
584       /* Field 13 has the gpgsm chain ID (take only the first one).  */
585       if (fields >= 13 && !key->chain_id && *field[12])
586         {
587           key->chain_id = strdup (field[12]);
588           if (!key->chain_id)
589             return gpg_error_from_errno (errno);
590         }
591       break;
592
593     case RT_SIG:
594     case RT_REV:
595       if (!opd->tmp_uid)
596         return 0;
597
598       /* Start a new (revoked) signature.  */
599       assert (opd->tmp_uid == key->_last_uid);
600       keysig = _gpgme_key_add_sig (key, (fields >= 10) ? field[9] : NULL);
601       if (!keysig)
602         return gpg_error (GPG_ERR_ENOMEM);      /* FIXME */
603
604       /* Field 2 has the calculated trust ('!', '-', '?', '%').  */
605       if (fields >= 2)
606         switch (field[1][0])
607           {
608           case '!':
609             keysig->status = gpg_error (GPG_ERR_NO_ERROR);
610             break;
611
612           case '-':
613             keysig->status = gpg_error (GPG_ERR_BAD_SIGNATURE);
614             break;
615
616           case '?':
617             keysig->status = gpg_error (GPG_ERR_NO_PUBKEY);
618             break;
619
620           case '%':
621             keysig->status = gpg_error (GPG_ERR_GENERAL);
622             break;
623
624           default:
625             keysig->status = gpg_error (GPG_ERR_NO_ERROR);
626             break;
627           }
628
629       /* Field 4 has the public key algorithm.  */
630       if (fields >= 4)
631         {
632           int i = atoi (field[3]);
633           if (i >= 1 && i < 128)
634             keysig->pubkey_algo = i;
635         }
636       
637       /* Field 5 has the long keyid.  */
638       if (fields >= 5 && strlen (field[4]) == DIM(keysig->_keyid) - 1)
639         strcpy (keysig->_keyid, field[4]);
640       
641       /* Field 6 has the timestamp (seconds).  */
642       if (fields >= 6)
643         keysig->timestamp = _gpgme_parse_timestamp (field[5], NULL);
644
645       /* Field 7 has the expiration time (seconds).  */
646       if (fields >= 7)
647         keysig->expires = _gpgme_parse_timestamp (field[6], NULL);
648
649       /* Field 11 has the signature class (eg, 0x30 means revoked).  */
650       if (fields >= 11)
651         if (field[10][0] && field[10][1])
652           {
653             int sig_class = _gpgme_hextobyte (field[10]);
654             if (sig_class >= 0)
655               {
656                 keysig->sig_class = sig_class;
657                 keysig->class = keysig->sig_class;
658                 if (sig_class == 0x30)
659                   keysig->revoked = 1;
660               }
661             if (field[10][2] == 'x')
662               keysig->exportable = 1;
663           }
664       break;
665
666     case RT_NONE:
667       /* Unknown record.  */
668       break;
669     }
670   return 0;
671 }
672
673
674 void
675 _gpgme_op_keylist_event_cb (void *data, gpgme_event_io_t type, void *type_data)
676 {
677   gpgme_error_t err;
678   gpgme_ctx_t ctx = (gpgme_ctx_t) data;
679   gpgme_key_t key = (gpgme_key_t) type_data;
680   void *hook;
681   op_data_t opd;
682   struct key_queue_item_s *q, *q2;
683
684   assert (type == GPGME_EVENT_NEXT_KEY);
685
686   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
687   opd = hook;
688   if (err)
689     return;
690
691   q = malloc (sizeof *q);
692   if (!q)
693     {
694       gpgme_key_unref (key);
695       /* FIXME       return GPGME_Out_Of_Core; */
696       return;
697     }
698   q->key = key;
699   q->next = NULL;
700   /* FIXME: Use a tail pointer?  */
701   if (!(q2 = opd->key_queue))
702     opd->key_queue = q;
703   else
704     {
705       for (; q2->next; q2 = q2->next)
706         ;
707       q2->next = q;
708     }
709   opd->key_cond = 1;
710 }
711
712
713 /* Start a keylist operation within CTX, searching for keys which
714    match PATTERN.  If SECRET_ONLY is true, only secret keys are
715    returned.  */
716 gpgme_error_t
717 gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern, int secret_only)
718 {
719   gpgme_error_t err;
720   void *hook;
721   op_data_t opd;
722
723   err = _gpgme_op_reset (ctx, 2);
724   if (err)
725     return err;
726
727   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook,
728                                sizeof (*opd), release_op_data);
729   opd = hook;
730   if (err)
731     return err;
732
733   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
734
735   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
736                                               keylist_colon_handler, ctx);
737   if (err)
738     return err;
739
740   return _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only,
741                                    ctx->keylist_mode);
742 }
743
744
745 /* Start a keylist operation within CTX, searching for keys which
746    match PATTERN.  If SECRET_ONLY is true, only secret keys are
747    returned.  */
748 gpgme_error_t
749 gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, const char *pattern[],
750                             int secret_only, int reserved)
751 {
752   gpgme_error_t err;
753   void *hook;
754   op_data_t opd;
755
756   err = _gpgme_op_reset (ctx, 2);
757   if (err)
758     return err;
759
760   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook,
761                                sizeof (*opd), release_op_data);
762   opd = hook;
763   if (err)
764     return err;
765
766   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
767   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
768                                               keylist_colon_handler, ctx);
769   if (err)
770     return err;
771
772   return _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only,
773                                        reserved, ctx->keylist_mode);
774 }
775
776
777 /* Return the next key from the keylist in R_KEY.  */
778 gpgme_error_t
779 gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key)
780 {
781   gpgme_error_t err;
782   struct key_queue_item_s *queue_item;
783   void *hook;
784   op_data_t opd;
785
786   if (!ctx || !r_key)
787     return gpg_error (GPG_ERR_INV_VALUE);
788   *r_key = NULL;
789   if (!ctx)
790     return gpg_error (GPG_ERR_INV_VALUE);
791
792   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
793   opd = hook;
794   if (err)
795     return err;
796
797   if (!opd->key_queue)
798     {
799       err = _gpgme_wait_on_condition (ctx, &opd->key_cond);
800       if (err)
801         return err;
802
803       if (!opd->key_cond)
804         return gpg_error (GPG_ERR_EOF);
805
806       opd->key_cond = 0; 
807       assert (opd->key_queue);
808     }
809   queue_item = opd->key_queue;
810   opd->key_queue = queue_item->next;
811   if (!opd->key_queue)
812     opd->key_cond = 0;
813   
814   *r_key = queue_item->key;
815   free (queue_item);
816   return 0;
817 }
818
819
820 /* Terminate a pending keylist operation within CTX.  */
821 gpgme_error_t
822 gpgme_op_keylist_end (gpgme_ctx_t ctx)
823 {
824   if (!ctx)
825     return gpg_error (GPG_ERR_INV_VALUE);
826
827   return 0;
828 }
829
830 \f
831 /* Get the key with the fingerprint FPR from the crypto backend.  If
832    SECRET is true, get the secret key.  */
833 gpgme_error_t
834 gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
835                int secret)
836 {
837   gpgme_ctx_t listctx;
838   gpgme_error_t err;
839   gpgme_key_t key;
840
841   if (!ctx || !r_key || !fpr)
842     return gpg_error (GPG_ERR_INV_VALUE);
843   
844   if (strlen (fpr) < 16)        /* We have at least a key ID.  */
845     return gpg_error (GPG_ERR_INV_VALUE);
846
847   /* FIXME: We use our own context because we have to avoid the user's
848      I/O callback handlers.  */
849   err = gpgme_new (&listctx);
850   if (err)
851     return err;
852   gpgme_set_protocol (listctx, gpgme_get_protocol (ctx));
853   gpgme_set_keylist_mode (listctx, ctx->keylist_mode);
854   err = gpgme_op_keylist_start (listctx, fpr, secret);
855   if (!err)
856     err = gpgme_op_keylist_next (listctx, r_key);
857   if (!err)
858     {
859       err = gpgme_op_keylist_next (listctx, &key);
860       if (gpgme_err_code (err) == GPG_ERR_EOF)
861         err = gpg_error (GPG_ERR_NO_ERROR);
862       else
863         {
864           if (!err)
865             {
866               gpgme_key_unref (key);
867               err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
868             }
869           gpgme_key_unref (*r_key);
870         }
871     }
872   gpgme_release (listctx);
873   return err;
874 }