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

#include "libpgp5.h"

/*------------------------------------*/
int main(int argc, char *argv[])
{
  unsigned char buf[2048], uid[1024], match[256], *bp, t;
  unsigned long i, j, ll, dhflg = 0, dsaflg = 0;
  DSA *dsakey = DSA_new();
  DH *dhkey = DH_new();
  unsigned long long dsakid = 0, dhkid = 0;
  FILE *outf = stdout;
  extern char *optarg;

  match[0] = 0;
  while ((i = getopt(argc, argv, "o:m:r:esx")) != -1) {
    if (i == 'm')
      strncpy(match, optarg, 256);
    else if (i == 'e')
      dhflg = 1;
    else if (i == 'x')
      dhflg = 2;
    else if (i == 's')
      dsaflg++;
    else if (i == 'r')
      kring = fopen(optarg, "rb");
    else if (i == 'o') {
      outf = fopen(optarg, "wb");
      if (outf == NULL)
        exit(-1);
    } else {
      fprintf(stderr, "usage: lookup5 [-r ring] [-m \"User ID\"] [-e] [-s]\n"
        "-m provides a user string to match, will return all with substring\n"
              "unless used with -e or -s (which returns the first matching)\n"
              "-e for encryption key only, -s for sign key only\n");
      exit(-1);
    }
  }

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

  for (;;) {
    t = fgetc(kring);
    j = (t & 0x7c) >> 2;
    if (j == 5 || j == 6 || j == 2 || j == 14 || j == 7) {
      ll = 1 << (t & 3);        /* length of length */
      fread(&buf[1], ll++, 1, kring);  /* decode length of rest */
      for (j = 1, i = 0; j < ll; j++)
        i = (i << 8) + buf[j];
    } else if (j == 12 || j == 13)
      i = fgetc(kring);
    else
      break;
    fread(buf, i, 1, kring);    /* read the rest of whatever it is */
    if (i < 2000)
      buf[i] = 0;               /* for UIDs and comments */
    bp = buf + 6;
    t = (t & 0x7c) >> 2;

    if (t == 2)                 /* sig */
      continue;
    else if (t == 12)           /* validity */
      continue;
    else if (t == 13) {         /* uid - should match */
      strcpy(uid, buf);
      continue;
    } else if (t == 5 || t == 6 || t == 7 || t == 14) {  /* sec or pub key */

      if (buf[0] != 4)          /* old RSA key */
        continue;

      ll = buf[1] << 24;        /* timestamp */
      ll += buf[2] << 16;
      ll += buf[3] << 8;
      ll += buf[4];

      if ((buf[5] & 0xfe) != 0x10)
        continue;
      /* buf[5] = 0x11 (DSA) or 0x10 (DH) */

      if (t == 5 || t == 6) {   /* dss */
        dsakey->p = pgp2BN5(&bp, 0);
        dsakey->q = pgp2BN5(&bp, 0);  /* correct length */
        dsakey->g = pgp2BN5(&bp, 0);
        dsakey->pub_key = pgp2BN5(&bp, 0);

        donewkeyid(buf, bp - buf);
        dsakid = nkidul;

      } else if (t == 7 || t == 14) {  /* dh priv */
        dhkey->p = pgp2BN5(&bp, 0);
        dhkey->g = pgp2BN5(&bp, 0);
        dhkey->pub_key = pgp2BN5(&bp, 0);

        donewkeyid(buf, bp - buf);
        dhkid = nkidul;

        if (strlen(match) && !strstr(uid, match))
          continue;

        if (!dsaflg && !dhflg) {
          fprintf(outf, "%016qX %016qX %s\n", dsakid, dhkid, uid);
          continue;
        } else if (dsaflg)
          fprintf(outf, "%016qX\n", dsakid);
        else if (dhflg == 1)
          fprintf(outf, "%016qX\n", dhkid);
        else if (dhflg == 2) {
          fwrite(xbp, 1, 3, outf);
          fwrite(buf, 1, bp - buf, outf);
        }
        return 0;
      }
      continue;
    }
    /* 1-pke 8-cmprs 9-cke 11-raw */
    else
      break;                    /* chunk that shouldn't be here */
  }
  return -4;                    /* not found */
}
