(gpgme_get_key): Return an error if FPR is NULL.
[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
120 static void
121 set_mainkey_trust_info (gpgme_key_t key, const char *src)
122 {
123   /* Look at letters and stop at the first digit.  */
124   while (*src && !isdigit (*src))
125     {
126       switch (*src)
127         {
128         case 'e':
129           key->subkeys->expired = 1;
130           break;
131
132         case 'r':
133           key->subkeys->revoked = 1;
134           break;
135
136         case 'd':
137           /* Note that gpg 1.3 won't print that anymore but only uses
138              the capabilities field. */
139           key->subkeys->disabled = 1;
140           break;
141
142         case 'i':
143           key->subkeys->invalid = 1;
144           break;
145         }
146       src++;
147     }
148 }
149
150
151 static void
152 set_userid_flags (gpgme_key_t key, const char *src)
153 {
154   gpgme_user_id_t uid = key->_last_uid;
155
156   assert (uid);
157   /* Look at letters and stop at the first digit.  */
158   while (*src && !isdigit (*src))
159     {
160       switch (*src)
161         {
162         case 'r':
163           uid->revoked = 1;
164           break;
165           
166         case 'i':
167           uid->invalid = 1;
168           break;
169
170         case 'n':
171           uid->validity = GPGME_VALIDITY_NEVER;
172           break;
173
174         case 'm':
175           uid->validity = GPGME_VALIDITY_MARGINAL;
176           break;
177
178         case 'f':
179           uid->validity = GPGME_VALIDITY_FULL;
180           break;
181
182         case 'u':
183           uid->validity = GPGME_VALIDITY_ULTIMATE;
184           break;
185         }
186       src++;
187     }
188 }
189
190
191 static void
192 set_subkey_trust_info (gpgme_subkey_t subkey, const char *src)
193 {
194   /* Look at letters and stop at the first digit.  */
195   while (*src && !isdigit (*src))
196     {
197       switch (*src)
198         {
199         case 'e':
200           subkey->expired = 1;
201           break;
202
203         case 'r':
204           subkey->revoked = 1;
205           break;
206
207         case 'd':
208           subkey->disabled = 1;
209           break;
210
211         case 'i':
212           subkey->invalid = 1;
213           break;
214         }
215       src++;
216     }
217 }
218
219
220 static void
221 set_mainkey_capability (gpgme_key_t key, const char *src)
222 {
223   while (*src)
224     {
225       switch (*src)
226         {
227         case 'e':
228           key->subkeys->can_encrypt = 1;
229           break;
230
231         case 's':
232           key->subkeys->can_sign = 1;
233           break;
234
235         case 'c':
236           key->subkeys->can_certify = 1;
237           break;
238
239         case 'a':
240           key->subkeys->can_authenticate = 1;
241           break;
242
243         case 'd':
244         case 'D':
245           /* Note, that this flag is also set using the key validity
246              field for backward compatibility with gpg 1.2.  We use d
247              and D, so that a future gpg version will be able to
248              disable certain subkeys. Currently it is expected that
249              gpg sets this for the primary key. */
250           key->subkeys->disabled = 1;
251           break;
252
253         case 'E':
254           key->can_encrypt = 1;
255           break;
256
257         case 'S':
258           key->can_sign = 1;
259           break;
260
261         case 'C':
262           key->can_certify = 1;
263           break;
264
265         case 'A':
266           key->can_authenticate = 1;
267           break;
268         }
269       src++;
270     }
271 }
272
273
274 static void
275 set_subkey_capability (gpgme_subkey_t subkey, const char *src)
276 {
277   while (*src)
278     {
279       switch (*src)
280         {
281         case 'e':
282           subkey->can_encrypt = 1;
283           break;
284
285         case 's':
286           subkey->can_sign = 1;
287           break;
288
289         case 'c':
290           subkey->can_certify = 1;
291           break;
292
293         case 'a':
294           subkey->can_authenticate = 1;
295           break;
296         }
297       src++;
298     }
299 }
300
301 static void
302 set_ownertrust (gpgme_key_t key, const char *src)
303 {
304   /* Look at letters and stop at the first digit.  */
305   while (*src && !isdigit (*src))
306     {
307       switch (*src)
308         {
309         case 'n':
310           key->owner_trust = GPGME_VALIDITY_NEVER;
311           break;
312
313         case 'm':
314           key->owner_trust = GPGME_VALIDITY_MARGINAL;
315           break;
316
317         case 'f':
318           key->owner_trust = GPGME_VALIDITY_FULL;
319           break;
320
321         case 'u':
322           key->owner_trust = GPGME_VALIDITY_ULTIMATE;
323           break;
324
325         default:
326           key->owner_trust = GPGME_VALIDITY_UNKNOWN;
327           break;
328         }
329       src++;
330     }
331 }
332
333
334 /* We have read an entire key into tmp_key and should now finish it.
335    It is assumed that this releases tmp_key.  */
336 static void
337 finish_key (gpgme_ctx_t ctx, op_data_t opd)
338 {
339   gpgme_key_t key = opd->tmp_key;
340
341   opd->tmp_key = NULL;
342   opd->tmp_uid = NULL;
343
344   if (key)
345     _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_KEY, key);
346 }
347
348
349 /* Note: We are allowed to modify LINE.  */
350 static gpgme_error_t
351 keylist_colon_handler (void *priv, char *line)
352 {
353   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
354   enum
355     {
356       RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR,
357       RT_SSB, RT_SEC, RT_CRT, RT_CRS, RT_REV
358     }
359   rectype = RT_NONE;
360 #define NR_FIELDS 13
361   char *field[NR_FIELDS];
362   int fields = 0;
363   void *hook;
364   op_data_t opd;
365   gpgme_error_t err;
366   gpgme_key_t key;
367   gpgme_subkey_t subkey = NULL;
368   gpgme_key_sig_t keysig = NULL;
369
370   DEBUG3 ("keylist_colon_handler ctx = %p, key = %p, line = %s\n",
371           ctx, key, line ? line : "(null)");
372
373   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
374   opd = hook;
375   if (err)
376     return err;
377
378   key = opd->tmp_key;
379
380   if (!line)
381     {
382       /* End Of File.  */
383       finish_key (ctx, opd);
384       return 0;
385     }
386
387   while (line && fields < NR_FIELDS)
388     {
389       field[fields++] = line;
390       line = strchr (line, ':');
391       if (line)
392         *(line++) = '\0';
393     }
394
395   if (!strcmp (field[0], "sig"))
396     rectype = RT_SIG;
397   else if (!strcmp (field[0], "rev"))
398     rectype = RT_REV;
399   else if (!strcmp (field[0], "pub"))
400     rectype = RT_PUB;
401   else if (!strcmp (field[0], "sec"))
402     rectype = RT_SEC;
403   else if (!strcmp (field[0], "crt"))
404     rectype = RT_CRT;
405   else if (!strcmp (field[0], "crs"))
406     rectype = RT_CRS;
407   else if (!strcmp (field[0], "fpr") && key) 
408     rectype = RT_FPR;
409   else if (!strcmp (field[0], "uid") && key)
410     rectype = RT_UID;
411   else if (!strcmp (field[0], "sub") && key)
412     rectype = RT_SUB; 
413   else if (!strcmp (field[0], "ssb") && key)
414     rectype = RT_SSB;
415   else 
416     rectype = RT_NONE;
417
418   /* Only look at signatures immediately following a user ID.  For
419      this, clear the user ID pointer when encountering anything but a
420      signature.  */
421   if (rectype != RT_SIG && rectype != RT_REV)
422     opd->tmp_uid = NULL;
423
424   switch (rectype)
425     {
426     case RT_PUB:
427     case RT_SEC:
428     case RT_CRT:
429     case RT_CRS:
430       /* Start a new keyblock.  */
431       err = _gpgme_key_new (&key);
432       if (err)
433         return err;
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 }