#pragma pack(2)
#include <Common.h>
#include <System/SysAll.h>
#include <UI/UIAll.h>
#include <System/SysEvtMgr.h>
#include <System/FileStream.h>
#include <libopgp.h>
#include "opgptst.h"

extern keyid_t keys[];

static DmOpenRef AddrDB;

#define MAXRECS 64

static VoidHand abhand[MAXRECS];
static char *abemail[MAXRECS];
static char *pgpk[MAXRECS];
static UInt recnum[MAXRECS];
static int nemails = 0;
static ListPtr keylist;

static struct {
  ULong opts;
  ULong flags;
  unsigned char dummy;
  char fields[1];
} *arecptr;

static void ScanAddrDB(FormPtr renf)
{
  LocalID Addrid;
  VoidHand hand1;
  UInt dbrec;
  char *emptr, *pkptr;
  ULong locf;
  int i;
  FileHand file, ofile;


  Addrid = DmFindDatabase(0, "AddressDB");
  AddrDB = DmOpenDatabase(0, Addrid, dmModeReadOnly | dmModeShowSecret);
  if (!AddrDB)
    ErrDisplay("No Addr DB");

  file = FileOpen(0, "pubring.pkr", 'OPKR', 'OPGP', NORMF, NULL);

  WinDrawChars("Address Book        ", 20, 0, 20);

  nemails = 0;
  for (dbrec = 1; dbrec < DmNumRecords(AddrDB); dbrec++) {

    if (!(hand1 = DmGetRecord(AddrDB, dbrec))
        || !(arecptr = MemHandleLock(hand1)))
      break;

    WinDrawChars("                        ", 24, 0, 32);
    WinDrawChars(arecptr->fields, StrLen(arecptr->fields) > 12 ? 12 : StrLen(arecptr->fields), 0, 32);

    pkptr = 0;
    locf = arecptr->flags;

    if (locf & 0x40080) {       /* email and note */
      emptr = arecptr->fields;
      for (i = 0; i < 7; i++, locf >>= 1)
        if (locf & 1)
          emptr += StrLen(emptr) + 1;
      locf >>= 1;
      pkptr = emptr;
      pkptr += StrLen(pkptr) + 1;

      for (i = 0; i < 10; i++, locf >>= 1)
        if (locf & 1)
          pkptr += StrLen(pkptr) + 1;
      pkptr = StrStr(pkptr, "-----BEGIN PGP PUBLIC");
    }
    if (pkptr) {
      abhand[nemails] = hand1;
      recnum[nemails] = dbrec;
      abemail[nemails] = emptr;
      pgpk[nemails] = pkptr;
      nemails++;

      ofile = FileOpen(0, "RingTemp", 'DATA', 'OPGP', TEMPF, NULL);
      FileWrite(ofile, pkptr, 1, StrLen(pkptr), NULL);
      FileRewind(ofile);
      PGP_dearmor(ofile, file);
      FileClose(ofile);

    } else {
      MemHandleUnlock(hand1);
      DmReleaseRecord(AddrDB, dbrec, 0);
    }
    if (nemails == MAXRECS)
      break;
  }

  keylist = FrmGetObjectPtr(renf, FrmGetObjectIndex(renf, pkeyid));
  LstSetListChoices(keylist, abemail, nemails);
  LstSetSelection(keylist, 0);

  CtlSetLabel(FrmGetObjectPtr(renf, FrmGetObjectIndex(renf, tkeyid)), abemail[0]);

  FileClose(file);

}

