_keybox_parse_openpgp (const unsigned char *image, size_t imagelen,
                       size_t *nparsed, keybox_openpgp_info_t info)
{
  gpg_error_t err = 0;
  const unsigned char *image_start, *data;
  size_t n, datalen;
  int pkttype;
  int first = 1;
  int read_error = 0;
  struct _keybox_openpgp_key_info *k, **ktail = NULL;
  struct _keybox_openpgp_uid_info *u, **utail = NULL;

  memset (info, 0, sizeof *info);
  if (nparsed)
    *nparsed = 0;

  image_start = image;
  while (image)
    {
      err = next_packet (&image, &imagelen, &data, &datalen, &pkttype, &n);
      if (err)
        {
          read_error = 1;
          break;
        }

      if (first)
        {
          if (pkttype == PKT_PUBLIC_KEY)
            ;
          else if (pkttype == PKT_SECRET_KEY)
            info->is_secret = 1;
          else
            {
              err = gpg_error (GPG_ERR_UNEXPECTED);
              if (nparsed)
                *nparsed += n;
              break;
            }
          first = 0;
        }
      else if (pkttype == PKT_PUBLIC_KEY || pkttype == PKT_SECRET_KEY)
        break; /* Next keyblock encountered - ready. */

      if (nparsed)
        *nparsed += n;

      if (pkttype == PKT_SIGNATURE)
        {
          /* For now we only count the total number of signatures. */
          info->nsigs++;
        }
      else if (pkttype == PKT_USER_ID)
        {
          info->nuids++;
          if (info->nuids == 1)
            {
              info->uids.off = data - image_start;
              info->uids.len = datalen;
              utail = &info->uids.next;
            }
          else
            {
              u = xtrycalloc (1, sizeof *u);
              if (!u)
                {
                  err = gpg_error_from_syserror ();
                  break;
                }
              u->off = data - image_start;
              u->len = datalen;
              *utail = u;
              utail = &u->next;
            }
        }
      else if (pkttype == PKT_PUBLIC_KEY || pkttype == PKT_SECRET_KEY)
        {
          err = parse_key (data, datalen, &info->primary);
          if (err)
            break;
        }
      else if( pkttype == PKT_PUBLIC_SUBKEY && datalen && *data == '#' )
        {
          /* Early versions of GnuPG used old PGP comment packets;
           * luckily all those comments are prefixed by a hash
           * sign - ignore these packets. */
        }
      else if (pkttype == PKT_PUBLIC_SUBKEY || pkttype == PKT_SECRET_SUBKEY)
        {
          info->nsubkeys++;
          if (info->nsubkeys == 1)
            {
              err = parse_key (data, datalen, &info->subkeys);
              if (err)
                {
                  info->nsubkeys--;
                  /* We ignore subkeys with unknown algorithms. */
                  if (gpg_err_code (err) == GPG_ERR_UNKNOWN_ALGORITHM
                      || gpg_err_code (err) == GPG_ERR_UNSUPPORTED_ALGORITHM)
                    err = 0;
                  if (err)
                    break;
                }
              else
                ktail = &info->subkeys.next;
            }
          else
            {
              k = xtrycalloc (1, sizeof *k);
              if (!k)
                {
                  err = gpg_error_from_syserror ();
                  break;
                }
              err = parse_key (data, datalen, k);
              if (err)
                {
                  xfree (k);
                  info->nsubkeys--;
                  /* We ignore subkeys with unknown algorithms. */
                  if (gpg_err_code (err) == GPG_ERR_UNKNOWN_ALGORITHM
                      || gpg_err_code (err) == GPG_ERR_UNSUPPORTED_ALGORITHM)
                    err = 0;
                  if (err)
                    break;
                }
              else
                {
                  *ktail = k;
                  ktail = &k->next;
                }
            }
        }
    }

  if (err)
    {
      _keybox_destroy_openpgp_info (info);
      if (!read_error)
        {
          /* Packet parsing worked, thus we should be able to skip the
             rest of the keyblock.  */
          while (image)
            {
              if (next_packet (&image, &imagelen,
                               &data, &datalen, &pkttype, &n) )
                break; /* Another error - stop here. */

              if (pkttype == PKT_PUBLIC_KEY || pkttype == PKT_SECRET_KEY)
                break; /* Next keyblock encountered - ready. */

              if (nparsed)
                *nparsed += n;
            }
        }
    }

  return err;
}