#include "libopgp.h"

static const u8_t dmt[84] =
{0xff, 0xff, 0xff, 0x3e, 0xff, 0x41, 0xff, 0x3f, 0x34, 0x35, 0x36, 0x37,
 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, 0xff, 0x40, 0xff, 0xff,
 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a, 0x1b, 0x1c,
 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0xff};

/* static, so when data ends on exact length we have the crc line */
static u8_t dabuf[256], *dabp;

static u32_t PGP_da4x3(u8_t ** c, FILE * ifd, int crcf)
{
  int i, j;
  u32_t t;

  for (i = 0; i < 4; i++) {
    while (!(j = *dabp++) || j > 124 || j < 40 || ((*c)[i] = dmt[j - 40]) > 65)
      if (!j && !fgets(dabp = dabuf, 255, ifd))
        return -1;
    if ((*c)[i] < 64)
      continue;
    if (!crcf)
      break;
    i--;
  }
  t = ((*c)[0] << 18) | ((*c)[1] << 12) | ((*c)[2] << 6) | (*c)[3];
  if (crcf)
    return t;
  (*c)[0] = t >> 16, (*c)[1] = t >> 8, (*c)[2] = t;
  i -= (i > 1);
  *c += i;
  return i;
}

static long unb64(FILE * ifd, FILE * ofd)
{                               /* null ofd returns crc */
  u8_t obuf[800], *c = obuf, *d = obuf;
  u32_t i, ccrc = 0xB704CE;

  dabp = dabuf;
  dabuf[0] = 0;
  do {
    i = PGP_da4x3(&c, ifd, 0);
    if (i != 3 || (c - obuf) > 768) {
      while (d != c)
        ccrc = ccrc << 8 ^ PGP_crc24t[0xff & ((ccrc >> 16) ^ *d++)];
      fwrite(obuf, 1, d - obuf, ofd);
      d = c = obuf;
    }
  } while (i == 3);
  return (ccrc & 0xffffff) ^ PGP_da4x3(&c, ifd, 1);
}

/* dearmor - should also return cert type and headers... */
int PGP_dearmor(FILE * ifd, FILE * ofd)
{
  while (!feof(ifd)) {
    fgets(dabuf, 255, ifd);
    if (strncmp(dabuf, "-----BEGIN PGP ", 15) ||
        !strncmp(dabuf, "-----BEGIN PGP SIGNED MESSAGE-----", 34))
      continue;                 /* skip to message */
    while (dabuf[0] != '\n' && dabuf[0] != '\r')
      fgets(dabuf, 255, ifd);
    if (unb64(ifd, ofd))
      return -1;
  }
  return 0;
}

/*-------------------------*/
/* unmime to buffer */
long PGP_um2b(FILE * ifd, char *ofd)
{
  u32_t i = 3, ccrc = 0xB704CE;
  u8_t *c = ofd, *d;

  dabp = dabuf;
  dabuf[0] = 0;
  while (i == 3)
    i = PGP_da4x3(&c, ifd, 0);
  d = ofd;
  while (d != c)
    ccrc = ccrc << 8 ^ PGP_crc24t[0xff & ((ccrc >> 16) ^ *d++)];
  return (ccrc & 0xffffff) ^ PGP_da4x3(&c, ifd, 1);
}

/* canonicalize string (and remove dash escape) */
void PGP_ctln(char *s)
{
  while (strlen(s) && s[strlen(s) - 1] <= ' ')
    s[strlen(s) - 1] = 0;
  strcat(s, "\r\n");
  if (!strncmp(s, "- -", 3))
    memmove(s, &s[2], strlen(s));
};
