/[winpt]/trunk/Src/wptKeyCache.cpp
ViewVC logotype

Contents of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 147 - (show annotations)
Fri Jan 13 14:21:16 2006 UTC (19 years, 1 month ago) by twoaday
File size: 18636 byte(s)
2006-11-13  Timo Schulz  <ts@g10code.com>
 
        * wptPreferencesDlg.cpp (prefs_dlg_proc): Changed translation.
        * wptGPGPrefsDlg.cpp (gpgprefs_dlg_proc): Likewise.
        * wptAboutDlgs.cpp (about_dlg_proc): Make sure GPG about
        dialog isn't shown twice.
        * wptKeyCache.cpp (gpg_keycache_next_updated_key): New.
        (gpg_keycache_update_key): Set update flag.
        * wptKeyManagerDlg.cpp (refresh_keylist): New.
        (keymanager_dlg_proc): Use new refresh system for keyservers.
        * wptKeyserverSearchDlg.cpp (kserver_search_dlg_proc):
        Update keycache.
        * wptKeyserverDlg.cpp (hkp_dlg_proc): Likewise.
        * wptKeyserver.cpp (socket_read_ext): New.
        (kserver_recv_key_ext): New.
        (kserver_read_config, kserver_write_config): Removed.
         


1 /* wptKeyCache.cpp- Caching for the pub- and the secring
2 * Copyright (C) 2001-2006 Timo Schulz
3 *
4 * This file is part of MyGPGME.
5 *
6 * MyGPGME is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * MyGPGME is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <windows.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <malloc.h>
29 #include <ctype.h>
30 #include <assert.h>
31 #include <gpgme.h>
32
33 #include "wptKeyCache.h"
34 #include "openpgp.h"
35 #include "wptNLS.h"
36 #include "wptErrors.h"
37 #include "wptW32API.h"
38 #include "wptGPG.h"
39
40
41 /* Attribute list which holds the image data. */
42 struct attr_list_s {
43 struct attr_list_s *next;
44 char *fpr; /* fingerprint of the key */
45 unsigned char *d; /* actual JPEG data. */
46 unsigned long octets; /* length of the data. */
47 unsigned int flags; /* status of the attribute. */
48 };
49 typedef struct attr_list_s *attr_list_t;
50
51
52 void
53 free_attr_list (attr_list_t ctx)
54 {
55 attr_list_t n;
56 while (ctx) {
57 n = ctx->next;
58 free (ctx->fpr);
59 free (ctx->d);
60 ctx = n;
61 }
62 }
63
64 /* Parse the attribute list in @fp and store it into @ctx.
65 Return value: number of parsed items. */
66 int
67 parse_attr_list (FILE *fp, const BYTE *data, DWORD datlen, attr_list_t *ctx)
68 {
69 attr_list_t c, t;
70 char buf[512], *p, *buffer;
71 int pos, n=0;
72
73 *ctx = NULL;
74 while (fgets (buf, 511, fp)) {
75 if (strstr (buf, "\r\n"))
76 buf[strlen (buf)-2]=0;
77 if (strstr (buf, "\n"))
78 buf[strlen (buf)-1]=0;
79 if (strlen (buf) < 2 || !strstr (buf, "ATTRIBUTE"))
80 continue;
81 buffer = buf+9+10;
82 pos = 0;
83 c = (attr_list_t)calloc (1, sizeof *c);
84 p = strtok (buffer, " ");
85 while (p != NULL) {
86 switch (pos) {
87 case 0:
88 c->fpr = strdup (p);
89 break;
90
91 case 1:
92 c->octets = strtoul (p, NULL, 10);
93 break;
94
95 case 7:
96 c->flags = strtoul (p, NULL, 10);
97 break;
98
99 default:
100 break;
101 }
102 pos++;
103 p = strtok (NULL, " ");
104 }
105 /*printf ("id=%s octets=%d flags=%d\n", c->fpr, c->octets, c->flags);*/
106 if (!*ctx)
107 *ctx = c;
108 else {
109 for (t = *ctx; t->next; t=t->next)
110 ;
111 t->next = c;
112 }
113 c->d = (unsigned char*)malloc (c->octets);
114 memcpy (c->d, data, c->octets);
115 data += c->octets;
116 datlen -= c->octets;
117 n++;
118 }
119 /*assert (datlen == 0); */
120 return n;
121 }
122
123
124 static int
125 parse_attr_data (const char *keyid, attr_list_t *list)
126 {
127 gpgme_error_t err;
128 FILE *tmp;
129 char *status;
130 BYTE *data;
131 DWORD ndata;
132
133 err = gpg_get_photoid_data (keyid, &status, &data, &ndata);
134 if (err)
135 return err;
136
137 if (ndata > 0) {
138 tmp = tmpfile ();
139 fwrite (status, 1, strlen (status), tmp);
140 fflush (tmp);
141 rewind (tmp);
142
143 ndata = parse_attr_list (tmp, data, ndata, list);
144 fclose (tmp);
145 }
146 else
147 *list = NULL;
148
149 safe_free (status);
150 safe_free (data);
151 return ndata;
152 }
153
154
155 /* Parse the secret keyring and retrieve some additional information
156 for each key which was found. */
157 static void
158 parse_secring (gpg_keycache_t cache, const char *kid, const char *secring)
159 {
160 PACKET *pkt;
161 PKT_secret_key *sk;
162 gpg_iobuf_t inp;
163 gpgme_error_t err;
164 gpgme_key_t key;
165 struct keycache_s *c=NULL;
166 char keyid[16+1];
167
168 inp = gpg_iobuf_open (secring);
169 if (!inp)
170 return;
171
172 gpg_iobuf_ioctl (inp, 3, 1, NULL);
173 pkt = (PACKET*)calloc (1, sizeof *pkt);
174 gpg_init_packet (pkt);
175 while (gpg_parse_packet (inp, pkt) != -1) {
176 if (pkt->pkttype == PKT_SECRET_KEY) {
177 sk = pkt->pkt.secret_key;
178 /* XXX: key IDs of card public keys are wrong! */
179 _snprintf (keyid, sizeof (keyid)-1, "%08lX",
180 gpg_keyid_from_sk (sk, NULL));
181 if (kid && strcmp (kid, keyid) != 0)
182 goto next;
183 err = gpg_keycache_find_key2 (cache, keyid, 0, &key, &c);
184 if (err)
185 goto next;
186 c->gloflags.is_protected = sk->is_protected;
187 c->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
188 if (c->pubpart != NULL) {
189 c->pubpart->gloflags.is_protected = sk->is_protected;
190 c->pubpart->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
191 }
192 }
193 next:
194 gpg_free_packet (pkt);
195 gpg_init_packet (pkt);
196 }
197 safe_free (pkt);
198 gpg_iobuf_close (inp);
199 }
200
201
202 /* Update the photo image of a single key with the fingerprint
203 @fpr. The @dat struct contains the new item data. */
204 static gpgme_error_t
205 keycache_update_photo (gpg_keycache_t ctx, const char *fpr, attr_list_t dat)
206 {
207 struct keycache_s *fnd = NULL;
208 gpgme_key_t key;
209
210 gpg_keycache_find_key2 (ctx, fpr, 0, &key, &fnd);
211 if (!fnd)
212 return gpg_error (GPG_ERR_NOT_FOUND);
213 safe_free (fnd->attrib.d);
214 fnd->attrib.flags = dat->flags;
215 fnd->attrib.len = dat->octets;
216 fnd->attrib.d = (unsigned char*)malloc (dat->octets);
217 memcpy (fnd->attrib.d, dat->d, dat->octets);
218 return 0;
219 }
220
221
222 /* Update all photo images in the cache. */
223 static gpgme_error_t
224 keycache_update_photos (gpg_keycache_t ctx)
225 {
226 attr_list_t list=NULL, n;
227 DWORD ndata;
228
229 ndata = parse_attr_data (NULL, &list);
230 if (ndata < 1) {
231 free_attr_list (list);
232 return 0;
233 }
234
235 for (n=list; n; n=n->next)
236 keycache_update_photo (ctx, n->fpr, n);
237 free_attr_list (list);
238 return 0;
239 }
240
241
242 /* Merge the information from the keyrings into the key cache structure. */
243 gpgme_error_t
244 keycache_prepare2 (gpg_keycache_t ctx, const char *kid,
245 const char *pubring, const char *secring)
246 {
247 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
248 gpgme_key_t key = NULL;
249 gpg_iobuf_t inp;
250 PACKET *pkt;
251 struct keycache_s *c;
252 const byte *sym_prefs;
253 char keyid[16+1];
254 int key_seen = 0;
255 size_t nsym =0;
256
257 if (secring) {
258 parse_secring (ctx, kid, secring);
259 if (!pubring)
260 return 0;
261 }
262 inp = gpg_iobuf_open (pubring);
263 if (!inp)
264 return gpg_error (GPG_ERR_KEYRING_OPEN);
265 gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */
266
267 pkt = (PACKET*)calloc (1, sizeof * pkt);
268 gpg_init_packet (pkt);
269 while (gpg_parse_packet (inp, pkt) != -1) {
270 if (pkt->pkttype == PKT_PUBLIC_KEY) {
271 strcpy (keyid, "");
272 key_seen = 1;
273 }
274
275 if (pkt->pkttype == PKT_SIGNATURE &&
276 pkt->pkt.signature->sig_class == 0x1F) {
277 if (pkt->pkt.signature->numrevkeys == 0)
278 goto next;
279 _snprintf (keyid, sizeof (keyid) -1, "%08X",
280 pkt->pkt.signature->keyid[1]);
281 if (kid && strcmp (kid, keyid) != 0)
282 goto next;
283 err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
284 if (err)
285 goto next;
286 c->gloflags.has_desig_rev = 1;
287 }
288 if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 ) {
289 sym_prefs = gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,
290 SIGSUBPKT_PREF_SYM, &nsym);
291 if (!sym_prefs)
292 goto next;
293 _snprintf (keyid, sizeof (keyid) - 1, "%08X",
294 pkt->pkt.signature->keyid[1]);
295 if (kid && strcmp (kid, keyid) != 0)
296 goto next;
297 err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
298 if (err)
299 goto next;
300 else if (nsym > 0) {
301 c->sym_prefs = (unsigned char*)calloc (1, nsym+1);
302 if (!c->sym_prefs)
303 return gpg_error (GPG_ERR_ENOMEM);
304 memcpy (c->sym_prefs, sym_prefs, nsym);
305 }
306 }
307 next:
308 gpg_free_packet (pkt);
309 gpg_init_packet(pkt);
310 }
311
312 safe_free (pkt);
313 gpg_iobuf_close (inp);
314 return err;
315 }
316
317
318 gpgme_error_t
319 gpg_keycache_prepare (gpg_keycache_t ctx, const char *pubr, const char *secr)
320 {
321 return keycache_prepare2 (ctx, NULL, pubr, secr);
322 }
323
324 gpgme_error_t
325 gpg_keycache_prepare_single (gpg_keycache_t ctx, const char *keyid,
326 const char *pubr, const char *secr)
327 {
328 if (!strncmp (keyid, "0x", 2))
329 keyid += 2;
330 return keycache_prepare2 (ctx, keyid, pubr, secr);
331 }
332
333
334 /* Create new keycache object and return it in @r_ctx.
335 Return value: 0 on success. */
336 gpgme_error_t
337 gpg_keycache_new (gpg_keycache_t *r_ctx)
338 {
339 gpg_keycache_t ctx;
340
341 if (!r_ctx)
342 return gpg_error (GPG_ERR_INV_ARG);
343 ctx = (gpg_keycache_t)calloc (1, sizeof *ctx);
344 if (!ctx)
345 return gpg_error (GPG_ERR_ENOMEM);
346 ctx->secret = 0;
347 ctx->pos = 0;
348 *r_ctx = ctx;
349 return 0;
350 }
351
352
353 /* Release keycache object @ctx. */
354 void
355 gpg_keycache_release (gpg_keycache_t ctx)
356 {
357 struct keycache_s *c, *c2;
358
359 if (!ctx)
360 return;
361
362 for (c = ctx->item; c; c = c2) {
363 c2 = c->next;
364 gpgme_key_release (c->key);
365 c->key = NULL;
366 safe_free (c->sym_prefs);
367 safe_free (c->attrib.d);
368 safe_free (c->card_type);
369 free (c);
370 }
371 safe_free (ctx);
372 }
373
374
375 /* Set (progress) callback for the given keycache object.
376 @ctx the keycache
377 @cb the callback function
378 @cb_value1 opaque value which is passed to the callback.
379 @cb_value2 see @cb_value1. */
380 void
381 gpg_keycache_set_cb (gpg_keycache_t ctx,
382 void (*cb)(void *, const char *, int, int, int),
383 void * cb_value1, int cb_value2)
384 {
385 if (!ctx)
386 return;
387 ctx->cb = cb;
388 ctx->cb_value = cb_value1;
389 ctx->cb_value2 = cb_value2;
390 }
391
392
393 /* Add @key to the cache @ctx. @opaque return the key cache context as a void*.
394 Return value: 0 on success. */
395 gpgme_error_t
396 gpg_keycache_add_key (gpg_keycache_t ctx, gpgme_key_t key, void **opaque)
397 {
398 struct keycache_s *c, *n1;
399
400 if (!ctx)
401 return gpg_error (GPG_ERR_INV_ARG);
402
403 c = (struct keycache_s*)calloc (1, sizeof *c);
404 if (!c)
405 return gpg_error (GPG_ERR_ENOMEM);
406 c->gloflags.is_protected = 1; /*default: assume protection. */
407 c->key = key;
408 if (!ctx->item)
409 ctx->item = c;
410 else {
411 for (n1 = ctx->item; n1 && n1->next; n1 = n1->next)
412 ;
413 n1->next = c;
414 }
415 if (opaque)
416 *opaque = c;
417 return 0;
418 }
419
420
421
422 #define has_keyid_len(pattern) (\
423 strlen (pattern) == 8 || strlen (pattern) == 10 || \
424 strlen (pattern) == 16 || strlen (pattern) == 18)
425
426
427 gpgme_error_t
428 gpg_keycache_find_key2 (gpg_keycache_t ctx, const char *pattern, int flags,
429 gpgme_key_t *r_key, struct keycache_s **r_item)
430 {
431 struct keycache_s *c;
432 gpgme_subkey_t s;
433 gpgme_user_id_t u;
434 gpgme_key_t key;
435 const char *kid;
436
437 if (!ctx || !r_key)
438 return gpg_error (GPG_ERR_INV_ARG);
439
440 if (strstr (pattern, "0x"))
441 pattern += 2;
442
443 /* Sometimes a subkey has no valid fpr. As a kludge we convert v4
444 fingerprints into the 64-bit keyid. */
445 if (strlen (pattern) == 40 && isxdigit (*pattern))
446 pattern += 32;
447
448 /* XXX: this code is very slow, revamp it and use hash tables whenever
449 it is possible. */
450 for (c = ctx->item; c; c = c->next) {
451 key = c->key;
452 assert (key->_refs >= 1);
453 for (s = key->subkeys; s; s = s->next) {
454 for (u = key->uids; u; u = u->next) {
455 if (u->name && stristr (u->name, pattern)) {
456 if (r_item)
457 *r_item = c;
458 *r_key = flags? c->pubpart->key : c->key;
459 return 0;
460 }
461 }
462 if (has_keyid_len (pattern))
463 kid = s->keyid;
464 else
465 kid = s->fpr;
466 if (kid && stristr (kid, pattern)) {
467 if (r_item)
468 *r_item = c;
469 *r_key = flags? c->pubpart->key : c->key;
470 return 0;
471 }
472 }
473 }
474 *r_key = NULL;
475 return gpg_error (GPG_ERR_INTERNAL);
476 }
477
478
479 gpgme_error_t
480 gpg_keycache_find_key (gpg_keycache_t ctx, const char *pattern,
481 int flags, gpgme_key_t *r_key)
482 {
483 return gpg_keycache_find_key2 (ctx, pattern, flags, r_key, NULL);
484 }
485
486
487 /* Reload a photo image of a single key with the keyid @keyid.
488 Return value: 0 on success. */
489 static gpgme_error_t
490 keycache_reload_photo (gpg_keycache_t ctx, const char *keyid)
491 {
492 attr_list_t list;
493
494 if (parse_attr_data (keyid, &list) < 1) {
495 free_attr_list (list);
496 return 0;
497 }
498 keycache_update_photo (ctx, list->fpr, list);
499 free_attr_list (list);
500 return 0;
501 }
502
503
504 /* Return the next key which was updated. Before it is
505 returned the update flag is cleared.
506 Return value: 0 on success. */
507 gpgme_error_t
508 gpg_keycache_next_updated_key (gpg_keycache_t ctx,
509 struct keycache_s **r_obj)
510 {
511 struct keycache_s *c;
512
513 for (c = ctx->item; c; c = c->next) {
514 if (c->flags == 1) {
515 c->flags = 0;
516 *r_obj = c;
517 return 0;
518 }
519 }
520 return gpg_error (GPG_ERR_NOT_FOUND);
521 }
522
523
524
525 gpgme_error_t
526 gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,
527 void *opaque, const char *keyid)
528 {
529 struct keycache_s *c = NULL, *c_new=NULL;
530 gpgme_key_t key=NULL, fndkey=NULL;
531 gpgme_error_t err;
532 gpgme_ctx_t gctx;
533 gpg_keycache_t pub = (gpg_keycache_t)opaque;
534
535 err = gpgme_new (&gctx);
536 if (err)
537 return err;
538 err = gpgme_get_key (gctx, keyid, &key, is_sec);
539 gpgme_release (gctx);
540 if (err)
541 return err;
542 err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);
543 if (!err && c != NULL) {
544 log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);
545 gpgme_key_release (fndkey);
546 c->key = key;
547 c->flags = 1;
548 if (is_sec && pub != NULL &&
549 !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {
550 log_debug ("keycache update: set public part %p\r\n", fndkey);
551 c->pubpart->key = fndkey;
552 }
553 /* XXX: this is also called for keys without a photo-id. */
554 keycache_reload_photo (ctx, keyid);
555 }
556 else {
557 log_debug ("keycache add: sync public part\r\n");
558 if (is_sec)
559 gpg_keycache_find_key2 (pub, keyid, 0, &fndkey, &c_new);
560 gpg_keycache_add_key (ctx, key, (void **)&c);
561 if (c != NULL && is_sec) {
562 log_debug ("keycache add: keyid=%s %p %p\r\n", keyid, c, fndkey);
563 c->pubpart = c_new;
564 if (c_new != NULL) {
565 c->pubpart->key = fndkey;
566 c->gloflags.is_protected = c_new->gloflags.is_protected;
567 c->gloflags.divert_to_card = c_new->gloflags.divert_to_card;
568 }
569 }
570 if (c)
571 c->flags = 1;
572 }
573 return 0;
574 }
575
576
577 /* Delete a key from the cache @ctx with the pattern @pattern.
578 Return value: 0 on success. */
579 gpgme_error_t
580 gpg_keycache_delete_key (gpg_keycache_t ctx, const char *pattern)
581 {
582 struct keycache_s *itm = NULL, *c;
583 gpgme_key_t key;
584 gpgme_error_t rc;
585
586 if (!ctx)
587 return gpg_error (GPG_ERR_INV_ARG);
588 rc = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
589 if (rc)
590 return rc;
591
592 c = ctx->item;
593 if (c->next == NULL) {
594 gpgme_key_release (itm->key);
595 if (itm)
596 free (itm);
597 ctx->item = NULL;
598 }
599 else {
600 while (c && c->next != itm)
601 c = c->next;
602 c->next = c->next->next;
603 gpgme_key_release (itm->key);
604 if (itm)
605 free (itm);
606 }
607 return 0;
608 }
609
610
611 /* Initialize the given cache @ctx. If @pattern is NULL, the entire keyring
612 will be added to the cache. @secret is 1 if the source is the secret keyring.
613 Return value: 0 on success. */
614 gpgme_error_t
615 gpg_keycache_init (gpg_keycache_t ctx, const char *pattern, int secret)
616 {
617 gpgme_error_t err;
618 gpgme_ctx_t c;
619 gpgme_key_t key;
620 int count = 0;
621
622 if (!ctx)
623 return gpg_error (GPG_ERR_INV_ARG);
624
625 err = gpgme_new (&c);
626 if (err)
627 return err;
628
629 gpgme_set_keylist_mode (c, GPGME_KEYLIST_MODE_SIGS);
630 err = gpgme_op_keylist_start (c, pattern, secret);
631 while(!err) {
632 err = gpgme_op_keylist_next (c, &key);
633 if (!err)
634 err = gpg_keycache_add_key (ctx, key, NULL);
635 if (ctx->cb)
636 ctx->cb (ctx->cb_value, _("Load GPG Keyrings..."), 0,
637 count++, ctx->cb_value2);
638 }
639 if (gpgme_err_code (err) == GPG_ERR_EOF)
640 err = gpg_error (GPG_ERR_NO_ERROR);
641 keycache_update_photos (ctx);
642 /* XXX: make sure the progress dialog is closed. */
643 gpgme_op_keylist_end (c);
644 gpgme_release (c);
645 return err;
646 }
647
648
649 /* XXX: kludge to see if the key is stored on a card. */
650 static int
651 key_divert_to_card (gpgme_key_t key)
652 {
653 gpgme_subkey_t k;
654 int n=0, n_alg=0, can_auth = 0;
655
656 for (k = key->subkeys; k; k = k->next) {
657 n++;
658 if (k->pubkey_algo == GPGME_PK_RSA && k->length == 1024)
659 n_alg++;
660 if (k->can_authenticate)
661 can_auth++;
662 }
663 if (n == 3 && n_alg == 3 && can_auth == 1)
664 return 1;
665 return 0;
666 }
667
668
669 static unsigned char*
670 copy_uid_prefs (const unsigned char *prefs)
671 {
672 unsigned char *p;
673 size_t pos=0;
674
675 while (prefs[pos] != 0)
676 pos++;
677 p = (unsigned char*)calloc (1, pos+1);
678 if (!p)
679 abort ();
680 memcpy (p, prefs, pos);
681 return p;
682 }
683
684
685 gpgme_error_t
686 gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)
687 {
688 struct keycache_s *c, *c_sec;
689 gpgme_key_t key;
690
691 if (!pub || !sec)
692 return gpg_error (GPG_ERR_INV_ARG);
693
694 for (c=sec->item; c; c=c->next) {
695 if (!gpg_keycache_find_key2 (pub, c->key->subkeys->keyid, 0, &key, &c_sec)) {
696 c_sec->gloflags.is_protected = c->gloflags.is_protected;
697 c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;
698 if (!c->gloflags.divert_to_card)
699 c->gloflags.divert_to_card = key_divert_to_card (key);
700 c->sym_prefs = copy_uid_prefs (c_sec->sym_prefs);
701 c->pubpart = c_sec;
702 c->pubpart->key = key;
703 }
704 }
705 return 0;
706 }
707
708
709 /* Rewind the given cache @ctx to the begin. */
710 void
711 gpg_keycache_rewind (gpg_keycache_t ctx)
712 {
713 if (ctx)
714 ctx->pos = 0;
715 }
716
717
718
719 /* Return the number of elements in the cache @ctx. */
720 int
721 gpg_keycache_get_size (gpg_keycache_t ctx)
722 {
723 struct keycache_s *c;
724 int count = 0;
725
726 if (!ctx)
727 return 0;
728 for (c = ctx->item; c; c = c->next)
729 count++;
730 return count;
731 }
732
733
734 static gpgme_error_t
735 keycache_next_key (gpg_keycache_t ctx, int flags,
736 struct keycache_s **c, gpgme_key_t *r_key)
737 {
738 if (!ctx || !r_key)
739 return gpg_error (GPG_ERR_INV_ARG);
740
741 if (!ctx->pos)
742 ctx->tmp = ctx->item;
743
744 if (!ctx->tmp || !ctx->tmp->key) {
745 ctx->pos = 0;
746 *r_key = NULL;
747 return gpg_error (GPG_ERR_EOF);
748 }
749
750 *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;
751 *c = ctx->tmp = ctx->tmp->next;
752 ctx->pos++;
753
754 return 0;
755 }
756
757
758 /* Return the next key from the cache @ctx. The key will be returned
759 in @r_key. @flags can contain additional flags.
760 Return value: 0 on success. */
761 gpgme_error_t
762 gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)
763 {
764 struct keycache_s *c=NULL;
765 gpgme_error_t err = 0;
766
767 err = keycache_next_key (ctx, flags, &c, r_key);
768 return err;
769 }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26