/* Common utility routines for rbldnsd.
 */

#include <syslog.h>
#include <stdio.h>
#include <string.h>
#include "rbldnsd.h"

int
readzlines(FILE *f, struct zonedata *z,
           int (*zlpfn)(struct zonedata *z,
                        char *line, int lineno, int llines)) {
  char buf[512], *line;
  int lineno = 0, llineno = 0, noeol = 0, l;
  while(fgets(buf, sizeof(buf), f)) {
    l = strlen(buf);
    if (!l) /* can this happen? */
      continue;
    if (noeol) { /* read parts of long line up to \n */
      if (buf[l - 1] == '\n')
        noeol = 0;
      continue;
    }
    ++lineno;
    if (buf[l - 1] == '\n')
      buf[--l] = '\0';
    else {
      if (!feof(f))
        zlog(LOG_WARNING, lineno, "long line (truncated)");
      noeol = 1; /* mark it to be read above */
    }
    /* skip whitespace */
    line = buf;
    while(*line == ' ' || *line == '\t')
      ++line;
    if (line[0] && line[0] != '#')
      if (!zlpfn(z, line, lineno, llineno++))
        return 0;
  }
  return 1;
}

/* helper routine for dntoip4addr() */

static const unsigned char *dnotoa(const unsigned char *q, unsigned *ap) {
  if (*q < 1 || *q > 3) return NULL;
  if (q[1] < '0' || q[1] > '9') return NULL;
  *ap = q[1] - '0';
  if (*q == 1) return q + 2;
  if (q[2] < '0' || q[2] > '9') return NULL;
  *ap = *ap * 10 + (q[2] - '0');
  if (*q == 2) return q + 3;
  if (q[3] < '0' || q[3] > '9') return NULL;
  *ap = *ap * 10 + (q[3] - '0');
  return *ap > 255 ? NULL : q + 4;
}

/* parse DN (as in 4.3.2.1.in-addr.arpa) to ip4addr_t */

ip4addr_t dntoip4addr(const unsigned char *q) {
  ip4addr_t a = 0, o;
  if ((q = dnotoa(q, &o)) == NULL) return 0; a |= o;
  if ((q = dnotoa(q, &o)) == NULL) return 0; a |= o << 8;
  if ((q = dnotoa(q, &o)) == NULL) return 0; a |= o << 16;
  if ((q = dnotoa(q, &o)) == NULL) return 0; a |= o << 24;
  return *q == 0 ? a : 0;
}

int addrtxt(char *str, ip4addr_t *ap, char **txtp) {
  *ap = 0;
  while(*str == ' ' || *str == '\t') ++str;
  if (*str == ':') {
    char *p = strchr(++str, ':');
    if (p) {
      int bits;
      *p++ = '\0';
      if ((bits = ip4cidr(str, ap)) == 8)
        *ap = (*ap >> 24) | 0x7f000000; /* only last digit in 127.0.0.x */
      else if (bits != 32)
        return 0;
    }
    else
      p = str;
    while(*p == ' ' || *p == '\t') ++p;
    *txtp = p;
  }
  else
    *txtp = str;
  if (strlen(*txtp) >= 255) (*txtp)[254] = '\0'; /* limited by DNS and sstr */
  return 1;
}
