2002-12-04 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 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
31 #include "util.h"
32 #include "context.h"
33 #include "ops.h"
34 #include "key.h"
35
36 \f
37 struct keylist_result_s
38 {
39   int truncated;
40   GpgmeData xmlinfo;
41 };
42
43
44 void
45 _gpgme_release_keylist_result (KeylistResult result)
46 {
47   if (!result)
48     return;
49   free (result);
50 }
51
52
53 /* Append some XML info.  args is currently ignore but we might want
54    to add more information in the future (like source of the
55    keylisting.  With args of NULL the XML structure is closed.  */
56 static void
57 append_xml_keylistinfo (GpgmeData *rdh, char *args)
58 {
59   GpgmeData dh;
60
61   if (!*rdh)
62     {
63       if (gpgme_data_new (rdh))
64         return; /* FIXME: We are ignoring out-of-core.  */
65       dh = *rdh;
66       _gpgme_data_append_string (dh, "<GnupgOperationInfo>\n");
67     }
68   else
69     {
70       dh = *rdh;
71       _gpgme_data_append_string (dh, "  </keylisting>\n");
72     }
73
74   if (!args)
75     {
76       /* Just close the XML containter.  */
77       _gpgme_data_append_string (dh, "</GnupgOperationInfo>\n");
78       return;
79     }
80
81   _gpgme_data_append_string (dh, "  <keylisting>\n    <truncated/>\n");
82     
83 }
84
85
86 static void
87 keylist_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
88 {
89   if (ctx->error)
90     return;
91   test_and_allocate_result (ctx, keylist);
92
93    switch (code)
94     {
95     case GPGME_STATUS_TRUNCATED:
96       ctx->result.keylist->truncated = 1;
97       break;
98
99     case GPGME_STATUS_EOF:
100       if (ctx->result.keylist->truncated)
101         append_xml_keylistinfo (&ctx->result.keylist->xmlinfo, "1");
102       if (ctx->result.keylist->xmlinfo)
103         {
104           append_xml_keylistinfo (&ctx->result.keylist->xmlinfo, NULL);
105           _gpgme_set_op_info (ctx, ctx->result.keylist->xmlinfo);
106           ctx->result.keylist->xmlinfo = NULL;
107         }
108       break;
109
110     default:
111       /* Ignore all other codes.  */
112       break;
113     }
114 }
115
116 \f
117 static time_t
118 parse_timestamp (char *timestamp)
119 {
120   if (!*timestamp)
121     return 0;
122
123   return (time_t) strtoul (timestamp, NULL, 10);
124 }
125
126
127 static void
128 set_mainkey_trust_info (GpgmeKey key, const char *src)
129 {
130   /* Look at letters and stop at the first digit.  */
131   while (*src && !isdigit (*src))
132     {
133       switch (*src)
134         {
135         case 'e':
136           key->keys.flags.expired = 1;
137           break;
138
139         case 'r':
140           key->keys.flags.revoked = 1;
141           break;
142
143         case 'd':
144           key->keys.flags.disabled = 1;
145           break;
146
147         case 'i':
148           key->keys.flags.invalid = 1;
149           break;
150         }
151       src++;
152     }
153 }
154
155
156 static void
157 set_userid_flags (GpgmeKey key, const char *src)
158 {
159   struct user_id_s *uid = key->last_uid;
160
161   assert (uid);
162   /* Look at letters and stop at the first digit.  */
163   while (*src && !isdigit (*src))
164     {
165       switch (*src)
166         {
167         case 'r':
168           uid->revoked = 1;
169           break;
170           
171         case 'i':
172           uid->invalid = 1;
173           break;
174
175         case 'n':
176           uid->validity = GPGME_VALIDITY_NEVER;
177           break;
178
179         case 'm':
180           uid->validity = GPGME_VALIDITY_MARGINAL;
181           break;
182
183         case 'f':
184           uid->validity = GPGME_VALIDITY_FULL;
185           break;
186
187         case 'u':
188           uid->validity = GPGME_VALIDITY_ULTIMATE;
189           break;
190         }
191       src++;
192     }
193 }
194
195
196 static void
197 set_subkey_trust_info (struct subkey_s *subkey, const char *src)
198 {
199   /* Look at letters and stop at the first digit.  */
200   while (*src && !isdigit (*src))
201     {
202       switch (*src)
203         {
204         case 'e':
205           subkey->flags.expired = 1;
206           break;
207
208         case 'r':
209           subkey->flags.revoked = 1;
210           break;
211
212         case 'd':
213           subkey->flags.disabled = 1;
214           break;
215
216         case 'i':
217           subkey->flags.invalid = 1;
218           break;
219         }
220       src++;
221     }
222 }
223
224
225 static void
226 set_mainkey_capability (GpgmeKey key, const char *src)
227 {
228   while (*src)
229     {
230       switch (*src)
231         {
232         case 'e':
233           key->keys.flags.can_encrypt = 1;
234           break;
235
236         case 's':
237           key->keys.flags.can_sign = 1;
238           break;
239
240         case 'c':
241           key->keys.flags.can_certify = 1;
242           break;
243
244         case 'E':
245           key->gloflags.can_encrypt = 1;
246           break;
247
248         case 'S':
249           key->gloflags.can_sign = 1;
250           break;
251
252         case 'C':
253           key->gloflags.can_certify = 1;
254           break;
255         }
256       src++;
257     }
258 }
259
260
261 static void
262 set_subkey_capability (struct subkey_s *subkey, const char *src)
263 {
264   while (*src)
265     {
266       switch (*src)
267         {
268         case 'e':
269           subkey->flags.can_encrypt = 1;
270           break;
271
272         case 's':
273           subkey->flags.can_sign = 1;
274           break;
275
276         case 'c':
277           subkey->flags.can_certify = 1;
278           break;
279         }
280       src++;
281     }
282 }
283
284 static void
285 set_ownertrust (GpgmeKey key, const char *src)
286 {
287   /* Look at letters and stop at the first digit.  */
288   while (*src && !isdigit (*src))
289     {
290       switch (*src)
291         {
292         case 'n':
293           key->otrust = GPGME_VALIDITY_NEVER;
294           break;
295
296         case 'm':
297           key->otrust = GPGME_VALIDITY_MARGINAL;
298           break;
299
300         case 'f':
301           key->otrust = GPGME_VALIDITY_FULL;
302           break;
303
304         case 'u':
305           key->otrust = GPGME_VALIDITY_ULTIMATE;
306           break;
307
308         default:
309           key->otrust = GPGME_VALIDITY_UNKNOWN;
310           break;
311         }
312       src++;
313     }
314 }
315
316
317 /* We have read an entire key into ctx->tmp_key and should now finish
318    it.  It is assumed that this releases ctx->tmp_key.  */
319 static void
320 finish_key (GpgmeCtx ctx)
321 {
322   GpgmeKey key = ctx->tmp_key;
323
324   ctx->tmp_key = NULL;
325
326   if (key)
327     _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_KEY, key);
328 }
329
330
331 /* Note: We are allowed to modify LINE.  */
332 static void
333 keylist_colon_handler (GpgmeCtx ctx, char *line)
334 {
335   enum
336     {
337       RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR, RT_SSB, RT_SEC,
338       RT_CRT, RT_CRS, RT_REV
339     }
340   rectype = RT_NONE;
341 #define NR_FIELDS 13
342   char *field[NR_FIELDS];
343   int fields = 0;
344   GpgmeKey key = ctx->tmp_key;
345   struct subkey_s *subkey = NULL;
346   struct certsig_s *certsig = NULL;
347
348   DEBUG3 ("keylist_colon_handler ctx = %p, key = %p, line = %s\n",
349           ctx, key, line ? line : "(null)");
350
351   if (ctx->error)
352     return;
353
354   if (!line)
355     {
356       /* End Of File.  */
357       finish_key (ctx);
358       return; 
359     }
360
361   while (line && fields < NR_FIELDS)
362     {
363       field[fields++] = line;
364       line = strchr (line, ':');
365       if (line)
366         *(line++) = '\0';
367     }
368
369   if (!strcmp (field[0], "sig"))
370     rectype = RT_SIG;
371   else if (!strcmp (field[0], "rev"))
372     rectype = RT_REV;
373   else if (!strcmp (field[0], "uid") && key)
374     rectype = RT_UID;
375   else if (!strcmp (field[0], "sub") && key)
376     {
377       /* Start a new subkey.  */
378       rectype = RT_SUB; 
379       if (!(subkey = _gpgme_key_add_subkey (key)))
380         {
381           ctx->error = mk_error (Out_Of_Core);
382           return;
383         }
384     }
385   else if (!strcmp (field[0], "ssb") && key)
386     {
387       /* Start a new secret subkey.  */
388       rectype = RT_SSB;
389       if (!(subkey = _gpgme_key_add_secret_subkey (key)))
390         {
391           ctx->error = mk_error (Out_Of_Core);
392           return;
393         }
394     }
395   else if (!strcmp (field[0], "pub"))
396     {
397       /* Start a new keyblock.  */
398       if (_gpgme_key_new (&key))
399         {
400           /* The only kind of error we can get.  */
401           ctx->error = mk_error (Out_Of_Core);
402           return;
403         }
404       rectype = RT_PUB;
405       finish_key (ctx);
406       assert (!ctx->tmp_key);
407       ctx->tmp_key = key;
408     }
409   else if (!strcmp (field[0], "sec"))
410     {
411       /* Start a new keyblock,  */
412       if (_gpgme_key_new_secret (&key))
413         {
414           /* The only kind of error we can get.  */
415           ctx->error = mk_error (Out_Of_Core);
416           return;
417         }
418       rectype = RT_SEC;
419       finish_key (ctx);
420       assert (!ctx->tmp_key);
421       ctx->tmp_key = key;
422     }
423   else if (!strcmp (field[0], "crt"))
424     {
425       /* Start a new certificate.  */
426       if (_gpgme_key_new (&key))
427         {
428           /* The only kind of error we can get.  */
429           ctx->error = mk_error (Out_Of_Core);
430           return;
431         }
432       key->x509 = 1;
433       rectype = RT_CRT;
434       finish_key (ctx);
435       assert (!ctx->tmp_key);
436       ctx->tmp_key = key;
437     }
438   else if (!strcmp (field[0], "crs"))
439     {
440       /* Start a new certificate.  */
441       if (_gpgme_key_new_secret (&key))
442         {
443           /* The only kind of error we can get.  */
444           ctx->error = mk_error (Out_Of_Core);
445           return;
446         }
447       key->x509 = 1;
448       rectype = RT_CRS;
449       finish_key (ctx);
450       assert (!ctx->tmp_key);
451       ctx->tmp_key = key;
452     }
453   else if (!strcmp (field[0], "fpr") && key) 
454     rectype = RT_FPR;
455   else 
456     rectype = RT_NONE;
457
458   /* Only look at signatures immediately following a user ID.  For
459      this, clear the user ID pointer when encountering anything but a
460      signature.  */
461   if (rectype != RT_SIG && rectype != RT_REV)
462     ctx->tmp_uid = NULL;
463
464   switch (rectype)
465     {
466     case RT_CRT:
467     case RT_CRS:
468       /* Field 8 has the X.509 serial number.  */
469       if (fields >= 8)
470         {
471           key->issuer_serial = strdup (field[7]);
472           if (!key->issuer_serial)
473             ctx->error = mk_error (Out_Of_Core);
474         }
475
476       /* Field 10 is not used for gpg due to --fixed-list-mode option
477          but GPGSM stores the issuer name.  */
478       if (fields >= 10 && _gpgme_decode_c_string (field[9],
479                                                   &key->issuer_name, 0))
480           ctx->error = mk_error (Out_Of_Core);
481       /* Fall through!  */
482
483     case RT_PUB:
484     case RT_SEC:
485       /* Field 2 has the trust info.  */
486       if (fields >= 2)
487         set_mainkey_trust_info (key, field[1]);
488
489       /* Field 3 has the key length.  */
490       if (fields >= 3)
491         {
492           int i = atoi (field[2]);
493           /* Ignore invalid values.  */
494           if (i > 1)
495             key->keys.key_len = i; 
496         }
497
498       /* Field 4 has the public key algorithm.  */
499       if (fields >= 4)
500         {
501           int i = atoi (field[3]);
502           if (i >= 1 && i < 128)
503             key->keys.key_algo = i;
504         }
505
506       /* Field 5 has the long keyid.  */
507       if (fields >= 5 && strlen (field[4]) == DIM(key->keys.keyid) - 1)
508         strcpy (key->keys.keyid, field[4]);
509
510       /* Field 6 has the timestamp (seconds).  */
511       if (fields >= 6)
512         key->keys.timestamp = parse_timestamp (field[5]);
513
514       /* Field 7 has the expiration time (seconds).  */
515       if (fields >= 7)
516         key->keys.expires_at = parse_timestamp (field[6]);
517
518       /* Field 9 has the ownertrust.  */
519       if (fields >= 9)
520         set_ownertrust (key, field[8]);
521
522       /* Field 11 has the signature class.  */
523
524       /* Field 12 has the capabilities.  */
525       if (fields >= 12)
526         set_mainkey_capability (key, field[11]);
527       break;
528
529     case RT_SUB:
530     case RT_SSB:
531       /* Field 2 has the trust info.  */
532       if (fields >= 2)
533         set_subkey_trust_info (subkey, field[1]);
534
535       /* Field 3 has the key length.  */
536       if (fields >= 3)
537         {
538           int i = atoi (field[2]);
539           /* Ignore invalid values.  */
540           if (i > 1)
541             subkey->key_len = i;
542         }
543
544       /* Field 4 has the public key algorithm.  */
545       if (fields >= 4)
546         {
547           int i = atoi (field[3]);
548           if (i >= 1 && i < 128)
549             subkey->key_algo = i;
550         }
551
552       /* Field 5 has the long keyid.  */
553       if (fields >= 5 && strlen (field[4]) == DIM(subkey->keyid) - 1)
554         strcpy (subkey->keyid, field[4]);
555
556       /* Field 6 has the timestamp (seconds).  */
557       if (fields >= 6)
558         subkey->timestamp = parse_timestamp (field[5]);
559
560       /* Field 7 has the expiration time (seconds).  */
561       if (fields >= 7)
562         subkey->expires_at = parse_timestamp (field[6]);
563
564       /* Field 8 is reserved (LID).  */
565       /* Field 9 has the ownertrust.  */
566       /* Field 10, the user ID, is n/a for a subkey.  */
567       
568       /* Field 11 has the signature class.  */
569
570       /* Field 12 has the capabilities.  */
571       if (fields >= 12)
572         set_subkey_capability (subkey, field[11]);
573       break;
574
575     case RT_UID:
576       /* Field 2 has the trust info, and field 10 has the user ID.  */
577       if (fields >= 10)
578         {
579           if (_gpgme_key_append_name (key, field[9]))
580             ctx->error = mk_error (Out_Of_Core);
581           else
582             {
583               if (field[1])
584                 set_userid_flags (key, field[1]);
585               ctx->tmp_uid = key->last_uid;
586             }
587         }
588       break;
589
590     case RT_FPR:
591       /* Field 10 has the fingerprint (take only the first one).  */
592       if (fields >= 10 && !key->keys.fingerprint && field[9] && *field[9])
593         {
594           key->keys.fingerprint = strdup (field[9]);
595           if (!key->keys.fingerprint)
596             ctx->error = mk_error (Out_Of_Core);
597         }
598
599       /* Field 13 has the gpgsm chain ID (take only the first one).  */
600       if (fields >= 13 && !key->chain_id && *field[12])
601         {
602           key->chain_id = strdup (field[12]);
603           if (!key->chain_id)
604             ctx->error = mk_error (Out_Of_Core);
605         }
606       break;
607
608     case RT_SIG:
609     case RT_REV:
610       if (!ctx->tmp_uid)
611         return;
612
613       /* Start a new (revoked) signature.  */
614       assert (ctx->tmp_uid == key->last_uid);
615       certsig = _gpgme_key_add_certsig (key, (fields >= 10) ? field[9] : NULL);
616       if (!certsig)
617         {
618           ctx->error = mk_error (Out_Of_Core);
619           return;
620         }
621
622       /* Field 2 has the calculated trust ('!', '-', '?', '%').  */
623       if (fields >= 2)
624         switch (field[1][0])
625           {
626           case '!':
627             certsig->sig_stat = GPGME_SIG_STAT_GOOD;
628             break;
629
630           case '-':
631             certsig->sig_stat = GPGME_SIG_STAT_BAD;
632             break;
633
634           case '?':
635             certsig->sig_stat = GPGME_SIG_STAT_NOKEY;
636             break;
637
638           case '%':
639             certsig->sig_stat = GPGME_SIG_STAT_ERROR;
640             break;
641
642           default:
643             certsig->sig_stat = GPGME_SIG_STAT_NONE;
644             break;
645           }
646
647       /* Field 4 has the public key algorithm.  */
648       if (fields >= 4)
649         {
650           int i = atoi (field[3]);
651           if (i >= 1 && i < 128)
652             certsig->algo = i;
653         }
654       
655       /* Field 5 has the long keyid.  */
656       if (fields >= 5 && strlen (field[4]) == DIM(certsig->keyid) - 1)
657         strcpy (certsig->keyid, field[4]);
658       
659       /* Field 6 has the timestamp (seconds).  */
660       if (fields >= 6)
661         certsig->timestamp = parse_timestamp (field[5]);
662
663       /* Field 7 has the expiration time (seconds).  */
664       if (fields >= 7)
665         certsig->expires_at = parse_timestamp (field[6]);
666
667       /* Field 11 has the signature class (eg, 0x30 means revoked).  */
668       if (fields >= 11)
669         if (field[10][0] && field[10][1])
670           {
671             int class = _gpgme_hextobyte (field[10]);
672             if (class >= 0)
673               {
674                 certsig->sig_class = class;
675                 if (class == 0x30)
676                   certsig->flags.revoked = 1;
677               }
678             if (field[10][2] == 'x')
679               certsig->flags.exportable = 1;
680           }
681       break;
682
683     case RT_NONE:
684       /* Unknown record.  */
685       break;
686     }
687 }
688
689
690 void
691 _gpgme_op_keylist_event_cb (void *data, GpgmeEventIO type, void *type_data)
692 {
693   GpgmeCtx ctx = (GpgmeCtx) data;
694   GpgmeKey key = (GpgmeKey) type_data;
695   struct key_queue_item_s *q, *q2;
696
697   assert (type == GPGME_EVENT_NEXT_KEY);
698
699   _gpgme_key_cache_add (key);
700
701   q = malloc (sizeof *q);
702   if (!q)
703     {
704       gpgme_key_release (key);
705       ctx->error = mk_error (Out_Of_Core);
706       return;
707     }
708   q->key = key;
709   q->next = NULL;
710   /* FIXME: Lock queue.  Use a tail pointer?  */
711   if (!(q2 = ctx->key_queue))
712     ctx->key_queue = q;
713   else
714     {
715       for (; q2->next; q2 = q2->next)
716         ;
717       q2->next = q;
718     }
719   ctx->key_cond = 1;
720   /* FIXME: Unlock queue.  */
721 }
722
723
724 /**
725  * gpgme_op_keylist_start:
726  * @c: context 
727  * @pattern: a GnuPG user ID or NULL for all
728  * @secret_only: List only keys where the secret part is available
729  * 
730  * Note that this function also cancels a pending key listing
731  * operaton. To actually retrieve the key, use
732  * gpgme_op_keylist_next().
733  * 
734  * Return value:  0 on success or an errorcode. 
735  **/
736 GpgmeError
737 gpgme_op_keylist_start (GpgmeCtx ctx, const char *pattern, int secret_only)
738 {
739   GpgmeError err = 0;
740
741   err = _gpgme_op_reset (ctx, 2);
742   if (err)
743     goto leave;
744
745   gpgme_key_release (ctx->tmp_key);
746   ctx->tmp_key = NULL;
747   /* Fixme: Release key_queue.  */
748
749   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
750   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
751                                               keylist_colon_handler, ctx);
752   if (err)
753     goto leave;
754
755   /* We don't want to use the verbose mode as this will also print the
756      key signatures which is in most cases not needed and furthermore
757      we just ignore those lines - This should speed up things.  */
758   _gpgme_engine_set_verbosity (ctx->engine, 0);
759
760   err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only,
761                                   ctx->keylist_mode);
762
763   if (!err)     /* And kick off the process.  */
764     err = _gpgme_engine_start (ctx->engine, ctx);
765
766  leave:
767   if (err)
768     {
769       ctx->pending = 0; 
770       _gpgme_engine_release (ctx->engine);
771       ctx->engine = NULL;
772     }
773   return err;
774 }
775
776
777 /**
778  * gpgme_op_keylist_ext_start:
779  * @c: context 
780  * @pattern: a NULL terminated array of search patterns
781  * @secret_only: List only keys where the secret part is available
782  * @reserved: Should be 0.
783  * 
784  * Note that this function also cancels a pending key listing
785  * operaton. To actually retrieve the key, use
786  * gpgme_op_keylist_next().
787  * 
788  * Return value:  0 on success or an errorcode. 
789  **/
790 GpgmeError
791 gpgme_op_keylist_ext_start (GpgmeCtx ctx, const char *pattern[],
792                             int secret_only, int reserved)
793 {
794   GpgmeError err = 0;
795
796   err = _gpgme_op_reset (ctx, 2);
797   if (err)
798     goto leave;
799
800   gpgme_key_release (ctx->tmp_key);
801   ctx->tmp_key = NULL;
802
803   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
804   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
805                                               keylist_colon_handler, ctx);
806   if (err)
807     goto leave;
808
809   /* We don't want to use the verbose mode as this will also print the
810      key signatures which is in most cases not needed and furthermore
811      we just ignore those lines - This should speed up things.  */
812   _gpgme_engine_set_verbosity (ctx->engine, 0);
813
814   err = _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only,
815                                       reserved, ctx->keylist_mode);
816
817   /* And kick off the process.  */
818   if (!err)
819     err = _gpgme_engine_start (ctx->engine, ctx);
820
821  leave:
822   if (err)
823     {
824       ctx->pending = 0; 
825       _gpgme_engine_release (ctx->engine);
826       ctx->engine = NULL;
827     }
828   return err;
829 }
830
831
832 /**
833  * gpgme_op_keylist_next:
834  * @c: Context
835  * @r_key: Returned key object
836  * 
837  * Return the next key from the key listing started with
838  * gpgme_op_keylist_start().  The caller must free the key using
839  * gpgme_key_release().  If the last key has already been returned the
840  * last time the function was called, %GPGME_EOF is returned and the
841  * operation is finished.
842  * 
843  * Return value: 0 on success, %GPGME_EOF or another error code.
844  **/
845 GpgmeError
846 gpgme_op_keylist_next (GpgmeCtx ctx, GpgmeKey *r_key)
847 {
848   struct key_queue_item_s *queue_item;
849
850   if (!r_key)
851     return mk_error (Invalid_Value);
852   *r_key = NULL;
853   if (!ctx)
854     return mk_error (Invalid_Value);
855   if (!ctx->pending)
856     return mk_error (No_Request);
857   if (ctx->error)
858     return ctx->error;
859
860   if (!ctx->key_queue)
861     {
862       GpgmeError err = _gpgme_wait_on_condition (ctx, &ctx->key_cond);
863       if (err)
864         {
865           ctx->pending = 0;
866           return err;
867         }
868       if (!ctx->pending)
869         {
870           /* The operation finished.  Because not all keys might have
871              been returned to the caller yet, we just reset the
872              pending flag to 1.  This will cause us to call
873              _gpgme_wait_on_condition without any active file
874              descriptors, but that is a no-op, so it is safe.  */
875           ctx->pending = 1;
876         }
877       if (!ctx->key_cond)
878         {
879           ctx->pending = 0;
880           return mk_error (EOF);
881         }
882       ctx->key_cond = 0; 
883       assert (ctx->key_queue);
884     }
885   queue_item = ctx->key_queue;
886   ctx->key_queue = queue_item->next;
887   if (!ctx->key_queue)
888     ctx->key_cond = 0;
889   
890   *r_key = queue_item->key;
891   free (queue_item);
892   return 0;
893 }
894
895
896 /**
897  * gpgme_op_keylist_end:
898  * @c: Context
899  * 
900  * Ends the keylist operation and allows to use the context for some
901  * other operation next.
902  **/
903 GpgmeError
904 gpgme_op_keylist_end (GpgmeCtx ctx)
905 {
906   if (!ctx)
907     return mk_error (Invalid_Value);
908   if (!ctx->pending)
909     return mk_error (No_Request);
910   if (ctx->error)
911     return ctx->error;
912
913   ctx->pending = 0;
914   return 0;
915 }