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