/[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 205 by twoaday, Thu Apr 27 12:46:03 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      }  /* Store utf8 decoded user IDs in the code to avoid in-place decoding. */
255      if (ctx)  static gpgme_error_t
256          free (ctx);  keycache_decode_uids (gpg_keycache_t ctx)
257  }  {
258        struct native_uid_s *n, *t;
259        struct keycache_s *c;
260  /* Set (progress) callback for the given keycache object.      gpgme_user_id_t u;
261     @ctx the keycache  
262     @cb  the callback function      for (c = ctx->item; c; c = c->next) {
263     @cb_value1 opaque value which is passed to the callback.          for (u = c->key->uids; u; u = u->next) {
264     @cb_value2 see @cb_value1. */              n = (struct native_uid_s*)calloc (1, sizeof *n);
265  void              if (!n)
266  gpg_keycache_set_cb (gpg_keycache_t ctx,                  BUG (0);
267                       void (*cb)(void *, const char *, int, int, int),              if (is_8bit_string (u->uid)) {
268                       void * cb_value1, int cb_value2)                  n->malloced = 1;
269  {                  n->uid = utf8_to_native (u->uid);
270      if (!ctx)                  if (u->name != NULL)
271          return;                      n->name = utf8_to_native (u->name);
272      ctx->cb = cb;                  if (u->email != NULL)
273      ctx->cb_value = cb_value1;                      n->email = strdup (u->email);
274      ctx->cb_value2 = cb_value2;                  if (u->comment != NULL)
275  }                      n->comment = utf8_to_native (u->comment);
276                }
277                else {
278  /* Add @key to the cache @ctx. @opaque return the key cache context as a void*.                  n->malloced = 0;
279     Return value: 0 on success. */                  n->uid = u->uid;
280  gpgme_error_t                  n->name = u->name;
281  gpg_keycache_add_key (gpg_keycache_t ctx, gpgme_key_t key, void **opaque)                  n->comment = u->comment;
282  {                  n->email = u->email;
283      struct keycache_s * c, * n1;              }
284                    if (!c->uids)
285      if (!ctx)                  c->uids = n;
286          return gpg_error (GPG_ERR_INV_ARG);              else {
287                        for (t = c->uids; t->next; t=t->next)
288      c = (struct keycache_s*)calloc (1, sizeof *c);                      ;
289      if (!c)                  t->next = n;
290          return gpg_error (GPG_ERR_ENOMEM);              }
291      c->gloflags.is_protected = 1; /*default: assume protection. */          }
292      c->key = key;      }  
293      if (!ctx->item)      return 0;
294          ctx->item = c;  }
295      else {  
296          for (n1 = ctx->item; n1 && n1->next; n1 = n1->next)  
297              ;  static void
298          n1->next = c;  free_native_uids (struct native_uid_s *n)
299      }  {
300      if (opaque)      struct native_uid_s *t;
301          *opaque = c;  
302      return 0;      while (n != NULL) {
303  }          t = n->next;
304            if (n->malloced) {
305                safe_free (n->uid);
306                safe_free (n->name);
307  #define has_keyid_len(pattern) (\              safe_free (n->comment);
308      strlen (pattern) == 8  || strlen (pattern) == 10 || \              safe_free (n->email);
309      strlen (pattern) == 16 || strlen (pattern) == 18)              safe_free (n->uid);
310            }
311            safe_free (n);
312  gpgme_error_t          n = t;
313  gpg_keycache_find_key2 (gpg_keycache_t ctx, const char *pattern, int flags,      }
314                          gpgme_key_t *r_key, struct keycache_s **r_item)  }
315  {  
316      struct keycache_s *c;  
317      gpgme_subkey_t s;  
318      gpgme_user_id_t u;  /* Merge the information from the keyrings into the key cache structure. */
319      gpgme_key_t key;  gpgme_error_t
320      const char *kid;  keycache_prepare2 (gpg_keycache_t ctx, const char *kid,
321                           const char *pubring, const char *secring)
322      if (!ctx || !r_key)  {
323          return gpg_error (GPG_ERR_INV_ARG);      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
324            gpgme_key_t key = NULL;
325      if (strstr (pattern, "0x"))      gpg_iobuf_t inp;
326          pattern += 2;      PACKET *pkt;
327        struct keycache_s *c;
328      /* Sometimes a subkey has no valid fpr. As a kludge we convert v4      const byte *sym_prefs;
329         fingerprints into the 64-bit keyid. */      char keyid[16+1];
330      if (strlen (pattern) == 40 && isxdigit (*pattern))      int key_seen = 0;
331          pattern += 32;      size_t nsym =0;
332    
333      /* XXX: this code is very slow, revamp it and use hash tables whenever      if (secring) {
334              it is possible. */          parse_secring (ctx, kid, secring);
335      for (c = ctx->item; c; c = c->next) {          if (!pubring)
336          key = c->key;              return 0;
337          assert (key->_refs >= 1);      }
338          for (s = key->subkeys; s; s = s->next) {      inp = gpg_iobuf_open (pubring);
339              for (u = key->uids; u; u = u->next) {      if (!inp)
340                  if (u->name && stristr (u->name, pattern)) {          return gpg_error (GPG_ERR_KEYRING_OPEN);
341                      if (r_item)      gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */
342                          *r_item = c;  
343                      *r_key = flags? c->pubpart->key : c->key;      pkt = (PACKET*)calloc (1, sizeof * pkt);
344                      return 0;      if (!pkt)
345                  }          BUG (0);
346              }      gpg_init_packet (pkt);
347              if (has_keyid_len (pattern))      while (gpg_parse_packet (inp, pkt) != -1) {
348                  kid = s->keyid;          if (pkt->pkttype == PKT_PUBLIC_KEY) {
349              else              strcpy (keyid, "");
350                  kid = s->fpr;              key_seen = 1;
351              if (kid && stristr (kid, pattern)) {          }
352                  if (r_item)  
353                      *r_item = c;          if (pkt->pkttype == PKT_SIGNATURE &&
354                  *r_key = flags? c->pubpart->key : c->key;              pkt->pkt.signature->sig_class == 0x1F) {
355                  return 0;              if (pkt->pkt.signature->numrevkeys == 0)
356              }                  goto next;
357          }              _snprintf (keyid, sizeof (keyid) -1, "%08X",
358      }                          pkt->pkt.signature->keyid[1]);
359      *r_key = NULL;              if (kid && strcmp (kid, keyid) != 0)
360      return gpg_error (GPG_ERR_INTERNAL);                  goto next;
361  } /* keycache_find_key */              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
362                if (err)
363                    goto next;
364  gpgme_error_t              c->gloflags.has_desig_rev = 1;
365  gpg_keycache_find_key (gpg_keycache_t ctx, const char *pattern,          }
366                         int flags, gpgme_key_t *r_key)          if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 ) {
367  {              sym_prefs = gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,
368      return gpg_keycache_find_key2 (ctx, pattern, flags, r_key, NULL);                                                SIGSUBPKT_PREF_SYM, &nsym);
369  }              if (!sym_prefs)
370                    goto next;
371                _snprintf (keyid, sizeof (keyid) - 1, "%08X",
372  gpgme_error_t                          pkt->pkt.signature->keyid[1]);
373  gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,              if (kid && strcmp (kid, keyid) != 0)
374                           void *opaque, const char *keyid)                  goto next;
375  {              err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
376      struct keycache_s *c = NULL, *c_new=NULL;              if (err)
377      gpgme_key_t key=NULL, fndkey=NULL;                  goto next;
378      gpgme_error_t err;              else if (nsym > 0) {
379      gpgme_ctx_t gctx;                  c->sym_prefs = (unsigned char*)calloc (1, nsym+1);
380      gpg_keycache_t pub = (gpg_keycache_t)opaque;                  if (!c->sym_prefs)
381                        BUG (0);
382      err = gpgme_new (&gctx);                  memcpy (c->sym_prefs, sym_prefs, nsym);
383      if (err)              }
384          return err;          }
385      err = gpgme_get_key (gctx, keyid, &key, is_sec);  next:
386      gpgme_release (gctx);          gpg_free_packet (pkt);
387      if (err)          gpg_init_packet(pkt);
388          return err;      }
389      err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);  
390      if (!err && c != NULL) {      safe_free (pkt);
391          log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);      gpg_iobuf_close (inp);
392          gpgme_key_release (fndkey);      return err;
393          c->key = key;  }
394          c->flags = 0;  
395          if (is_sec && pub != NULL &&  
396              !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {  gpgme_error_t
397              log_debug ("keycache update: set public part %p\r\n", fndkey);  gpg_keycache_prepare (gpg_keycache_t ctx, const char *pubr, const char *secr)
398              c->pubpart->key = fndkey;  {
399          }      return keycache_prepare2 (ctx, NULL, pubr, secr);
400      }  }
401      else {  
402          log_debug ("keycache add: sync public part\r\n");  gpgme_error_t
403          if (is_sec)  gpg_keycache_prepare_single (gpg_keycache_t ctx, const char *keyid,
404              gpg_keycache_find_key2 (pub, keyid, 0, &fndkey, &c_new);                                 const char *pubr, const char *secr)
405          gpg_keycache_add_key (ctx, key, (void **)&c);  {
406          if (c != NULL && is_sec) {      if (!strncmp (keyid, "0x", 2))
407              log_debug ("keycache add: keyid=%s %p %p\r\n", keyid, c, fndkey);          keyid += 2;  
408              c->pubpart = c_new;      return keycache_prepare2 (ctx, keyid, pubr, secr);
409              if (c_new != NULL) {  }
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;  /* Create new keycache object and return it in @r_ctx.
413              }     Return value: 0 on success. */
414          }  gpgme_error_t
415      }  gpg_keycache_new (gpg_keycache_t *r_ctx)
416      return 0;  {
417  }      gpg_keycache_t ctx;
418        
419        if (!r_ctx)
420  /* Delete a key from the cache @ctx with the pattern @pattern.          return gpg_error (GPG_ERR_INV_ARG);
421     Return value: 0 on success. */      ctx = (gpg_keycache_t)calloc (1, sizeof *ctx);
422  gpgme_error_t      if (!ctx)
423  gpg_keycache_delete_key (gpg_keycache_t ctx, const char *pattern)          BUG (0);
424  {      ctx->secret = 0;
425      struct keycache_s *itm = NULL, *c;      ctx->pos = 0;
426      gpgme_key_t key;      *r_ctx = ctx;
427      gpgme_error_t rc;      return 0;
428    }
429      if (!ctx)  
430          return gpg_error (GPG_ERR_INV_ARG);  
431      rc = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);  /* Release keycache object @ctx. */
432      if (rc)  void
433          return rc;  gpg_keycache_release (gpg_keycache_t ctx)
434        {
435      c = ctx->item;      struct keycache_s *c, *c2;
436      if (c->next == NULL) {      
437          gpgme_key_release (itm->key);      if (!ctx)
438          if (itm)          return;
439              free (itm);  
440          ctx->item = NULL;      for (c = ctx->item; c; c = c2) {
441      }          c2 = c->next;
442      else {          gpgme_key_release (c->key);
443          while (c && c->next != itm)          c->key = NULL;
444              c = c->next;          safe_free (c->pref_keyserver);
445          c->next = c->next->next;          safe_free (c->sym_prefs);
446          gpgme_key_release (itm->key);          safe_free (c->attrib.d);
447          if (itm)          safe_free (c->card_type);
448              free (itm);          free_native_uids (c->uids);
449      }          safe_free (c);
450      return 0;      }
451  }      safe_free (ctx);
452    }
453    
454  /* Initialize the given cache @ctx. If @pattern is NULL, the entire keyring  
455     will be added to the cache. @secret is 1 if the source is the secret keyring.  /* Set (progress) callback for the given keycache object.
456     Return value: 0 on success. */     @ctx the keycache
457  gpgme_error_t     @cb  the callback function
458  gpg_keycache_init (gpg_keycache_t ctx, const char *pattern, int secret)     @cb_value1 opaque value which is passed to the callback.
459  {     @cb_value2 see @cb_value1. */
460      gpgme_error_t err;  void
461      gpgme_ctx_t c;  gpg_keycache_set_cb (gpg_keycache_t ctx,
462      gpgme_key_t key;                       void (*cb)(void *, const char *, int, int, int),
463      int count = 0;                       void * cb_value1, int cb_value2)
464        {
465      if (!ctx)      if (!ctx)
466          return gpg_error (GPG_ERR_INV_ARG);          return;
467            ctx->cb = cb;
468      err = gpgme_new (&c);      ctx->cb_value = cb_value1;
469      if (err)      ctx->cb_value2 = cb_value2;
470          return err;  }
471    
472      gpgme_set_keylist_mode  (c, GPGME_KEYLIST_MODE_SIGS);  
473      err = gpgme_op_keylist_start (c, pattern, secret);  /* Add @key to the cache @ctx. @opaque return the key cache context as a void*.
474      while(!err) {     Return value: 0 on success. */
475          err = gpgme_op_keylist_next (c, &key);  gpgme_error_t
476          if (!err)  gpg_keycache_add_key (gpg_keycache_t ctx, gpgme_key_t key, void **opaque)
477              err = gpg_keycache_add_key (ctx, key, NULL);  {
478          if (ctx->cb)      struct keycache_s *c, *n1;
479              ctx->cb (ctx->cb_value, _("Load GPG Keyrings..."), 0,      
480                       count++, ctx->cb_value2);      if (!ctx)
481      }          return gpg_error (GPG_ERR_INV_ARG);
482      if (gpgme_err_code (err) == GPG_ERR_EOF)      
483          err = gpg_error (GPG_ERR_NO_ERROR);      c = (struct keycache_s*)calloc (1, sizeof *c);
484      /* XXX: make sure the progress dialog is closed. */      if (!c)
485      gpgme_op_keylist_end (c);          BUG (0);
486      gpgme_release (c);      c->gloflags.is_protected = 1; /*default: assume protection. */
487      return err;      c->key = key;
488  }      if (!ctx->item)
489            ctx->item = c;
490        else {
491  /* XXX: kludge to see if the key is stored on a card. */          for (n1 = ctx->item; n1 && n1->next; n1 = n1->next)
492  static int              ;
493  key_divert_to_card (gpgme_key_t key)          n1->next = c;
494  {      }
495      gpgme_subkey_t k;      if (opaque)
496      int n=0, n_alg=0, can_auth = 0;          *opaque = c;
497        return 0;
498      for (k = key->subkeys; k; k = k->next) {  }
499          n++;  
500          if (k->pubkey_algo == GPGME_PK_RSA && k->length == 1024)  
501              n_alg++;  
502          if (k->can_authenticate)  #define has_keyid_len(pattern) (\
503              can_auth++;      strlen (pattern) == 8  || strlen (pattern) == 10 || \
504      }      strlen (pattern) == 16 || strlen (pattern) == 18)
505      if (n == 3 && n_alg == 3 && can_auth == 1)  
506          return 1;  
507      return 0;  gpgme_error_t
508  }  gpg_keycache_find_key2 (gpg_keycache_t ctx, const char *pattern, int flags,
509                            gpgme_key_t *r_key, struct keycache_s **r_item)
510    {
511  gpgme_error_t      struct keycache_s *c;
512  gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)      gpgme_subkey_t s;
513  {      gpgme_user_id_t u;
514      struct keycache_s *c, *c_sec;      gpgme_key_t key;
515      gpgme_key_t key;      const char *kid;
516        
517      if (!pub || !sec)      if (!ctx || !r_key)
518          return gpg_error (GPG_ERR_INV_ARG);          return gpg_error (GPG_ERR_INV_ARG);
519            
520      for (c=sec->item; c; c=c->next) {        if (strstr (pattern, "0x"))
521          if (!gpg_keycache_find_key2 (pub, c->key->subkeys->keyid, 0, &key, &c_sec)) {          pattern += 2;
522              c_sec->gloflags.is_protected = c->gloflags.is_protected;  
523              c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;      /* Sometimes a subkey has no valid fpr. As a kludge we convert v4
524              if (!c->gloflags.divert_to_card)         fingerprints into the 64-bit keyid. */
525                  c->gloflags.divert_to_card = key_divert_to_card (key);      if (strlen (pattern) == 40 && isxdigit (*pattern))
526              c->pubpart = c_sec;          pattern += 32;
527              c->pubpart->key = key;  
528          }      /* XXX: this code is very slow, revamp it and use hash tables whenever
529      }              it is possible. */
530      return 0;      for (c = ctx->item; c; c = c->next) {
531  }          key = c->key;
532            assert (key->_refs >= 1);
533            for (s = key->subkeys; s; s = s->next) {
534  /* Rewind the given cache @ctx to the begin. */              for (u = key->uids; u; u = u->next) {
535  void                  if (u->name && stristr (u->name, pattern)) {
536  gpg_keycache_rewind (gpg_keycache_t ctx)                      if (r_item)
537  {                          *r_item = c;
538      if (ctx)                      *r_key = flags? c->pubpart->key : c->key;
539          ctx->pos = 0;                      return 0;
540  }                  }
541                }
542                if (has_keyid_len (pattern))
543                    kid = s->keyid;
544  /* Return the number of elements in the cache @ctx. */              else
545  int                  kid = s->fpr;
546  gpg_keycache_get_size (gpg_keycache_t ctx)              if (kid && stristr (kid, pattern)) {
547  {                  if (r_item)
548      struct keycache_s *c;                      *r_item = c;
549      int count = 0;                  *r_key = flags? c->pubpart->key : c->key;
550                        return 0;
551      if (!ctx)              }
552          return 0;          }
553      for (c = ctx->item; c; c = c->next)      }
554          count++;      *r_key = NULL;
555      return count;      return gpg_error (GPG_ERR_INTERNAL);
556  }  }
557    
558    
559  static gpgme_error_t  gpgme_error_t
560  keycache_next_key (gpg_keycache_t ctx, int flags,  gpg_keycache_find_key (gpg_keycache_t ctx, const char *pattern,
561                     struct keycache_s **c, gpgme_key_t *r_key)                         int flags, gpgme_key_t *r_key)
562  {        {
563      if (!ctx || !r_key)      return gpg_keycache_find_key2 (ctx, pattern, flags, r_key, NULL);
564          return gpg_error (GPG_ERR_INV_ARG);  }
565    
566      if (!ctx->pos)  
567          ctx->tmp = ctx->item;  /* Reload a photo image of a single key with the keyid @keyid.
568           Return value: 0 on success. */
569      if (!ctx->tmp || !ctx->tmp->key) {  static gpgme_error_t
570          ctx->pos = 0;  keycache_reload_photo (gpg_keycache_t ctx, const char *keyid)
571          *r_key = NULL;  {
572          return gpg_error (GPG_ERR_EOF);      attr_list_t list;
573      }  
574            if (parse_attr_data (keyid, &list) < 1) {
575      *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;          free_attr_list (list);
576      *c = ctx->tmp = ctx->tmp->next;          return 0;
577      ctx->pos++;      }
578        keycache_update_photo (ctx, list->fpr, list);
579      return 0;      free_attr_list (list);
580  }      return 0;
581    }
582    
583  /* Return the next key from the cache @ctx. The key will be returned  
584     in @r_key. @flags can contain additional flags.  /* Return the next key which was updated. Before it is
585     Return value: 0 on success. */     returned the update flag is cleared.
586  gpgme_error_t     @r_status is 1 for a new key and 2 for an updated key.
587  gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)     Return value: 0 on success. */
588  {  gpgme_error_t
589      struct keycache_s *c=NULL;  gpg_keycache_next_updated_key (gpg_keycache_t ctx,
590      gpgme_error_t err = 0;                                 struct keycache_s **r_obj,
591                                   int *r_status)
592      err = keycache_next_key (ctx, flags, &c, r_key);  {
593      return err;      struct keycache_s *c;
594  }  
595        for (c = ctx->item; c; c = c->next) {
596            if (c->flags != 0) {
597                *r_status = c->flags;
598                *r_obj = c;
599                c->flags = 0;
600                return 0;
601            }
602        }
603        return gpg_error (GPG_ERR_NOT_FOUND);
604    }
605    
606    
607    
608    gpgme_error_t
609    gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,
610                             void *opaque, const char *keyid)
611    {
612        struct keycache_s *c = NULL, *c_new=NULL;
613        gpgme_key_t key=NULL, fndkey=NULL;
614        gpgme_error_t err;
615        gpgme_ctx_t gctx;
616        gpg_keycache_t pub = (gpg_keycache_t)opaque;
617    
618        err = gpgme_new (&gctx);
619        if (err)
620            return err;
621        gpgme_set_keylist_mode  (gctx, GPGME_KEYLIST_MODE_SIGS);
622        err = gpgme_get_key (gctx, keyid, &key, is_sec);
623        gpgme_release (gctx);
624        if (err)
625            return err;
626        err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);
627        if (!err && c != NULL) {
628            log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);
629            gpgme_key_release (fndkey);
630            c->key = key;
631            c->flags = KC_FLAG_UPD;
632            if (is_sec && pub != NULL &&
633                !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {
634                log_debug ("keycache update: set public part %p\r\n", fndkey);
635                c->pubpart->key = fndkey;
636            }
637            /* XXX: this is also called for keys without a photo-id. */
638            keycache_reload_photo (ctx, keyid);
639        }
640        else {
641            log_debug ("keycache add: sync public part\r\n");
642            if (is_sec)
643                gpg_keycache_find_key2 (pub, keyid, 0, &fndkey, &c_new);
644            gpg_keycache_add_key (ctx, key, (void **)&c);
645            if (c != NULL && is_sec) {
646                log_debug ("keycache add: keyid=%s %p %p\r\n", keyid, c, fndkey);
647                c->pubpart = c_new;
648                if (c_new != NULL) {
649                    c->pubpart->key = fndkey;
650                    c->gloflags.is_protected = c_new->gloflags.is_protected;
651                    c->gloflags.divert_to_card = c_new->gloflags.divert_to_card;
652                }
653            }
654            if (c)
655                c->flags = KC_FLAG_ADD;
656        }
657        return 0;
658    }
659    
660    
661    /* Delete a key from the cache @ctx with the pattern @pattern.
662       Return value: 0 on success. */
663    gpgme_error_t
664    gpg_keycache_delete_key (gpg_keycache_t ctx, const char *pattern)
665    {
666        struct keycache_s *itm = NULL, *c;
667        gpgme_key_t key;
668        gpgme_error_t rc;
669    
670        if (!ctx)
671            return gpg_error (GPG_ERR_INV_ARG);
672        rc = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
673        if (rc)
674            return rc;
675        
676        c = ctx->item;
677        if (c->next == NULL) {
678            gpgme_key_release (itm->key);
679            safe_free (itm);
680            ctx->item = NULL;
681        }
682        else {
683            for (; c != NULL; c = c->next) {
684                if (c->next == itm)
685                    break;
686            }
687            assert (c != NULL); /* XXX: sometimes access violation. */
688            c->next = c->next->next;
689            gpgme_key_release (itm->key);
690            safe_free (itm);
691        }
692        return 0;
693    }
694    
695    
696    /* Initialize the given cache @ctx. If @pattern is NULL, the entire keyring
697       will be added to the cache. @secret is 1 if the source is the secret keyring.
698       Return value: 0 on success. */
699    gpgme_error_t
700    gpg_keycache_init (gpg_keycache_t ctx, const char *pattern, int secret)
701    {
702        gpgme_error_t err;
703        gpgme_ctx_t c;
704        gpgme_key_t key;
705        int count = 0;
706        
707        if (!ctx)
708            return gpg_error (GPG_ERR_INV_ARG);
709        
710        err = gpgme_new (&c);
711        if (err)
712            return err;
713    
714        gpgme_set_keylist_mode  (c, GPGME_KEYLIST_MODE_SIGS);
715        err = gpgme_op_keylist_start (c, pattern, secret);
716        while(!err) {
717            err = gpgme_op_keylist_next (c, &key);
718            if (!err)
719                err = gpg_keycache_add_key (ctx, key, NULL);
720            if (ctx->cb)
721                ctx->cb (ctx->cb_value, _("Load GPG Keyrings..."), 0,
722                         count++, ctx->cb_value2);
723        }
724        if (gpgme_err_code (err) == GPG_ERR_EOF)
725            err = gpg_error (GPG_ERR_NO_ERROR);
726        keycache_update_photos (ctx);
727        keycache_decode_uids (ctx);
728        /* XXX: make sure the progress dialog is closed. */
729        gpgme_op_keylist_end (c);
730        gpgme_release (c);
731        return err;
732    }
733    
734    
735    /* XXX: kludge to see if the key is stored on a card. */
736    static int
737    key_divert_to_card (gpgme_key_t key)
738    {
739        gpgme_subkey_t k;
740        int n=0, n_alg=0, can_auth = 0;
741    
742        for (k = key->subkeys; k; k = k->next) {
743            n++;
744            if (k->pubkey_algo == GPGME_PK_RSA && k->length == 1024)
745                n_alg++;
746            if (k->can_authenticate)
747                can_auth++;
748        }
749        if (n == 3 && n_alg == 3 && can_auth == 1)
750            return 1;
751        return 0;
752    }
753    
754    
755    static unsigned char*
756    copy_uid_prefs (const unsigned char *prefs)
757    {
758        unsigned char *p;
759        size_t pos=0;
760    
761        while (prefs[pos] != 0)
762            pos++;
763        p = (unsigned char*)calloc (1, pos+1);
764        if (!p)
765            BUG (0);
766        memcpy (p, prefs, pos);
767        return p;
768    }
769    
770    
771    gpgme_error_t
772    gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)
773    {
774        struct keycache_s *c, *c_sec;
775        gpgme_key_t key;
776    
777        if (!pub || !sec)
778            return gpg_error (GPG_ERR_INV_ARG);
779        
780        for (c=sec->item; c; c=c->next) {  
781            if (!gpg_keycache_find_key2 (pub, c->key->subkeys->keyid, 0, &key, &c_sec)) {
782                c_sec->gloflags.is_protected = c->gloflags.is_protected;
783                c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;
784                if (!c->gloflags.divert_to_card)
785                    c->gloflags.divert_to_card = key_divert_to_card (key);
786                if (c_sec->sym_prefs)
787                    c->sym_prefs = copy_uid_prefs (c_sec->sym_prefs);
788                c->pubpart = c_sec;
789                c->pubpart->key = key;
790            }
791        }
792        return 0;
793    }
794    
795    
796    /* Rewind the given cache @ctx to the begin. */
797    void
798    gpg_keycache_rewind (gpg_keycache_t ctx)
799    {
800        if (ctx)
801            ctx->pos = 0;
802    }
803    
804    
805    
806    /* Return the number of elements in the cache @ctx. */
807    int
808    gpg_keycache_get_size (gpg_keycache_t ctx)
809    {
810        struct keycache_s *c;
811        int count = 0;
812        
813        if (!ctx)
814            return 0;
815        for (c = ctx->item; c; c = c->next)
816            count++;
817        return count;
818    }
819    
820    
821    static gpgme_error_t
822    keycache_next_key (gpg_keycache_t ctx, int flags,
823                       struct keycache_s **c, gpgme_key_t *r_key)
824    {      
825        if (!ctx || !r_key)
826            return gpg_error (GPG_ERR_INV_ARG);
827    
828        if (!ctx->pos)
829            ctx->tmp = ctx->item;
830        
831        if (!ctx->tmp || !ctx->tmp->key) {
832            ctx->pos = 0;
833            *r_key = NULL;
834            return gpg_error (GPG_ERR_EOF);
835        }
836        if (ctx->tmp->flags != 0)
837            ctx->tmp->flags = 0; /* reset the 'updated' status. */
838        /* it might be possible there is no public key. */
839        if (flags && ctx->tmp->pubpart == NULL)
840            flags = 0;
841        *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;
842        *c = ctx->tmp;
843        ctx->tmp = ctx->tmp->next;    
844        ctx->pos++;
845    
846        return 0;
847    }
848    
849    
850    /* Return the next key from the cache @ctx. The key will be returned
851       in @r_key. @flags can contain additional flags.
852       Return value: 0 on success. */
853    gpgme_error_t
854    gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)
855    {
856        struct keycache_s *c=NULL;
857        gpgme_error_t err;
858    
859        err = keycache_next_key (ctx, flags, &c, r_key);
860        return err;
861    }
862    
863    gpgme_error_t
864    gpg_keycache_next_key2 (gpg_keycache_t ctx, int flags,
865                            struct keycache_s **c, gpgme_key_t *r_key)
866    {
867        return keycache_next_key (ctx, flags, c, r_key);
868    }
869    
870    
871    /* Search for a key with the pattern @pattern and mark
872       this key as the default signing key if found.
873       Return value: 0 on success. */
874    gpgme_error_t
875    gpg_keycache_set_default_key (gpg_keycache_t ctx,
876                                  const char *pattern)
877    {
878        gpgme_error_t err;
879        gpgme_key_t key;
880        struct keycache_s *itm;
881    
882        err = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
883        if (err)
884            return err;
885    
886        if (itm)
887            itm->default_key = 1;
888        return 0;
889    }
890    
891    /* Return the default key from the cache. If no was
892       marked before, NULL is returned in @r_key.
893       Return value: 0 on success. */
894    gpgme_error_t
895    gpg_keycache_get_default_key (gpg_keycache_t ctx,
896                                  gpgme_key_t *r_key)
897    {
898        struct keycache_s *itm;
899    
900        *r_key = NULL;
901        for (itm = ctx->item; itm; itm = itm->next) {
902            if (itm->default_key) {
903                *r_key = itm->key;
904                break;
905            }
906        }
907        if (!*r_key)
908            return gpgme_error (GPG_ERR_NOT_FOUND);
909        return 0;
910    }
911    
912    
913    static gpgme_error_t
914    decode_subpacket (const char *subpkt_data, int *type,
915                      char **out, WORD *outlen)
916    {
917        char tmp[128], *p = tmp, *val;
918        char *enc = NULL;
919        size_t pos = 0, i=0;
920    
921        /* example: spk:24:1:21:http%3A//subkeys.pgp.de */
922        *outlen = 0;
923        *out = NULL;
924        
925        if (strncmp (subpkt_data, "spk:", 4))
926            return gpg_error (GPG_ERR_NO_DATA);
927    
928        strncpy (tmp, subpkt_data, 62);
929        val = strtok (tmp, ":");
930        while (val != NULL) {
931            switch (pos++) {
932            case 0:
933                break;
934    
935            case 1:
936                if (type)
937                    *type = atoi (val);
938                break;
939    
940            case 2:
941                break;
942    
943            case 3:
944                *outlen = atoi (val);
945                break;
946    
947            case 4:
948                enc = strdup (val);
949                break;
950            }
951            val = strtok (NULL, ":");
952        }
953        if (!enc)
954            return gpg_error (GPG_ERR_NO_DATA);;
955        *out = (char*)calloc (1, strlen (enc)+1);
956        if (!*out)
957            BUG (0);
958        for (pos = 0; pos < strlen (enc); pos++) {
959            if (enc[pos] == '%' && enc[pos+1] == '%')
960                (*out)[i++] = '%';
961            else if (enc[pos] == '%') {
962                char temp[3];
963                temp[0] = enc[++pos];
964                temp[1] = enc[++pos];
965                temp[2] = 0;
966                (*out)[i++] = (char)strtoul (temp, NULL, 16);
967            }
968            else
969                (*out)[i++] = enc[pos];
970        }
971        (*out)[i] = 0;
972        safe_free (enc);
973        return 0;
974    }
975    
976    
977    /* If the attribute given in @attr is not set in the
978       key cache object, try to update it. */
979    gpgme_error_t
980    gpg_keycache_update_attr (struct keycache_s *item,
981                              int attr, int force)
982    {
983        gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
984        char *val = NULL;
985        WORD n = 0;    
986    
987        switch (attr) {
988        case KC_ATTR_PREFSYM:
989            if (!force && item->sym_prefs)
990                break;
991            safe_free (item->sym_prefs);
992            err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
993            if (!err && val != NULL)
994                err = decode_subpacket (val, NULL, (char**)&item->sym_prefs, &n);
995            break;
996    
997        case KC_ATTR_PREFKSERV:
998            if (!force && item->pref_keyserver)
999                break;
1000            safe_free (item->pref_keyserver);
1001            err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
1002            if (!err && val != NULL)
1003                err = decode_subpacket (val, NULL, &item->pref_keyserver, &n);
1004            break;
1005        }
1006        safe_free (val);
1007        return err;
1008    }

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26