#include "libopgp.h"

int PGP_decry(FILE * inf, FILE * outf, u8_t * keybuf)
{
  int i, j, cfbcnt = 0;
  u32_t ll, gaz;
  u8_t *dbuf, convkey[30], ckeybuf[256], *bp, cvealg = 0;
  void *cfbc[16];

  for (;;) {
    if (keybuf)
      strncpy(ckeybuf, keybuf, 255);
    i = fgetc(inf);
    if ((i & 0xfc) == 0xa8) {   /* literal w/ len & string ("PGP"), bypass */
      free(PGP_gtpkt(inf, i, NULL));
      i = fgetc(inf);
    }
    if (i == 0xc9 || (i & 0xfc) == 0xa4)
      break;
    if ((i & 0xfd) != 0xc1 && (i & 0xf4) != 0x84)  /* new PKE ? */
      exit(-1);
    dbuf = PGP_gtpkt(inf, i, &gaz);
    cfbc[cfbcnt] = NULL;
    if (i == 0xc1 || (i & 0xfc) == 0x84) {
      if (PGP_pkdec(dbuf, ckeybuf))
        continue;
      bp = ckeybuf;
      cvealg = *bp++;           /* crypttype */
      j = PGP_cksz(cvealg);
      memcpy(convkey, bp, j);
      for (ll = 0, i = 0; i < j; i++)  /* accumulate and verify checksum */
        ll += *bp++;
      if (ll != (bp[0] * 256 + bp[1]))
        return -4;
    } else if (i == 0xc3 || (i & 0xfc) == 0x8c) {
      bp = dbuf;
      if (4 != PGP_gts2k(&bp, ckeybuf, &cfbc[cfbcnt]))
        continue;
      if ((ll = gaz + dbuf - bp)) {  /* NZ len means passph enc keymat */
        PGP_cblk(bp, ll, cfbc[cfbcnt]);
        free(cfbc[cfbcnt]), cfbc[cfbcnt] = NULL;
        cvealg = *bp++;         /* crypttype */
        memcpy(convkey, bp, ll - 1);
      }
    }
    free(dbuf);
    memset(ckeybuf, 0, 32);
    if (!cfbc[cfbcnt])
      cfbc[cfbcnt] = PGP_cini(convkey, ckeybuf, cvealg, 0);
    cfbcnt++;
  }
  ungetc(i, inf);
  if (!cfbcnt)
    return -7;
  return PGP_cdec(inf, outf, cfbc, cfbcnt);
}
