#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

#include "libpgp5.h"

/*------------------------------------*/
int main(int argc, char *argv[])
{
  unsigned char *bp0, *bp, t, *sp = NULL;
  unsigned long i, ll;
  int j;
  DSA *dsakey = DSA_new();
  DH *dhkey = DH_new();
  unsigned long long dsakid = 0, dhkid = 0;
  FILE *outf = stdout;
  extern char *optarg;
#ifndef NO_RSA
  RSA *rsakey = RSA_new();
#endif

  while ((i = getopt(argc, argv, "o:r:")) != -1) {
    if (i == 'r')
      kring = fopen(optarg, "rb");
    else if (i == 'o') {
      outf = fopen(optarg, "wb");
      if (outf == NULL)
        exit(-1);
    } else {
      fprintf(stderr, "usage: ringscan [-r ring]\n");
      exit(-1);
    }
  }

  bp = malloc(2048);
  if (!kring && (bp = getenv("PGPPATH"))) {  /* if no kring, try PGPPATH */
    strcat(bp, "/pubring.pkr");
    kring = fopen(bp, "rb");
  }
  if (!kring && (bp = getenv("HOME"))) {  /* no, try default from HOME */
    strcat(bp, "/.pgp/pubring.pkr");
    kring = fopen(bp, "rb");
  }
  if (!kring)
    return -3;                  /* no keyring */
  free(bp);

  while (!feof(kring)) {
    t = fgetc(kring);
    if (!(bp = gazinta(kring, t, &j)))
      break;
    bp0 = bp;
    t = (t & 0x7c) >> 2;
    switch (t) {
    case 2:                    /* sig */
      fprintf(outf, "sig\n");
      continue;
    case 12:                   /* validity */
      fprintf(outf, "val %02x\n", *bp);
      continue;
    case 13:                   /* uid - should match */
      fprintf(outf, "uid %s\n", bp);
      continue;
    case 5:
    case 6:
    case 7:
    case 14:
      switch (t) {
      case 5:
        sp = "KEY";
        break;
      case 6:
        sp = "key";
        break;
      case 7:
        sp = "SUB";
        break;
      case 14:
        sp = "sub";
        break;
      }
      j = *bp++;                /* vers */
      /* timestamp */
      ll = *bp++ << 24, ll += *bp++ << 16, ll += *bp++ << 8, ll += *bp++;
      if (j != 4)
        bp += 2;                /* old valid days */
      switch (*bp++) {
      case 0x11:
        dsakey->p = pgp2BN5(&bp), dsakey->q = pgp2BN5(&bp);
        dsakey->g = pgp2BN5(&bp);
        dsakey->pub_key = pgp2BN5(&bp);
        donewkeyid(bp0, bp - bp0);
        fprintf(outf, "%s %016qX DSA\n", sp, nkidul);
        break;
      case 0x10:
        dhkey->p = pgp2BN5(&bp), dhkey->g = pgp2BN5(&bp);
        dhkey->pub_key = pgp2BN5(&bp);
        donewkeyid(bp0, bp - bp0);
        fprintf(outf, "%s %016qX DH\n", sp, nkidul);
        break;
#ifndef NO_RSA
      case 1:
      case 2:
      case 3:
        rsakey->n = pgp2BN5(&bp), rsakey->e = pgp2BN5(&bp);
        donewkeyid(bp0, bp - bp0);
        dsakid = nkidul;
        j = 64;
        dhkid = 0;
        while (j)
          dhkid = (dhkid << 1) + BN_is_bit_set(rsakey->n, --j);
        fprintf(outf, "%s %016qX RSA %016qX (v4)\n", sp, dsakid, nkidul);
        break;
#endif
      }
      break;
    default:
      fprintf(outf, "??? %d\n", t);
    }
    free(bp);
  }
  return -4;                    /* not found */
}
