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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26