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

Diff of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 28 by twoaday, Thu Oct 20 12:35:59 2005 UTC revision 207 by twoaday, Fri Apr 28 10:28:24 2006 UTC
# Line 1  Line 1 
1  /* wptKeyCache.cpp- Caching for the pub- and the secring  /* wptKeyCache.cpp- Caching for the pub- and the secring
2   *      Copyright (C) 2001-2005 Timo Schulz   *      Copyright (C) 2001-2006 Timo Schulz
3   *   *
4   * This file is part of MyGPGME.   * This file is part of WinPT.
5   *   *
6   * MyGPGME is free software; you can redistribute it and/or modify   * WinPT is free software; you can redistribute it and/or modify
7   * it under the terms of the GNU General Public License as published by   * 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   * the Free Software Foundation; either version 2 of the License, or
9   * (at your option) any later version.   * (at your option) any later version.
10   *   *
11   * MyGPGME is distributed in the hope that it will be useful,   * WinPT is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.   * GNU General Public License for more details.
15   *   *
16   * You should have received a copy of the GNU General Public License   * You should have received a copy of the GNU General Public License
17   * along with this program; if not, write to the Free Software   * along with this program; if not, write to the Free Software
18   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19   */   */
20  #include <windows.h>  
21  #include <stdio.h>  #ifdef HAVE_CONFIG_H
22  #include <string.h>  #include <config.h>
23  #include <malloc.h>  #endif
24  #include <ctype.h>  
25  #include <assert.h>  #include <windows.h>
26    #include <stdio.h>
27  #include "w32gpgme.h"  #include <string.h>
28  #include "openpgp.h"  #include <malloc.h>
29  #include "wptNLS.h"  #include <ctype.h>
30  #include "wptErrors.h"  #include <assert.h>
31    #include <gpgme.h>
32    
33  /* convert a binary buffer into its hex representation. */  #include "wptKeyCache.h"
34  static void  #include "openpgp.h"
35  buffer_to_string (char *dst, size_t dlen, const byte *buf, size_t nbytes)  #include "wptNLS.h"
36  {  #include "wptErrors.h"
37      char dig[3];  #include "wptW32API.h"
38      size_t i;  #include "wptGPG.h"
39    #include "wptTypes.h"
40      memset (dst, 0, dlen);  #include "wptUTF8.h"
41      for (i = 0; i < nbytes && dlen > 0; i++) {  
42          sprintf (dig, "%02X", buf[i]);  
43          strcat (dst, dig);  /* Attribute list which holds the image data. */
44          dlen -= 2;  struct attr_list_s {
45      }      struct attr_list_s *next;
46  }      char *fpr;                   /* fingerprint of the key */
47        unsigned char *d;            /* actual JPEG data. */
48        unsigned long octets;        /* length of the data. */
49  /* Parse the secret keyring and retrieve some additional information      unsigned int flags;          /* status of the attribute. */
50     for each key which was found. */  };
51  static void  typedef struct attr_list_s *attr_list_t;
52  parse_secring (gpg_keycache_t cache, const char *kid, const char *secring)  
53  {      
54      PACKET *pkt = (PACKET*)calloc (1, sizeof *pkt);  /* Free attribute list @ctx. */
55      PKT_secret_key *sk;  void
56      gpg_iobuf_t inp;  free_attr_list (attr_list_t ctx)
57      gpgme_error_t err;  {
58      gpgme_key_t key;      attr_list_t n;
59      struct keycache_s *c=NULL;      while (ctx) {
60      char keyid[16+1];          n = ctx->next;
61            safe_free (ctx->fpr);
62      inp = gpg_iobuf_open (secring);          safe_free (ctx->d);
63      if (!inp) {          ctx = n;
64          safe_free (pkt);      }
65          return;  }
66      }          
67      gpg_iobuf_ioctl (inp, 3, 1, NULL);  /* Parse the attribute list in @fp and store it into @ctx.
68      gpg_init_packet (pkt);     Return value: number of parsed items. */
69      while (gpg_parse_packet (inp, pkt) != -1) {  int
70          if (pkt->pkttype == PKT_SECRET_KEY) {  parse_attr_list (FILE *fp, const BYTE *data, DWORD datlen, attr_list_t *ctx)
71              sk = pkt->pkt.secret_key;  {
72              /* XXX: key IDs of card public keys are wrong! */      attr_list_t c, t;
73              _snprintf (keyid, sizeof (keyid)-1, "%08lX",      char buf[512], *p, *buffer;
74                         gpg_keyid_from_sk (sk, NULL));      int pos, n=0;
75              if (kid && strcmp (kid, keyid) != 0)      
76                  goto next;      *ctx = NULL;
77              err = gpg_keycache_find_key2 (cache, keyid, 0, &key, &c);      while (fgets (buf, 511, fp)) {
78              if (err)          if (strstr (buf, "\r\n"))
79                  goto next;              buf[strlen (buf)-2]=0;
80              c->gloflags.is_protected = sk->is_protected;          if (strstr (buf, "\n"))
81              c->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;              buf[strlen (buf)-1]=0;
82              if (c->pubpart != NULL) {              if (strlen (buf) < 2 || !strstr (buf, "ATTRIBUTE"))
83                  c->pubpart->gloflags.is_protected = sk->is_protected;                  continue;
84                  c->pubpart->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;          buffer = buf+9+10;
85              }          pos = 0;
86          }          c = (attr_list_t)calloc (1, sizeof *c);
87  next:          if (!c)
88          gpg_free_packet (pkt);              BUG (0);
89          gpg_init_packet (pkt);          p = strtok (buffer, " ");
90      }          while (p != NULL) {
91      safe_free (pkt);              switch (pos) {
92      gpg_iobuf_close (inp);              case 0:
93  }                  c->fpr = strdup (p);
94                    break;
95                    
96  /* Merge the information from the keyrings into the key cache structure. */              case 1:
97  gpgme_error_t                  c->octets = strtoul (p, NULL, 10);
98  keycache_prepare2 (gpg_keycache_t ctx, const char *kid,                  break;
99                     const char *pubring, const char *secring)                  
100  {              case 7:
101      gpgme_error_t err;                  c->flags = strtoul (p, NULL, 10);
102      gpgme_key_t key = NULL;                  break;
103      gpg_iobuf_t inp;                  
104      PACKET *pkt = (PACKET*)calloc (1, sizeof * pkt);              default:
105      struct keycache_s *c;                  break;
106      const byte *sym_prefs;              }
107      char keyid[16+1], *id = NULL;              pos++;
108      int key_seen = 0;              p = strtok (NULL, " ");
109      size_t nbytes = 0, nsym =0;          }
110            if (!*ctx)
111      if (secring) {              *ctx = c;
112          parse_secring (ctx, kid, secring);          else {
113          if (!pubring) {              for (t = *ctx; t->next; t=t->next)
114              safe_free(pkt);                  ;
115              return 0;              t->next = c;
116          }          }
117      }          c->d = (unsigned char*)malloc (c->octets);
118      inp = gpg_iobuf_open (pubring);          if (!c->d)
119      if (!inp) {              BUG (0);
120          safe_free( pkt );          memcpy (c->d, data, c->octets);
121          return gpg_error (GPG_ERR_KEYRING_OPEN);          data += c->octets;
122      }          datlen -= c->octets;
123      gpg_iobuf_ioctl( inp, 3, 1, NULL ); /* disable cache */          n++;
124        }
125      gpg_init_packet( pkt );      /*assert (datlen == 0); */
126      while (gpg_parse_packet (inp, pkt) != -1) {      return n;
127          if (pkt->pkttype == PKT_PUBLIC_KEY) {  }
128              strcpy (keyid, "");  
129              key_seen = 1;  
130          }  static int
131    parse_attr_data (const char *keyid, attr_list_t *list)
132          if (pkt->pkttype == PKT_SIGNATURE && pkt->pkt.signature->sig_class == 0x1F) {  {
133              if (pkt->pkt.signature->numrevkeys == 0)      gpgme_error_t err;
134                  goto next;      FILE *tmp;    
135              _snprintf (keyid, sizeof keyid -1, "%08X", pkt->pkt.signature->keyid[1]);      BYTE *data;
136              if (kid && strcmp (kid, keyid) != 0)      char *status, tmpnam[MAX_PATH+1];
137                  goto next;      DWORD ndata = 0;
138              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);  
139              if (err)      err = gpg_get_photoid_data (keyid, &status, &data, &ndata);
140                  goto next;      if (err)
141              c->gloflags.has_desig_rev = 1;          return err;
142          }  
143          if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 ) {      get_temp_name (tmpnam, MAX_PATH, NULL);
144              sym_prefs=gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,      tmp = fopen (tmpnam, "w+b");
145                                              SIGSUBPKT_PREF_SYM, &nsym);      if (ndata > 0 && tmp != NULL) {
146              if (sym_prefs == NULL)          fwrite (status, 1, strlen (status), tmp);
147                  goto next;          fflush (tmp);
148              _snprintf (keyid, sizeof keyid - 1, "%08X", pkt->pkt.signature->keyid[1]);          rewind (tmp);
149              if (kid && strcmp (kid, keyid) != 0)  
150                  goto next;          ndata = parse_attr_list (tmp, data, ndata, list);
151              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);          fclose (tmp);
152              if (err)          DeleteFile (tmpnam);
153                  goto next;      }
154              else if (nsym > 0) {      else
155                  c->sym_prefs = (unsigned char*)calloc (1, nsym+1);          *list = NULL;
156                  if (!c->sym_prefs)  
157                      return gpg_error (GPG_ERR_ENOMEM);      safe_free (status);
158                  memcpy (c->sym_prefs, sym_prefs, nsym);      safe_free (data);
159              }      return ndata;
160          }  }
161          if (pkt->pkttype == PKT_USER_ID) {  
162              if (id)  
163                  free (id);  /* Parse the secret keyring and retrieve some additional information
164              id = strdup (pkt->pkt.user_id->name);     for each key which was found. */
165              if (!id) {  static void
166                  err = gpg_error (GPG_ERR_ENOMEM);  parse_secring (gpg_keycache_t cache, const char *kid, const char *secring)
167                  goto fail;  {    
168              }      PACKET *pkt;
169          }      PKT_secret_key *sk;
170          if ((pkt->pkttype == PKT_USER_ID || pkt->pkttype == PKT_ATTRIBUTE)      gpg_iobuf_t inp;
171              && pkt->pkt.user_id->attrib_data && key) {      gpgme_error_t err;
172              PKT_user_id *id = pkt->pkt.user_id;      gpgme_key_t key;
173              c->attrib.used = 1;      struct keycache_s *c=NULL;
174              c->attrib.len = id->attrib_len;      char keyid[16+1];
175              c->attrib.d = (unsigned char*)calloc (1, id->attrib_len + 1);  
176              if (!c->attrib.d) {      inp = gpg_iobuf_open (secring);
177                  err = gpg_error (GPG_ERR_ENOMEM);      if (!inp)
178                  goto fail;          return;
179              }  
180              memcpy (c->attrib.d, id->attrib_data, id->attrib_len);      gpg_iobuf_ioctl (inp, 3, 1, NULL);
181              key = NULL;      pkt = (PACKET*)calloc (1, sizeof *pkt);
182              c = NULL;      if (!pkt)
183          }          BUG (0);
184  next:      gpg_init_packet (pkt);
185          gpg_free_packet (pkt);      while (gpg_parse_packet (inp, pkt) != -1) {
186          gpg_init_packet(pkt);          if (pkt->pkttype == PKT_SECRET_KEY) {
187      }              sk = pkt->pkt.secret_key;
188                /* XXX: key IDs of card public keys are wrong! */
189  fail:              _snprintf (keyid, sizeof (keyid)-1, "%08lX",
190      safe_free (id);                         gpg_keyid_from_sk (sk, NULL));
191      safe_free (pkt);              if (kid && strcmp (kid, keyid) != 0)
192      gpg_iobuf_close (inp);                  goto next;
193      return err;              err = gpg_keycache_find_key2 (cache, keyid, 0, &key, &c);
194  }              if (err)
195                    goto next;
196                c->gloflags.is_protected = sk->is_protected;
197  gpgme_error_t              c->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
198  gpg_keycache_prepare (gpg_keycache_t ctx, const char *pubr, const char *secr)              if (c->pubpart != NULL) {    
199  {                  c->pubpart->gloflags.is_protected = sk->is_protected;    
200      return keycache_prepare2 (ctx, NULL, pubr, secr);                  c->pubpart->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
201  }              }
202            }
203  gpgme_error_t  next:
204  gpg_keycache_prepare_single (gpg_keycache_t ctx, const char *keyid,          gpg_free_packet (pkt);
205                                 const char *pubr, const char *secr)          gpg_init_packet (pkt);
206  {      }
207      if (!strncmp (keyid, "0x", 2))      safe_free (pkt);
208          keyid += 2;        gpg_iobuf_close (inp);
209      return keycache_prepare2 (ctx, keyid, pubr, secr);  }
210  }  
211    
212    /* Update the photo image of a single key with the fingerprint
213  /* Create new keycache object and return it in @r_ctx.     @fpr. The @dat struct contains the new item data. */
214     Return value: 0 on success. */  static gpgme_error_t
215  gpgme_error_t  keycache_update_photo (gpg_keycache_t ctx, const char *fpr, attr_list_t dat)
216  gpg_keycache_new (gpg_keycache_t *r_ctx)  {
217  {      struct keycache_s *fnd = NULL;
218      gpg_keycache_t ctx;      gpgme_key_t key;
219            
220      if (!r_ctx)      gpg_keycache_find_key2 (ctx, fpr, 0, &key, &fnd);
221          return gpg_error (GPG_ERR_INV_ARG);      if (!fnd)
222      ctx = (gpg_keycache_t)calloc (1, sizeof *ctx);          return gpg_error (GPG_ERR_NOT_FOUND);
223      if (!ctx)      safe_free (fnd->attrib.d);
224          return gpg_error (GPG_ERR_ENOMEM);      fnd->attrib.flags = dat->flags;
225      ctx->secret = 0;      fnd->attrib.len = dat->octets;
226      ctx->pos = 0;      fnd->attrib.d = (unsigned char*)malloc (dat->octets);
227      *r_ctx = ctx;      if (!fnd->attrib.d)
228      return 0;          BUG (0);
229  }      memcpy (fnd->attrib.d, dat->d, dat->octets);
230        return 0;
231    }
232  /* Release keycache object @ctx. */  
233  void  
234  gpg_keycache_release (gpg_keycache_t ctx)  /* Update all photo images in the cache. */
235  {  static gpgme_error_t
236      struct keycache_s *c, *c2;  keycache_update_photos (gpg_keycache_t ctx)
237        {
238      if (!ctx)      attr_list_t list=NULL, n;
239          return;      DWORD ndata;
240    
241      for (c = ctx->item; c; c = c2) {      ndata = parse_attr_data (NULL, &list);
242          c2 = c->next;      if (ndata < 1) {
243          gpgme_key_release (c->key);          free_attr_list (list);
244          c->key = NULL;          return 0;
245          if (c->sym_prefs)      }
246              free (c->sym_prefs);  
247          c->sym_prefs = NULL;      for (n=list; n; n=n->next)
248          if (c->attrib.d)          keycache_update_photo (ctx, n->fpr, n);
249              free (c->attrib.d);      free_attr_list (list);
250          c->attrib.d = NULL;      return 0;
251          if (c->card_type)  }
252              free (c->card_type);  
253          free (c);  
254      }  static void
255      if (ctx)  keycache_decode_uid (struct keycache_s *ctx)
256          free (ctx);  {
257  }      gpgme_user_id_t u;
258        struct native_uid_s *n, *t;
259    
260  /* Set (progress) callback for the given keycache object.      for (u = ctx->key->uids; u; u = u->next) {
261     @ctx the keycache          n = (struct native_uid_s*)calloc (1, sizeof *n);
262     @cb  the callback function          if (!n)
263     @cb_value1 opaque value which is passed to the callback.              BUG (0);
264     @cb_value2 see @cb_value1. */          if (is_8bit_string (u->uid)) {
265  void              n->malloced = 1;
266  gpg_keycache_set_cb (gpg_keycache_t ctx,              n->uid = utf8_to_native (u->uid);
267                       void (*cb)(void *, const char *, int, int, int),              if (u->name != NULL)
268                       void * cb_value1, int cb_value2)                  n->name = utf8_to_native (u->name);
269  {              if (u->email != NULL)
270      if (!ctx)                  n->email = strdup (u->email);
271          return;              if (u->comment != NULL)
272      ctx->cb = cb;                  n->comment = utf8_to_native (u->comment);
273      ctx->cb_value = cb_value1;          }
274      ctx->cb_value2 = cb_value2;          else {
275  }              n->malloced = 0;
276                n->uid = u->uid;
277                n->name = u->name;
278  /* Add @key to the cache @ctx. @opaque return the key cache context as a void*.              n->comment = u->comment;
279     Return value: 0 on success. */              n->email = u->email;
280  gpgme_error_t          }
281  gpg_keycache_add_key (gpg_keycache_t ctx, gpgme_key_t key, void **opaque)          n->validity = u->validity;
282  {          n->revoked = u->revoked;
283      struct keycache_s * c, * n1;          if (!ctx->uids)
284                    ctx->uids = n;
285      if (!ctx)          else {
286          return gpg_error (GPG_ERR_INV_ARG);              for (t = ctx->uids; t->next; t=t->next)
287                        ;
288      c = (struct keycache_s*)calloc (1, sizeof *c);              t->next = n;          
289      if (!c)          }
290          return gpg_error (GPG_ERR_ENOMEM);      }
291      c->gloflags.is_protected = 1; /*default: assume protection. */  }
292      c->key = key;  
293      if (!ctx->item)  
294          ctx->item = c;  /* Store utf8 decoded user IDs in the code to avoid in-place decoding. */
295      else {  static void
296          for (n1 = ctx->item; n1 && n1->next; n1 = n1->next)  keycache_decode_uids (gpg_keycache_t ctx)
297              ;  {
298          n1->next = c;      struct keycache_s *c;
299      }  
300      if (opaque)      for (c = ctx->item; c; c = c->next)
301          *opaque = c;          keycache_decode_uid (c);
302      return 0;  }
303  }  
304    
305    static void
306    free_native_uids (struct native_uid_s **r_n)
307  #define has_keyid_len(pattern) (\  {
308      strlen (pattern) == 8  || strlen (pattern) == 10 || \      struct native_uid_s *t;
309      strlen (pattern) == 16 || strlen (pattern) == 18)      struct native_uid_s *n = *r_n;
310    
311        while (n != NULL) {
312  gpgme_error_t          t = n->next;
313  gpg_keycache_find_key2 (gpg_keycache_t ctx, const char *pattern, int flags,          if (n->malloced) {
314                          gpgme_key_t *r_key, struct keycache_s **r_item)              safe_free (n->uid);
315  {              safe_free (n->name);
316      struct keycache_s *c;              safe_free (n->comment);
317      gpgme_subkey_t s;              safe_free (n->email);
318      gpgme_user_id_t u;              safe_free (n->uid);
319      gpgme_key_t key;          }
320      const char *kid;          safe_free (n);
321                n = t;
322      if (!ctx || !r_key)      }
323          return gpg_error (GPG_ERR_INV_ARG);      *r_n = NULL;
324        }
325      if (strstr (pattern, "0x"))  
326          pattern += 2;  
327    
328      /* Sometimes a subkey has no valid fpr. As a kludge we convert v4  /* Merge the information from the keyrings into the key cache structure. */
329         fingerprints into the 64-bit keyid. */  gpgme_error_t
330      if (strlen (pattern) == 40 && isxdigit (*pattern))  keycache_prepare2 (gpg_keycache_t ctx, const char *kid,
331          pattern += 32;                     const char *pubring, const char *secring)
332    {
333      /* XXX: this code is very slow, revamp it and use hash tables whenever      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
334              it is possible. */      gpgme_key_t key = NULL;
335      for (c = ctx->item; c; c = c->next) {      gpg_iobuf_t inp;
336          key = c->key;      PACKET *pkt;
337          assert (key->_refs >= 1);      struct keycache_s *c;
338          for (s = key->subkeys; s; s = s->next) {      const byte *sym_prefs;
339              for (u = key->uids; u; u = u->next) {      char keyid[16+1];
340                  if (u->name && stristr (u->name, pattern)) {      int key_seen = 0;
341                      if (r_item)      size_t nsym =0;
342                          *r_item = c;  
343                      *r_key = flags? c->pubpart->key : c->key;      if (secring) {
344                      return 0;          parse_secring (ctx, kid, secring);
345                  }          if (!pubring)
346              }              return 0;
347              if (has_keyid_len (pattern))      }
348                  kid = s->keyid;      inp = gpg_iobuf_open (pubring);
349              else      if (!inp)
350                  kid = s->fpr;          return gpg_error (GPG_ERR_KEYRING_OPEN);
351              if (kid && stristr (kid, pattern)) {      gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */
352                  if (r_item)  
353                      *r_item = c;      pkt = (PACKET*)calloc (1, sizeof * pkt);
354                  *r_key = flags? c->pubpart->key : c->key;      if (!pkt)
355                  return 0;          BUG (0);
356              }      gpg_init_packet (pkt);
357          }      while (gpg_parse_packet (inp, pkt) != -1) {
358      }          if (pkt->pkttype == PKT_PUBLIC_KEY) {
359      *r_key = NULL;              strcpy (keyid, "");
360      return gpg_error (GPG_ERR_INTERNAL);              key_seen = 1;
361  } /* keycache_find_key */          }
362    
363            if (pkt->pkttype == PKT_SIGNATURE &&
364  gpgme_error_t              pkt->pkt.signature->sig_class == 0x1F) {
365  gpg_keycache_find_key (gpg_keycache_t ctx, const char *pattern,              if (pkt->pkt.signature->numrevkeys == 0)
366                         int flags, gpgme_key_t *r_key)                  goto next;
367  {              _snprintf (keyid, sizeof (keyid) -1, "%08X",
368      return gpg_keycache_find_key2 (ctx, pattern, flags, r_key, NULL);                          pkt->pkt.signature->keyid[1]);
369  }              if (kid && strcmp (kid, keyid) != 0)
370                    goto next;
371                err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
372  gpgme_error_t              if (err)
373  gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,                  goto next;
374                           void *opaque, const char *keyid)              c->gloflags.has_desig_rev = 1;
375  {          }
376      struct keycache_s *c = NULL, *c_new=NULL;          if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 ) {
377      gpgme_key_t key=NULL, fndkey=NULL;              sym_prefs = gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,
378      gpgme_error_t err;                                                SIGSUBPKT_PREF_SYM, &nsym);
379      gpgme_ctx_t gctx;              if (!sym_prefs)
380      gpg_keycache_t pub = (gpg_keycache_t)opaque;                  goto next;
381                _snprintf (keyid, sizeof (keyid) - 1, "%08X",
382      err = gpgme_new (&gctx);                          pkt->pkt.signature->keyid[1]);
383      if (err)              if (kid && strcmp (kid, keyid) != 0)
384          return err;                  goto next;
385      err = gpgme_get_key (gctx, keyid, &key, is_sec);              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
386      gpgme_release (gctx);              if (err)
387      if (err)                  goto next;
388          return err;              else if (nsym > 0) {
389      err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);                  c->sym_prefs = (unsigned char*)calloc (1, nsym+1);
390      if (!err && c != NULL) {                  if (!c->sym_prefs)
391          log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);                      BUG (0);
392          gpgme_key_release (fndkey);                  memcpy (c->sym_prefs, sym_prefs, nsym);
393          c->key = key;              }
394          c->flags = 0;          }
395          if (is_sec && pub != NULL &&  next:
396              !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {          gpg_free_packet (pkt);
397              log_debug ("keycache update: set public part %p\r\n", fndkey);          gpg_init_packet(pkt);
398              c->pubpart->key = fndkey;      }
399          }  
400      }      safe_free (pkt);
401      else {      gpg_iobuf_close (inp);
402          log_debug ("keycache add: sync public part\r\n");      return err;
403          if (is_sec)  }
404              gpg_keycache_find_key2 (pub, keyid, 0, &fndkey, &c_new);  
405          gpg_keycache_add_key (ctx, key, (void **)&c);  
406          if (c != NULL && is_sec) {  gpgme_error_t
407              log_debug ("keycache add: keyid=%s %p %p\r\n", keyid, c, fndkey);  gpg_keycache_prepare (gpg_keycache_t ctx, const char *pubr, const char *secr)
408              c->pubpart = c_new;  {
409              if (c_new != NULL) {      return keycache_prepare2 (ctx, NULL, pubr, secr);
410                  c->pubpart->key = fndkey;  }
411                  c->gloflags.is_protected = c_new->gloflags.is_protected;  
412                  c->gloflags.divert_to_card = c_new->gloflags.divert_to_card;  gpgme_error_t
413              }  gpg_keycache_prepare_single (gpg_keycache_t ctx, const char *keyid,
414          }                                 const char *pubr, const char *secr)
415      }  {
416      return 0;      if (!strncmp (keyid, "0x", 2))
417  }          keyid += 2;  
418        return keycache_prepare2 (ctx, keyid, pubr, secr);
419    }
420  /* Delete a key from the cache @ctx with the pattern @pattern.  
421     Return value: 0 on success. */  
422  gpgme_error_t  /* Create new keycache object and return it in @r_ctx.
423  gpg_keycache_delete_key (gpg_keycache_t ctx, const char *pattern)     Return value: 0 on success. */
424  {  gpgme_error_t
425      struct keycache_s *itm = NULL, *c;  gpg_keycache_new (gpg_keycache_t *r_ctx)
426      gpgme_key_t key;  {
427      gpgme_error_t rc;      gpg_keycache_t ctx;
428        
429      if (!ctx)      if (!r_ctx)
430          return gpg_error (GPG_ERR_INV_ARG);          return gpg_error (GPG_ERR_INV_ARG);
431      rc = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);      ctx = (gpg_keycache_t)calloc (1, sizeof *ctx);
432      if (rc)      if (!ctx)
433          return rc;          BUG (0);
434            ctx->secret = 0;
435      c = ctx->item;      ctx->pos = 0;
436      if (c->next == NULL) {      *r_ctx = ctx;
437          gpgme_key_release (itm->key);      return 0;
438          if (itm)  }
439              free (itm);  
440          ctx->item = NULL;  
441      }  /* Release keycache object @ctx. */
442      else {  void
443          while (c && c->next != itm)  gpg_keycache_release (gpg_keycache_t ctx)
444              c = c->next;  {
445          c->next = c->next->next;      struct keycache_s *c, *c2;
446          gpgme_key_release (itm->key);      
447          if (itm)      if (!ctx)
448              free (itm);          return;
449      }  
450      return 0;      for (c = ctx->item; c; c = c2) {
451  }          c2 = c->next;
452            gpgme_key_release (c->key);
453            c->key = NULL;
454  /* Initialize the given cache @ctx. If @pattern is NULL, the entire keyring          safe_free (c->pref_keyserver);
455     will be added to the cache. @secret is 1 if the source is the secret keyring.          safe_free (c->sym_prefs);
456     Return value: 0 on success. */          safe_free (c->attrib.d);
457  gpgme_error_t          safe_free (c->card_type);
458  gpg_keycache_init (gpg_keycache_t ctx, const char *pattern, int secret)          free_native_uids (&c->uids);
459  {          safe_free (c);
460      gpgme_error_t err;      }
461      gpgme_ctx_t c;      safe_free (ctx);
462      gpgme_key_t key;  }
463      int count = 0;  
464        
465      if (!ctx)  /* Set (progress) callback for the given keycache object.
466          return gpg_error (GPG_ERR_INV_ARG);     @ctx the keycache
467           @cb  the callback function
468      err = gpgme_new (&c);     @cb_value1 opaque value which is passed to the callback.
469      if (err)     @cb_value2 see @cb_value1. */
470          return err;  void
471    gpg_keycache_set_cb (gpg_keycache_t ctx,
472      gpgme_set_keylist_mode  (c, GPGME_KEYLIST_MODE_SIGS);                       void (*cb)(void *, const char *, int, int, int),
473      err = gpgme_op_keylist_start (c, pattern, secret);                       void * cb_value1, int cb_value2)
474      while(!err) {  {
475          err = gpgme_op_keylist_next (c, &key);      if (!ctx)
476          if (!err)          return;
477              err = gpg_keycache_add_key (ctx, key, NULL);      ctx->cb = cb;
478          if (ctx->cb)      ctx->cb_value = cb_value1;
479              ctx->cb (ctx->cb_value, _("Load GPG Keyrings..."), 0,      ctx->cb_value2 = cb_value2;
480                       count++, ctx->cb_value2);  }
481      }  
482      if (gpgme_err_code (err) == GPG_ERR_EOF)  
483          err = gpg_error (GPG_ERR_NO_ERROR);  /* Add @key to the cache @ctx. @opaque return the key cache context as a void*.
484      /* XXX: make sure the progress dialog is closed. */     Return value: 0 on success. */
485      gpgme_op_keylist_end (c);  gpgme_error_t
486      gpgme_release (c);  gpg_keycache_add_key (gpg_keycache_t ctx, gpgme_key_t key, void **opaque)
487      return err;  {
488  }      struct keycache_s *c, *n1;
489        
490        if (!ctx)
491  /* XXX: kludge to see if the key is stored on a card. */          return gpg_error (GPG_ERR_INV_ARG);
492  static int      
493  key_divert_to_card (gpgme_key_t key)      c = (struct keycache_s*)calloc (1, sizeof *c);
494  {      if (!c)
495      gpgme_subkey_t k;          BUG (0);
496      int n=0, n_alg=0, can_auth = 0;      c->gloflags.is_protected = 1; /*default: assume protection. */
497        c->key = key;
498      for (k = key->subkeys; k; k = k->next) {      if (!ctx->item)
499          n++;          ctx->item = c;
500          if (k->pubkey_algo == GPGME_PK_RSA && k->length == 1024)      else {
501              n_alg++;          for (n1 = ctx->item; n1 && n1->next; n1 = n1->next)
502          if (k->can_authenticate)              ;
503              can_auth++;          n1->next = c;
504      }      }
505      if (n == 3 && n_alg == 3 && can_auth == 1)      if (opaque)
506          return 1;          *opaque = c;
507      return 0;      return 0;
508  }  }
509    
510    
511  gpgme_error_t  
512  gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)  #define has_keyid_len(pattern) (\
513  {      strlen (pattern) == 8  || strlen (pattern) == 10 || \
514      struct keycache_s *c, *c_sec;      strlen (pattern) == 16 || strlen (pattern) == 18)
515      gpgme_key_t key;  
516    
517      if (!pub || !sec)  gpgme_error_t
518          return gpg_error (GPG_ERR_INV_ARG);  gpg_keycache_find_key2 (gpg_keycache_t ctx, const char *pattern, int flags,
519                                gpgme_key_t *r_key, struct keycache_s **r_item)
520      for (c=sec->item; c; c=c->next) {    {
521          if (!gpg_keycache_find_key2 (pub, c->key->subkeys->keyid, 0, &key, &c_sec)) {      struct keycache_s *c;
522              c_sec->gloflags.is_protected = c->gloflags.is_protected;      gpgme_subkey_t s;
523              c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;      gpgme_user_id_t u;
524              if (!c->gloflags.divert_to_card)      gpgme_key_t key;
525                  c->gloflags.divert_to_card = key_divert_to_card (key);      const char *kid;
526              c->pubpart = c_sec;      
527              c->pubpart->key = key;      if (!ctx || !r_key)
528          }          return gpg_error (GPG_ERR_INV_ARG);
529      }      
530      return 0;      if (strstr (pattern, "0x"))
531  }          pattern += 2;
532    
533        /* Sometimes a subkey has no valid fpr. As a kludge we convert v4
534  /* Rewind the given cache @ctx to the begin. */         fingerprints into the 64-bit keyid. */
535  void      if (strlen (pattern) == 40 && isxdigit (*pattern))
536  gpg_keycache_rewind (gpg_keycache_t ctx)          pattern += 32;
537  {  
538      if (ctx)      /* XXX: this code is very slow, revamp it and use hash tables whenever
539          ctx->pos = 0;              it is possible. */
540  }      for (c = ctx->item; c; c = c->next) {
541            key = c->key;
542            assert (key->_refs >= 1);
543            for (s = key->subkeys; s; s = s->next) {
544  /* Return the number of elements in the cache @ctx. */              for (u = key->uids; u; u = u->next) {
545  int                  if (u->name && stristr (u->name, pattern)) {
546  gpg_keycache_get_size (gpg_keycache_t ctx)                      if (r_item)
547  {                          *r_item = c;
548      struct keycache_s *c;                      *r_key = flags? c->pubpart->key : c->key;
549      int count = 0;                      return 0;
550                        }
551      if (!ctx)              }
552          return 0;              if (has_keyid_len (pattern))
553      for (c = ctx->item; c; c = c->next)                  kid = s->keyid;
554          count++;              else
555      return count;                  kid = s->fpr;
556  }              if (kid && stristr (kid, pattern)) {
557                    if (r_item)
558                        *r_item = c;
559  static gpgme_error_t                  *r_key = flags? c->pubpart->key : c->key;
560  keycache_next_key (gpg_keycache_t ctx, int flags,                  return 0;
561                     struct keycache_s **c, gpgme_key_t *r_key)              }
562  {                }
563      if (!ctx || !r_key)      }
564          return gpg_error (GPG_ERR_INV_ARG);      *r_key = NULL;
565        return gpg_error (GPG_ERR_INTERNAL);
566      if (!ctx->pos)  }
567          ctx->tmp = ctx->item;  
568        
569      if (!ctx->tmp || !ctx->tmp->key) {  gpgme_error_t
570          ctx->pos = 0;  gpg_keycache_find_key (gpg_keycache_t ctx, const char *pattern,
571          *r_key = NULL;                         int flags, gpgme_key_t *r_key)
572          return gpg_error (GPG_ERR_EOF);  {
573      }      return gpg_keycache_find_key2 (ctx, pattern, flags, r_key, NULL);
574        }
575      *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;  
576      *c = ctx->tmp = ctx->tmp->next;  
577      ctx->pos++;  /* Reload a photo image of a single key with the keyid @keyid.
578       Return value: 0 on success. */
579      return 0;  static gpgme_error_t
580  }  keycache_reload_photo (gpg_keycache_t ctx, const char *keyid)
581    {
582        attr_list_t list;
583  /* Return the next key from the cache @ctx. The key will be returned  
584     in @r_key. @flags can contain additional flags.      if (parse_attr_data (keyid, &list) < 1) {
585     Return value: 0 on success. */          free_attr_list (list);
586  gpgme_error_t          return 0;
587  gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)      }
588  {      keycache_update_photo (ctx, list->fpr, list);
589      struct keycache_s *c=NULL;      free_attr_list (list);
590      gpgme_error_t err = 0;      return 0;
591    }
592      err = keycache_next_key (ctx, flags, &c, r_key);  
593      return err;  
594  }  /* Return the next key which was updated. Before it is
595       returned the update flag is cleared.
596       @r_status is 1 for a new key and 2 for an updated key.
597       Return value: 0 on success. */
598    gpgme_error_t
599    gpg_keycache_next_updated_key (gpg_keycache_t ctx,
600                                   struct keycache_s **r_obj,
601                                   int *r_status)
602    {
603        struct keycache_s *c;
604    
605        for (c = ctx->item; c; c = c->next) {
606            if (c->flags != 0) {
607                *r_status = c->flags;
608                *r_obj = c;
609                c->flags = 0;
610                return 0;
611            }
612        }
613        return gpg_error (GPG_ERR_NOT_FOUND);
614    }
615    
616    
617    
618    gpgme_error_t
619    gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,
620                             void *opaque, const char *keyid)
621    {
622        struct keycache_s *c = NULL, *c_new=NULL;
623        gpgme_key_t key=NULL, fndkey=NULL;
624        gpgme_error_t err;
625        gpgme_ctx_t gctx;
626        gpg_keycache_t pub = (gpg_keycache_t)opaque;
627    
628        err = gpgme_new (&gctx);
629        if (err)
630            return err;
631        gpgme_set_keylist_mode  (gctx, GPGME_KEYLIST_MODE_SIGS);
632        err = gpgme_get_key (gctx, keyid, &key, is_sec);
633        gpgme_release (gctx);
634        if (err)
635            return err;
636        err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);
637        if (!err && c != NULL) {
638            log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);
639            gpgme_key_release (fndkey);
640            c->key = key;
641            c->flags = KC_FLAG_UPD;
642            if (is_sec && pub != NULL &&
643                !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {
644                log_debug ("keycache update: set public part %p\r\n", fndkey);
645                c->pubpart->key = fndkey;
646            }
647            /* XXX: this is also called for keys without a photo-id. */
648            keycache_reload_photo (ctx, keyid);
649    
650            /* refresh utf8 user ID list. */
651            free_native_uids (&c->uids);
652            keycache_decode_uid (c);
653        }
654        else {
655            log_debug ("keycache add: sync public part\r\n");
656            if (is_sec)
657                gpg_keycache_find_key2 (pub, keyid, 0, &fndkey, &c_new);
658            gpg_keycache_add_key (ctx, key, (void **)&c);
659            if (c != NULL && is_sec) {
660                log_debug ("keycache add: keyid=%s %p %p\r\n", keyid, c, fndkey);
661                c->pubpart = c_new;
662                if (c_new != NULL) {
663                    c->pubpart->key = fndkey;
664                    c->gloflags.is_protected = c_new->gloflags.is_protected;
665                    c->gloflags.divert_to_card = c_new->gloflags.divert_to_card;
666                }
667            }
668            if (c)
669                c->flags = KC_FLAG_ADD;
670        }
671        return 0;
672    }
673    
674    
675    /* Delete a key from the cache @ctx with the pattern @pattern.
676       Return value: 0 on success. */
677    gpgme_error_t
678    gpg_keycache_delete_key (gpg_keycache_t ctx, const char *pattern)
679    {
680        struct keycache_s *itm = NULL, *c;
681        gpgme_key_t key;
682        gpgme_error_t rc;
683    
684        if (!ctx)
685            return gpg_error (GPG_ERR_INV_ARG);
686        rc = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
687        if (rc)
688            return rc;
689        
690        c = ctx->item;
691        if (c->next == NULL) {
692            gpgme_key_release (itm->key);
693            safe_free (itm);
694            ctx->item = NULL;
695        }
696        else {
697            for (; c != NULL; c = c->next) {
698                if (c->next == itm)
699                    break;
700            }
701            assert (c != NULL); /* XXX: sometimes access violation. */
702            c->next = c->next->next;
703            gpgme_key_release (itm->key);
704            safe_free (itm);
705        }
706        return 0;
707    }
708    
709    
710    /* Initialize the given cache @ctx. If @pattern is NULL, the entire keyring
711       will be added to the cache. @secret is 1 if the source is the secret keyring.
712       Return value: 0 on success. */
713    gpgme_error_t
714    gpg_keycache_init (gpg_keycache_t ctx, const char *pattern, int secret)
715    {
716        gpgme_error_t err;
717        gpgme_ctx_t c;
718        gpgme_key_t key;
719        int count = 0;
720        
721        if (!ctx)
722            return gpg_error (GPG_ERR_INV_ARG);
723        
724        err = gpgme_new (&c);
725        if (err)
726            return err;
727    
728        gpgme_set_keylist_mode  (c, GPGME_KEYLIST_MODE_SIGS);
729        err = gpgme_op_keylist_start (c, pattern, secret);
730        while(!err) {
731            err = gpgme_op_keylist_next (c, &key);
732            if (!err)
733                err = gpg_keycache_add_key (ctx, key, NULL);
734            if (ctx->cb)
735                ctx->cb (ctx->cb_value, _("Load GPG Keyrings..."), 0,
736                         count++, ctx->cb_value2);
737        }
738        if (gpgme_err_code (err) == GPG_ERR_EOF)
739            err = gpg_error (GPG_ERR_NO_ERROR);
740        keycache_update_photos (ctx);
741        keycache_decode_uids (ctx);
742        /* XXX: make sure the progress dialog is closed. */
743        gpgme_op_keylist_end (c);
744        gpgme_release (c);
745        return err;
746    }
747    
748    
749    /* XXX: kludge to see if the key is stored on a card. */
750    static int
751    key_divert_to_card (gpgme_key_t key)
752    {
753        gpgme_subkey_t k;
754        int n=0, n_alg=0, can_auth = 0;
755    
756        for (k = key->subkeys; k; k = k->next) {
757            n++;
758            if (k->pubkey_algo == GPGME_PK_RSA && k->length == 1024)
759                n_alg++;
760            if (k->can_authenticate)
761                can_auth++;
762        }
763        if (n == 3 && n_alg == 3 && can_auth == 1)
764            return 1;
765        return 0;
766    }
767    
768    
769    static unsigned char*
770    copy_uid_prefs (const unsigned char *prefs)
771    {
772        unsigned char *p;
773        size_t pos=0;
774    
775        while (prefs[pos] != 0)
776            pos++;
777        p = (unsigned char*)calloc (1, pos+1);
778        if (!p)
779            BUG (0);
780        memcpy (p, prefs, pos);
781        return p;
782    }
783    
784    
785    gpgme_error_t
786    gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)
787    {
788        struct keycache_s *c, *c_sec;
789        gpgme_key_t key;
790    
791        if (!pub || !sec)
792            return gpg_error (GPG_ERR_INV_ARG);
793        
794        for (c=sec->item; c; c=c->next) {  
795            if (!gpg_keycache_find_key2 (pub, c->key->subkeys->keyid, 0, &key, &c_sec)) {
796                c_sec->gloflags.is_protected = c->gloflags.is_protected;
797                c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;
798                if (!c->gloflags.divert_to_card)
799                    c->gloflags.divert_to_card = key_divert_to_card (key);
800                if (c_sec->sym_prefs)
801                    c->sym_prefs = copy_uid_prefs (c_sec->sym_prefs);
802                c->pubpart = c_sec;
803                c->pubpart->key = key;
804            }
805        }
806        return 0;
807    }
808    
809    
810    /* Rewind the given cache @ctx to the begin. */
811    void
812    gpg_keycache_rewind (gpg_keycache_t ctx)
813    {
814        if (ctx)
815            ctx->pos = 0;
816    }
817    
818    
819    
820    /* Return the number of elements in the cache @ctx. */
821    int
822    gpg_keycache_get_size (gpg_keycache_t ctx)
823    {
824        struct keycache_s *c;
825        int count = 0;
826        
827        if (!ctx)
828            return 0;
829        for (c = ctx->item; c; c = c->next)
830            count++;
831        return count;
832    }
833    
834    
835    static gpgme_error_t
836    keycache_next_key (gpg_keycache_t ctx, int flags,
837                       struct keycache_s **c, gpgme_key_t *r_key)
838    {      
839        if (!ctx || !r_key)
840            return gpg_error (GPG_ERR_INV_ARG);
841    
842        if (!ctx->pos)
843            ctx->tmp = ctx->item;
844        
845        if (!ctx->tmp || !ctx->tmp->key) {
846            ctx->pos = 0;
847            *r_key = NULL;
848            return gpg_error (GPG_ERR_EOF);
849        }
850        if (ctx->tmp->flags != 0)
851            ctx->tmp->flags = 0; /* reset the 'updated' status. */
852        /* it might be possible there is no public key. */
853        if (flags && ctx->tmp->pubpart == NULL)
854            flags = 0;
855        *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;
856        *c = ctx->tmp;
857        ctx->tmp = ctx->tmp->next;    
858        ctx->pos++;
859    
860        return 0;
861    }
862    
863    
864    /* Return the next key from the cache @ctx. The key will be returned
865       in @r_key. @flags can contain additional flags.
866       Return value: 0 on success. */
867    gpgme_error_t
868    gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)
869    {
870        struct keycache_s *c=NULL;
871        gpgme_error_t err;
872    
873        err = keycache_next_key (ctx, flags, &c, r_key);
874        return err;
875    }
876    
877    gpgme_error_t
878    gpg_keycache_next_key2 (gpg_keycache_t ctx, int flags,
879                            struct keycache_s **c, gpgme_key_t *r_key)
880    {
881        return keycache_next_key (ctx, flags, c, r_key);
882    }
883    
884    
885    /* Search for a key with the pattern @pattern and mark
886       this key as the default signing key if found.
887       Return value: 0 on success. */
888    gpgme_error_t
889    gpg_keycache_set_default_key (gpg_keycache_t ctx,
890                                  const char *pattern)
891    {
892        gpgme_error_t err;
893        gpgme_key_t key;
894        struct keycache_s *itm;
895    
896        err = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
897        if (err)
898            return err;
899    
900        if (itm)
901            itm->default_key = 1;
902        return 0;
903    }
904    
905    /* Return the default key from the cache. If no was
906       marked before, NULL is returned in @r_key.
907       Return value: 0 on success. */
908    gpgme_error_t
909    gpg_keycache_get_default_key (gpg_keycache_t ctx,
910                                  gpgme_key_t *r_key)
911    {
912        struct keycache_s *itm;
913    
914        *r_key = NULL;
915        for (itm = ctx->item; itm; itm = itm->next) {
916            if (itm->default_key) {
917                *r_key = itm->key;
918                break;
919            }
920        }
921        if (!*r_key)
922            return gpgme_error (GPG_ERR_NOT_FOUND);
923        return 0;
924    }
925    
926    
927    static gpgme_error_t
928    decode_subpacket (const char *subpkt_data, int *type,
929                      char **out, WORD *outlen)
930    {
931        char tmp[128], *p = tmp, *val;
932        char *enc = NULL;
933        size_t pos = 0, i=0;
934    
935        /* example: spk:24:1:21:http%3A//subkeys.pgp.de */
936        *outlen = 0;
937        *out = NULL;
938        
939        if (strncmp (subpkt_data, "spk:", 4))
940            return gpg_error (GPG_ERR_NO_DATA);
941    
942        strncpy (tmp, subpkt_data, 62);
943        val = strtok (tmp, ":");
944        while (val != NULL) {
945            switch (pos++) {
946            case 0:
947                break;
948    
949            case 1:
950                if (type)
951                    *type = atoi (val);
952                break;
953    
954            case 2:
955                break;
956    
957            case 3:
958                *outlen = atoi (val);
959                break;
960    
961            case 4:
962                enc = strdup (val);
963                break;
964            }
965            val = strtok (NULL, ":");
966        }
967        if (!enc)
968            return gpg_error (GPG_ERR_NO_DATA);;
969        *out = (char*)calloc (1, strlen (enc)+1);
970        if (!*out)
971            BUG (0);
972        for (pos = 0; pos < strlen (enc); pos++) {
973            if (enc[pos] == '%' && enc[pos+1] == '%')
974                (*out)[i++] = '%';
975            else if (enc[pos] == '%') {
976                char temp[3];
977                temp[0] = enc[++pos];
978                temp[1] = enc[++pos];
979                temp[2] = 0;
980                (*out)[i++] = (char)strtoul (temp, NULL, 16);
981            }
982            else
983                (*out)[i++] = enc[pos];
984        }
985        (*out)[i] = 0;
986        safe_free (enc);
987        return 0;
988    }
989    
990    
991    /* If the attribute given in @attr is not set in the
992       key cache object, try to update it. */
993    gpgme_error_t
994    gpg_keycache_update_attr (struct keycache_s *item,
995                              int attr, int force)
996    {
997        gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
998        char *val = NULL;
999        WORD n = 0;    
1000    
1001        switch (attr) {
1002        case KC_ATTR_PREFSYM:
1003            if (!force && item->sym_prefs)
1004                break;
1005            safe_free (item->sym_prefs);
1006            err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
1007            if (!err && val != NULL)
1008                err = decode_subpacket (val, NULL, (char**)&item->sym_prefs, &n);
1009            break;
1010    
1011        case KC_ATTR_PREFKSERV:
1012            if (!force && item->pref_keyserver)
1013                break;
1014            safe_free (item->pref_keyserver);
1015            err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
1016            if (!err && val != NULL)
1017                err = decode_subpacket (val, NULL, &item->pref_keyserver, &n);
1018            break;
1019        }
1020        safe_free (val);
1021        return err;
1022    }

Legend:
Removed from v.28  
changed lines
  Added in v.207

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26