#define HALG 2
static int cleanaddr(int uf)
{
  unsigned int i, k;
  FileHand file, ofile;
  unsigned char *buf = NULL, *bp, t, x[4];
  unsigned long ll;
  keyid_t dhkid = 0;

  void *hctx;
  unsigned int salg;
  keyid_t key = 0;
  void *signkey;
  unsigned char sigbuf[768];

#if 1
  if (!uf && 0 >= (salg = PGP_gtkey(&signkey, "", &key))) {
    for (i = 0; i < nemails; i++) {
      MemHandleUnlock(abhand[i]);
      DmReleaseRecord(AddrDB, recnum[i], 0);  /* dirty only if signed */
    }
    nemails = 0;
    DmCloseDatabase(AddrDB);
    return -1;
  }
#endif

  i = LstGetSelection(keylist);
  bp = pgpk[i];

  file = FileOpen(0, "temp.pkr", 'OPKR', 'OPGP', TEMPF, NULL);
  ofile = FileOpen(0, "RingTemp", 'DATA', 'OPGP', TEMPF, NULL);
  FileWrite(ofile, bp, 1, StrLen(bp), NULL);
  FileRewind(ofile);
  PGP_dearmor(ofile, file);
  FileClose(ofile);

#if 0
  /* output file to add signature */
  ofile = FileOpen(0, "temp2.pkr", 'DATA', 'OPGP', TEMPF, NULL);
#endif

  FileRewind(file);

  dhkid = 0;
  while (!dhkid) {
    if (buf)
      MemPtrFree(buf);
    t = fgetc(file);

    if (!(bp = PGP_gtpkt(file, t, &ll)))
      break;

    /* write t, length stuff, buf */

    buf = bp;
    t = (t & 0x7c) >> 2;

#if 1
    if (t == 6 && !uf) {
      uf++;
      hctx = PGP_hini(HALG);
      x[0] = 0x99, x[1] = ll >> 8, x[2] = ll;
      PGP_hblk(hctx, x, 3);
      PGP_hblk(hctx, buf, ll);
    } else if (t == 13 && uf == 1) {
      uf++;
      PGP_hblk(hctx, buf, ll);
      uf++;
      ll = PGP_sigmk(signkey, hctx, sigbuf, key, 0x10, HALG, salg, NULL);
      /* insert dummy validity, signkey */
    }
#endif

    if (t == 5 || t == 6 || t == 7 || t == 14) {  /* sec or pub key */
      if (*bp++ != 4)
        bp += 2;                /* old valid days */
      bp += 4;

      switch (*bp++) {
      case 16:
      case 20:
        i = *bp++ * 256, i += *bp++, i = (i + 7) / 8, bp += i;
        i = *bp++ * 256, i += *bp++, i = (i + 7) / 8, bp += i;
        i = *bp++ * 256, i += *bp++, i = (i + 7) / 8, bp += i;
        dhkid = PGP_gkid(buf, bp - buf);
        break;
      case 1:
      case 2:
      case 3:
        i = *bp++ * 256, i += *bp++, i = (i + 7) / 8, bp += i - 8;
        t = 8;
        while (t--)
          dhkid = (dhkid << 8) + *bp++;
        break;
      }
    }
  }
  FileClose(file);

#if 0
  FileRewind(ofile);
  file = FileOpen(0, "temp.asc", 'OPKR', 'OPGP', TEMPF, NULL);
  PGP_armor(ofile, file);
  FileClose(ofile);
  FileRewind(file);
  /* file to clipboard */
#endif

#if 1
  {
    char obuf[20];

    StrIToH(obuf, dhkid);
    StrCat(obuf, "        ");
    WinDrawChars(obuf, StrLen(obuf), 0, 32);
  }
#endif
  keys[0] = dhkid;
  for (i = 0; i < nemails; i++) {
    MemHandleUnlock(abhand[i]);
    DmReleaseRecord(AddrDB, recnum[i], 0);  /* dirty only if signed */
  }
  nemails = 0;
  DmCloseDatabase(AddrDB);

  return 0;
}



int getkey()
{
  FormPtr renf;

  if (!(renf = FrmInitForm(fsetkey)))
    return;

  ScanAddrDB(renf);
  FrmDoDialog(renf);
  FrmDeleteForm(renf);

  return cleanaddr(3);
}
