/[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 147 by twoaday, Fri Jan 13 14:21:16 2006 UTC revision 205 by twoaday, Thu Apr 27 12:46:03 2006 UTC
# Line 1  Line 1 
1  /* wptKeyCache.cpp- Caching for the pub- and the secring  /* wptKeyCache.cpp- Caching for the pub- and the secring
2   *      Copyright (C) 2001-2006 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.
# Line 36  Line 36 
36  #include "wptErrors.h"  #include "wptErrors.h"
37  #include "wptW32API.h"  #include "wptW32API.h"
38  #include "wptGPG.h"  #include "wptGPG.h"
39    #include "wptTypes.h"
40    #include "wptUTF8.h"
41    
42    
43  /* Attribute list which holds the image data. */  /* Attribute list which holds the image data. */
# Line 49  struct attr_list_s { Line 51  struct attr_list_s {
51  typedef struct attr_list_s *attr_list_t;  typedef struct attr_list_s *attr_list_t;
52    
53    
54    /* Free attribute list @ctx. */
55  void  void
56  free_attr_list (attr_list_t ctx)  free_attr_list (attr_list_t ctx)
57  {  {
58      attr_list_t n;      attr_list_t n;
59      while (ctx) {      while (ctx) {
60          n = ctx->next;          n = ctx->next;
61          free (ctx->fpr);          safe_free (ctx->fpr);
62          free (ctx->d);          safe_free (ctx->d);
63          ctx = n;          ctx = n;
64      }      }
65  }  }
# Line 81  parse_attr_list (FILE *fp, const BYTE *d Line 84  parse_attr_list (FILE *fp, const BYTE *d
84          buffer = buf+9+10;          buffer = buf+9+10;
85          pos = 0;          pos = 0;
86          c = (attr_list_t)calloc (1, sizeof *c);          c = (attr_list_t)calloc (1, sizeof *c);
87            if (!c)
88                BUG (0);
89          p = strtok (buffer, " ");          p = strtok (buffer, " ");
90          while (p != NULL) {          while (p != NULL) {
91              switch (pos) {              switch (pos) {
# Line 102  parse_attr_list (FILE *fp, const BYTE *d Line 107  parse_attr_list (FILE *fp, const BYTE *d
107              pos++;              pos++;
108              p = strtok (NULL, " ");              p = strtok (NULL, " ");
109          }          }
         /*printf ("id=%s octets=%d flags=%d\n", c->fpr, c->octets, c->flags);*/  
110          if (!*ctx)          if (!*ctx)
111              *ctx = c;              *ctx = c;
112          else {          else {
# Line 111  parse_attr_list (FILE *fp, const BYTE *d Line 115  parse_attr_list (FILE *fp, const BYTE *d
115              t->next = c;              t->next = c;
116          }          }
117          c->d = (unsigned char*)malloc (c->octets);          c->d = (unsigned char*)malloc (c->octets);
118            if (!c->d)
119                BUG (0);
120          memcpy (c->d, data, c->octets);          memcpy (c->d, data, c->octets);
121          data += c->octets;          data += c->octets;
122          datlen -= c->octets;          datlen -= c->octets;
# Line 125  static int Line 131  static int
131  parse_attr_data (const char *keyid, attr_list_t *list)  parse_attr_data (const char *keyid, attr_list_t *list)
132  {  {
133      gpgme_error_t err;      gpgme_error_t err;
134      FILE *tmp;      FILE *tmp;    
     char *status;  
135      BYTE *data;      BYTE *data;
136      DWORD ndata;      char *status, tmpnam[MAX_PATH+1];
137        DWORD ndata = 0;
138    
139      err = gpg_get_photoid_data (keyid, &status, &data, &ndata);      err = gpg_get_photoid_data (keyid, &status, &data, &ndata);
140      if (err)      if (err)
141          return err;          return err;
142    
143      if (ndata > 0) {      get_temp_name (tmpnam, MAX_PATH, NULL);
144          tmp = tmpfile ();      tmp = fopen (tmpnam, "w+b");
145        if (ndata > 0 && tmp != NULL) {
146          fwrite (status, 1, strlen (status), tmp);          fwrite (status, 1, strlen (status), tmp);
147          fflush (tmp);          fflush (tmp);
148          rewind (tmp);          rewind (tmp);
149    
150          ndata = parse_attr_list (tmp, data, ndata, list);          ndata = parse_attr_list (tmp, data, ndata, list);
151          fclose (tmp);          fclose (tmp);
152            DeleteFile (tmpnam);
153      }      }
154      else      else
155          *list = NULL;          *list = NULL;
# Line 171  parse_secring (gpg_keycache_t cache, con Line 179  parse_secring (gpg_keycache_t cache, con
179    
180      gpg_iobuf_ioctl (inp, 3, 1, NULL);      gpg_iobuf_ioctl (inp, 3, 1, NULL);
181      pkt = (PACKET*)calloc (1, sizeof *pkt);      pkt = (PACKET*)calloc (1, sizeof *pkt);
182        if (!pkt)
183            BUG (0);
184      gpg_init_packet (pkt);      gpg_init_packet (pkt);
185      while (gpg_parse_packet (inp, pkt) != -1) {      while (gpg_parse_packet (inp, pkt) != -1) {
186          if (pkt->pkttype == PKT_SECRET_KEY) {          if (pkt->pkttype == PKT_SECRET_KEY) {
# Line 214  keycache_update_photo (gpg_keycache_t ct Line 224  keycache_update_photo (gpg_keycache_t ct
224      fnd->attrib.flags = dat->flags;      fnd->attrib.flags = dat->flags;
225      fnd->attrib.len = dat->octets;      fnd->attrib.len = dat->octets;
226      fnd->attrib.d = (unsigned char*)malloc (dat->octets);      fnd->attrib.d = (unsigned char*)malloc (dat->octets);
227        if (!fnd->attrib.d)
228            BUG (0);
229      memcpy (fnd->attrib.d, dat->d, dat->octets);      memcpy (fnd->attrib.d, dat->d, dat->octets);
230      return 0;      return 0;
231  }  }
# Line 239  keycache_update_photos (gpg_keycache_t c Line 251  keycache_update_photos (gpg_keycache_t c
251  }  }
252    
253    
254    /* Store utf8 decoded user IDs in the code to avoid in-place decoding. */
255    static gpgme_error_t
256    keycache_decode_uids (gpg_keycache_t ctx)
257    {
258        struct native_uid_s *n, *t;
259        struct keycache_s *c;
260        gpgme_user_id_t u;
261    
262        for (c = ctx->item; c; c = c->next) {
263            for (u = c->key->uids; u; u = u->next) {
264                n = (struct native_uid_s*)calloc (1, sizeof *n);
265                if (!n)
266                    BUG (0);
267                if (is_8bit_string (u->uid)) {
268                    n->malloced = 1;
269                    n->uid = utf8_to_native (u->uid);
270                    if (u->name != NULL)
271                        n->name = utf8_to_native (u->name);
272                    if (u->email != NULL)
273                        n->email = strdup (u->email);
274                    if (u->comment != NULL)
275                        n->comment = utf8_to_native (u->comment);
276                }
277                else {
278                    n->malloced = 0;
279                    n->uid = u->uid;
280                    n->name = u->name;
281                    n->comment = u->comment;
282                    n->email = u->email;
283                }
284                if (!c->uids)
285                    c->uids = n;
286                else {
287                    for (t = c->uids; t->next; t=t->next)
288                        ;
289                    t->next = n;
290                }
291            }
292        }  
293        return 0;
294    }
295    
296    
297    static void
298    free_native_uids (struct native_uid_s *n)
299    {
300        struct native_uid_s *t;
301    
302        while (n != NULL) {
303            t = n->next;
304            if (n->malloced) {
305                safe_free (n->uid);
306                safe_free (n->name);
307                safe_free (n->comment);
308                safe_free (n->email);
309                safe_free (n->uid);
310            }
311            safe_free (n);
312            n = t;
313        }
314    }
315    
316    
317    
318  /* Merge the information from the keyrings into the key cache structure. */  /* Merge the information from the keyrings into the key cache structure. */
319  gpgme_error_t  gpgme_error_t
320  keycache_prepare2 (gpg_keycache_t ctx, const char *kid,  keycache_prepare2 (gpg_keycache_t ctx, const char *kid,
# Line 265  keycache_prepare2 (gpg_keycache_t ctx, c Line 341  keycache_prepare2 (gpg_keycache_t ctx, c
341      gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */      gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */
342    
343      pkt = (PACKET*)calloc (1, sizeof * pkt);      pkt = (PACKET*)calloc (1, sizeof * pkt);
344        if (!pkt)
345            BUG (0);
346      gpg_init_packet (pkt);      gpg_init_packet (pkt);
347      while (gpg_parse_packet (inp, pkt) != -1) {      while (gpg_parse_packet (inp, pkt) != -1) {
348          if (pkt->pkttype == PKT_PUBLIC_KEY) {          if (pkt->pkttype == PKT_PUBLIC_KEY) {
# Line 300  keycache_prepare2 (gpg_keycache_t ctx, c Line 378  keycache_prepare2 (gpg_keycache_t ctx, c
378              else if (nsym > 0) {              else if (nsym > 0) {
379                  c->sym_prefs = (unsigned char*)calloc (1, nsym+1);                  c->sym_prefs = (unsigned char*)calloc (1, nsym+1);
380                  if (!c->sym_prefs)                  if (!c->sym_prefs)
381                      return gpg_error (GPG_ERR_ENOMEM);                      BUG (0);
382                  memcpy (c->sym_prefs, sym_prefs, nsym);                  memcpy (c->sym_prefs, sym_prefs, nsym);
383              }              }
384          }          }
# Line 342  gpg_keycache_new (gpg_keycache_t *r_ctx) Line 420  gpg_keycache_new (gpg_keycache_t *r_ctx)
420          return gpg_error (GPG_ERR_INV_ARG);          return gpg_error (GPG_ERR_INV_ARG);
421      ctx = (gpg_keycache_t)calloc (1, sizeof *ctx);      ctx = (gpg_keycache_t)calloc (1, sizeof *ctx);
422      if (!ctx)      if (!ctx)
423          return gpg_error (GPG_ERR_ENOMEM);          BUG (0);
424      ctx->secret = 0;      ctx->secret = 0;
425      ctx->pos = 0;      ctx->pos = 0;
426      *r_ctx = ctx;      *r_ctx = ctx;
# Line 363  gpg_keycache_release (gpg_keycache_t ctx Line 441  gpg_keycache_release (gpg_keycache_t ctx
441          c2 = c->next;          c2 = c->next;
442          gpgme_key_release (c->key);          gpgme_key_release (c->key);
443          c->key = NULL;          c->key = NULL;
444            safe_free (c->pref_keyserver);
445          safe_free (c->sym_prefs);          safe_free (c->sym_prefs);
446          safe_free (c->attrib.d);          safe_free (c->attrib.d);
447          safe_free (c->card_type);          safe_free (c->card_type);
448          free (c);          free_native_uids (c->uids);
449            safe_free (c);
450      }      }
451      safe_free (ctx);      safe_free (ctx);
452  }  }
# Line 402  gpg_keycache_add_key (gpg_keycache_t ctx Line 482  gpg_keycache_add_key (gpg_keycache_t ctx
482            
483      c = (struct keycache_s*)calloc (1, sizeof *c);      c = (struct keycache_s*)calloc (1, sizeof *c);
484      if (!c)      if (!c)
485          return gpg_error (GPG_ERR_ENOMEM);          BUG (0);
486      c->gloflags.is_protected = 1; /*default: assume protection. */      c->gloflags.is_protected = 1; /*default: assume protection. */
487      c->key = key;      c->key = key;
488      if (!ctx->item)      if (!ctx->item)
# Line 503  keycache_reload_photo (gpg_keycache_t ct Line 583  keycache_reload_photo (gpg_keycache_t ct
583    
584  /* Return the next key which was updated. Before it is  /* Return the next key which was updated. Before it is
585     returned the update flag is cleared.     returned the update flag is cleared.
586       @r_status is 1 for a new key and 2 for an updated key.
587     Return value: 0 on success. */     Return value: 0 on success. */
588  gpgme_error_t  gpgme_error_t
589  gpg_keycache_next_updated_key (gpg_keycache_t ctx,  gpg_keycache_next_updated_key (gpg_keycache_t ctx,
590                                 struct keycache_s **r_obj)                                 struct keycache_s **r_obj,
591                                   int *r_status)
592  {  {
593      struct keycache_s *c;      struct keycache_s *c;
594    
595      for (c = ctx->item; c; c = c->next) {      for (c = ctx->item; c; c = c->next) {
596          if (c->flags == 1) {          if (c->flags != 0) {
597              c->flags = 0;              *r_status = c->flags;
598              *r_obj = c;              *r_obj = c;
599                c->flags = 0;
600              return 0;              return 0;
601          }          }
602      }      }
# Line 535  gpg_keycache_update_key (gpg_keycache_t Line 618  gpg_keycache_update_key (gpg_keycache_t
618      err = gpgme_new (&gctx);      err = gpgme_new (&gctx);
619      if (err)      if (err)
620          return err;          return err;
621        gpgme_set_keylist_mode  (gctx, GPGME_KEYLIST_MODE_SIGS);
622      err = gpgme_get_key (gctx, keyid, &key, is_sec);      err = gpgme_get_key (gctx, keyid, &key, is_sec);
623      gpgme_release (gctx);      gpgme_release (gctx);
624      if (err)      if (err)
# Line 544  gpg_keycache_update_key (gpg_keycache_t Line 628  gpg_keycache_update_key (gpg_keycache_t
628          log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);          log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);
629          gpgme_key_release (fndkey);          gpgme_key_release (fndkey);
630          c->key = key;          c->key = key;
631          c->flags = 1;          c->flags = KC_FLAG_UPD;
632          if (is_sec && pub != NULL &&          if (is_sec && pub != NULL &&
633              !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {              !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {
634              log_debug ("keycache update: set public part %p\r\n", fndkey);              log_debug ("keycache update: set public part %p\r\n", fndkey);
# Line 568  gpg_keycache_update_key (gpg_keycache_t Line 652  gpg_keycache_update_key (gpg_keycache_t
652              }              }
653          }          }
654          if (c)          if (c)
655              c->flags = 1;              c->flags = KC_FLAG_ADD;
656      }      }
657      return 0;      return 0;
658  }  }
# Line 592  gpg_keycache_delete_key (gpg_keycache_t Line 676  gpg_keycache_delete_key (gpg_keycache_t
676      c = ctx->item;      c = ctx->item;
677      if (c->next == NULL) {      if (c->next == NULL) {
678          gpgme_key_release (itm->key);          gpgme_key_release (itm->key);
679          if (itm)          safe_free (itm);
             free (itm);  
680          ctx->item = NULL;          ctx->item = NULL;
681      }      }
682      else {      else {
683          while (c && c->next != itm)          for (; c != NULL; c = c->next) {
684              c = c->next;              if (c->next == itm)
685                    break;
686            }
687            assert (c != NULL); /* XXX: sometimes access violation. */
688          c->next = c->next->next;          c->next = c->next->next;
689          gpgme_key_release (itm->key);          gpgme_key_release (itm->key);
690          if (itm)          safe_free (itm);
             free (itm);  
691      }      }
692      return 0;      return 0;
693  }  }
# Line 639  gpg_keycache_init (gpg_keycache_t ctx, c Line 724  gpg_keycache_init (gpg_keycache_t ctx, c
724      if (gpgme_err_code (err) == GPG_ERR_EOF)      if (gpgme_err_code (err) == GPG_ERR_EOF)
725          err = gpg_error (GPG_ERR_NO_ERROR);          err = gpg_error (GPG_ERR_NO_ERROR);
726      keycache_update_photos (ctx);      keycache_update_photos (ctx);
727        keycache_decode_uids (ctx);
728      /* XXX: make sure the progress dialog is closed. */      /* XXX: make sure the progress dialog is closed. */
729      gpgme_op_keylist_end (c);      gpgme_op_keylist_end (c);
730      gpgme_release (c);      gpgme_release (c);
# Line 676  copy_uid_prefs (const unsigned char *pre Line 762  copy_uid_prefs (const unsigned char *pre
762          pos++;          pos++;
763      p = (unsigned char*)calloc (1, pos+1);      p = (unsigned char*)calloc (1, pos+1);
764      if (!p)      if (!p)
765          abort ();          BUG (0);
766      memcpy (p, prefs, pos);      memcpy (p, prefs, pos);
767      return p;      return p;
768  }  }
# Line 697  gpg_keycache_sync (gpg_keycache_t pub, g Line 783  gpg_keycache_sync (gpg_keycache_t pub, g
783              c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;              c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;
784              if (!c->gloflags.divert_to_card)              if (!c->gloflags.divert_to_card)
785                  c->gloflags.divert_to_card = key_divert_to_card (key);                  c->gloflags.divert_to_card = key_divert_to_card (key);
786              c->sym_prefs = copy_uid_prefs (c_sec->sym_prefs);              if (c_sec->sym_prefs)
787                    c->sym_prefs = copy_uid_prefs (c_sec->sym_prefs);
788              c->pubpart = c_sec;              c->pubpart = c_sec;
789              c->pubpart->key = key;              c->pubpart->key = key;
790          }          }
# Line 746  keycache_next_key (gpg_keycache_t ctx, i Line 833  keycache_next_key (gpg_keycache_t ctx, i
833          *r_key = NULL;          *r_key = NULL;
834          return gpg_error (GPG_ERR_EOF);          return gpg_error (GPG_ERR_EOF);
835      }      }
836            if (ctx->tmp->flags != 0)
837            ctx->tmp->flags = 0; /* reset the 'updated' status. */
838        /* it might be possible there is no public key. */
839        if (flags && ctx->tmp->pubpart == NULL)
840            flags = 0;
841      *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;      *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;
842      *c = ctx->tmp = ctx->tmp->next;      *c = ctx->tmp;
843        ctx->tmp = ctx->tmp->next;    
844      ctx->pos++;      ctx->pos++;
845    
846      return 0;      return 0;
# Line 762  gpgme_error_t Line 854  gpgme_error_t
854  gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)  gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)
855  {  {
856      struct keycache_s *c=NULL;      struct keycache_s *c=NULL;
857      gpgme_error_t err = 0;      gpgme_error_t err;
858    
859      err = keycache_next_key (ctx, flags, &c, r_key);      err = keycache_next_key (ctx, flags, &c, r_key);
860      return err;      return err;
861  }  }
862    
863    gpgme_error_t
864    gpg_keycache_next_key2 (gpg_keycache_t ctx, int flags,
865                            struct keycache_s **c, gpgme_key_t *r_key)
866    {
867        return keycache_next_key (ctx, flags, c, r_key);
868    }
869    
870    
871    /* Search for a key with the pattern @pattern and mark
872       this key as the default signing key if found.
873       Return value: 0 on success. */
874    gpgme_error_t
875    gpg_keycache_set_default_key (gpg_keycache_t ctx,
876                                  const char *pattern)
877    {
878        gpgme_error_t err;
879        gpgme_key_t key;
880        struct keycache_s *itm;
881    
882        err = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
883        if (err)
884            return err;
885    
886        if (itm)
887            itm->default_key = 1;
888        return 0;
889    }
890    
891    /* Return the default key from the cache. If no was
892       marked before, NULL is returned in @r_key.
893       Return value: 0 on success. */
894    gpgme_error_t
895    gpg_keycache_get_default_key (gpg_keycache_t ctx,
896                                  gpgme_key_t *r_key)
897    {
898        struct keycache_s *itm;
899    
900        *r_key = NULL;
901        for (itm = ctx->item; itm; itm = itm->next) {
902            if (itm->default_key) {
903                *r_key = itm->key;
904                break;
905            }
906        }
907        if (!*r_key)
908            return gpgme_error (GPG_ERR_NOT_FOUND);
909        return 0;
910    }
911    
912    
913    static gpgme_error_t
914    decode_subpacket (const char *subpkt_data, int *type,
915                      char **out, WORD *outlen)
916    {
917        char tmp[128], *p = tmp, *val;
918        char *enc = NULL;
919        size_t pos = 0, i=0;
920    
921        /* example: spk:24:1:21:http%3A//subkeys.pgp.de */
922        *outlen = 0;
923        *out = NULL;
924        
925        if (strncmp (subpkt_data, "spk:", 4))
926            return gpg_error (GPG_ERR_NO_DATA);
927    
928        strncpy (tmp, subpkt_data, 62);
929        val = strtok (tmp, ":");
930        while (val != NULL) {
931            switch (pos++) {
932            case 0:
933                break;
934    
935            case 1:
936                if (type)
937                    *type = atoi (val);
938                break;
939    
940            case 2:
941                break;
942    
943            case 3:
944                *outlen = atoi (val);
945                break;
946    
947            case 4:
948                enc = strdup (val);
949                break;
950            }
951            val = strtok (NULL, ":");
952        }
953        if (!enc)
954            return gpg_error (GPG_ERR_NO_DATA);;
955        *out = (char*)calloc (1, strlen (enc)+1);
956        if (!*out)
957            BUG (0);
958        for (pos = 0; pos < strlen (enc); pos++) {
959            if (enc[pos] == '%' && enc[pos+1] == '%')
960                (*out)[i++] = '%';
961            else if (enc[pos] == '%') {
962                char temp[3];
963                temp[0] = enc[++pos];
964                temp[1] = enc[++pos];
965                temp[2] = 0;
966                (*out)[i++] = (char)strtoul (temp, NULL, 16);
967            }
968            else
969                (*out)[i++] = enc[pos];
970        }
971        (*out)[i] = 0;
972        safe_free (enc);
973        return 0;
974    }
975    
976    
977    /* If the attribute given in @attr is not set in the
978       key cache object, try to update it. */
979    gpgme_error_t
980    gpg_keycache_update_attr (struct keycache_s *item,
981                              int attr, int force)
982    {
983        gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
984        char *val = NULL;
985        WORD n = 0;    
986    
987        switch (attr) {
988        case KC_ATTR_PREFSYM:
989            if (!force && item->sym_prefs)
990                break;
991            safe_free (item->sym_prefs);
992            err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
993            if (!err && val != NULL)
994                err = decode_subpacket (val, NULL, (char**)&item->sym_prefs, &n);
995            break;
996    
997        case KC_ATTR_PREFKSERV:
998            if (!force && item->pref_keyserver)
999                break;
1000            safe_free (item->pref_keyserver);
1001            err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
1002            if (!err && val != NULL)
1003                err = decode_subpacket (val, NULL, &item->pref_keyserver, &n);
1004            break;
1005        }
1006        safe_free (val);
1007        return err;
1008    }

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26