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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26