* conversion.c (_gpgme_parse_timestamp): New.
[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 class = _gpgme_hextobyte (field[10]);
654             if (class >= 0)
655               {
656                 keysig->class = class;
657                 if (class == 0x30)
658                   keysig->revoked = 1;
659               }
660             if (field[10][2] == 'x')
661               keysig->exportable = 1;
662           }
663       break;
664
665     case RT_NONE:
666       /* Unknown record.  */
667       break;
668     }
669   return 0;
670 }
671
672
673 void
674 _gpgme_op_keylist_event_cb (void *data, gpgme_event_io_t type, void *type_data)
675 {
676   gpgme_error_t err;
677   gpgme_ctx_t ctx = (gpgme_ctx_t) data;
678   gpgme_key_t key = (gpgme_key_t) type_data;
679   void *hook;
680   op_data_t opd;
681   struct key_queue_item_s *q, *q2;
682
683   assert (type == GPGME_EVENT_NEXT_KEY);
684
685   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
686   opd = hook;
687   if (err)
688     return;
689
690   q = malloc (sizeof *q);
691   if (!q)
692     {
693       gpgme_key_unref (key);
694       /* FIXME       return GPGME_Out_Of_Core; */
695       return;
696     }
697   q->key = key;
698   q->next = NULL;
699   /* FIXME: Use a tail pointer?  */
700   if (!(q2 = opd->key_queue))
701     opd->key_queue = q;
702   else
703     {
704       for (; q2->next; q2 = q2->next)
705         ;
706       q2->next = q;
707     }
708   opd->key_cond = 1;
709 }
710
711
712 /* Start a keylist operation within CTX, searching for keys which
713    match PATTERN.  If SECRET_ONLY is true, only secret keys are
714    returned.  */
715 gpgme_error_t
716 gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern, int secret_only)
717 {
718   gpgme_error_t err;
719   void *hook;
720   op_data_t opd;
721
722   err = _gpgme_op_reset (ctx, 2);
723   if (err)
724     return err;
725
726   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook,
727                                sizeof (*opd), release_op_data);
728   opd = hook;
729   if (err)
730     return err;
731
732   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
733
734   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
735                                               keylist_colon_handler, ctx);
736   if (err)
737     return err;
738
739   return _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only,
740                                    ctx->keylist_mode);
741 }
742
743
744 /* Start a keylist operation within CTX, searching for keys which
745    match PATTERN.  If SECRET_ONLY is true, only secret keys are
746    returned.  */
747 gpgme_error_t
748 gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, const char *pattern[],
749                             int secret_only, int reserved)
750 {
751   gpgme_error_t err;
752   void *hook;
753   op_data_t opd;
754
755   err = _gpgme_op_reset (ctx, 2);
756   if (err)
757     return err;
758
759   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook,
760                                sizeof (*opd), release_op_data);
761   opd = hook;
762   if (err)
763     return err;
764
765   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
766   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
767                                               keylist_colon_handler, ctx);
768   if (err)
769     return err;
770
771   return _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only,
772                                        reserved, ctx->keylist_mode);
773 }
774
775
776 /* Return the next key from the keylist in R_KEY.  */
777 gpgme_error_t
778 gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key)
779 {
780   gpgme_error_t err;
781   struct key_queue_item_s *queue_item;
782   void *hook;
783   op_data_t opd;
784
785   if (!ctx || !r_key)
786     return gpg_error (GPG_ERR_INV_VALUE);
787   *r_key = NULL;
788   if (!ctx)
789     return gpg_error (GPG_ERR_INV_VALUE);
790
791   err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
792   opd = hook;
793   if (err)
794     return err;
795
796   if (!opd->key_queue)
797     {
798       err = _gpgme_wait_on_condition (ctx, &opd->key_cond);
799       if (err)
800         return err;
801
802       if (!opd->key_cond)
803         return gpg_error (GPG_ERR_EOF);
804
805       opd->key_cond = 0; 
806       assert (opd->key_queue);
807     }
808   queue_item = opd->key_queue;
809   opd->key_queue = queue_item->next;
810   if (!opd->key_queue)
811     opd->key_cond = 0;
812   
813   *r_key = queue_item->key;
814   free (queue_item);
815   return 0;
816 }
817
818
819 /* Terminate a pending keylist operation within CTX.  */
820 gpgme_error_t
821 gpgme_op_keylist_end (gpgme_ctx_t ctx)
822 {
823   if (!ctx)
824     return gpg_error (GPG_ERR_INV_VALUE);
825
826   return 0;
827 }
828
829 \f
830 /* Get the key with the fingerprint FPR from the crypto backend.  If
831    SECRET is true, get the secret key.  */
832 gpgme_error_t
833 gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
834                int secret)
835 {
836   gpgme_ctx_t listctx;
837   gpgme_error_t err;
838   gpgme_key_t key;
839
840   if (!ctx || !r_key)
841     return gpg_error (GPG_ERR_INV_VALUE);
842   
843   if (strlen (fpr) < 16)        /* We have at least a key ID.  */
844     return gpg_error (GPG_ERR_INV_VALUE);
845
846   /* FIXME: We use our own context because we have to avoid the user's
847      I/O callback handlers.  */
848   err = gpgme_new (&listctx);
849   if (err)
850     return err;
851   gpgme_set_protocol (listctx, gpgme_get_protocol (ctx));
852   gpgme_set_keylist_mode (listctx, ctx->keylist_mode);
853   err = gpgme_op_keylist_start (listctx, fpr, secret);
854   if (!err)
855     err = gpgme_op_keylist_next (listctx, r_key);
856   if (!err)
857     {
858       err = gpgme_op_keylist_next (listctx, &key);
859       if (gpgme_err_code (err) == GPG_ERR_EOF)
860         err = gpg_error (GPG_ERR_NO_ERROR);
861       else
862         {
863           if (!err)
864             {
865               gpgme_key_unref (key);
866               err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
867             }
868           gpgme_key_unref (*r_key);
869         }
870     }
871   gpgme_release (listctx);
872   return err;
873 }