/***************************************************************************
                          posadisrc.cpp  -  routines for reading the posadisrc
                             -------------------
    begin                : do sep 4 2003
    copyright            : (C) 2003 by Meilof
    email                : meilof@users.sourceforge.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "posadisrc.h"
#include "configuration.h"
#include "lib.h"

/* ----- configuration helper functions ------------------------------------ */

void set_setting(setting_fn fn, void *u1, void *u2, const char *_ptr) {
  char *ptr = (char *)_ptr;
  bool more;
  stl_string i2;
  while (1) {
    try {
      i2 = read_entry(ptr);
    } catch (PException p) { throw PException(true, "Expected value: %s!", p.message); break; }
    if (i2[i2.size() - 1] == ',') {
      i2[i2.size() - 1] = 0;
      more = true;
    } else {
      more = false;
    }
    fn(u1, u2, i2.c_str());
    if (!more) {
      char *po = ptr;
      try {
        skip_whitespace(ptr, ptr);
        read_entry(ptr);
      } catch (PException p) {
        break;
      }
      throw PException(true, "Unexpected text at end of line: %s", po);
      break;
    }
  }
}

void zone_set(Zone *z, char *setting, const char *value) {
  z->feed_setting(setting, value);
}

void cachens_set(domainname *znroot, void *dat2, const char *value) {
  char dom[256];
  char dat[17];
  domainname di, d3;
  ZoneDomain *domn;
  char *ptr = strchr(value, '@');
  if (ptr) {
    if (ptr - value + 1 > (signed)sizeof(dom)) throw PException("Domain name too long");
    memcpy(dom, value, ptr - value);
    dom[ptr - value] = 0;
    ptr++;
    di = dom;
    if (strchr(ptr, ':') != 0) { dat[0] = '6'; txt_to_ipv6(dat + 1, ptr); }
    else { dat[0] = '4'; txt_to_ip(dat + 1, ptr); }
  } else {
    di = value;
    dat[0] = '0';
  }
  d3 = "";
  domn = create_domainname(cache_root_domain, d3, *znroot, ZF_DONOTREMOVE);
  domn->create_rrset(DNS_TYPE_NS)->add_rr(518400, di.len(), di.c_str());
  switch (dat[0]) {
    case '4':
      domn = create_domainname(cache_root_domain, d3, di, ZF_DONOTREMOVE);
      domn->create_rrset(DNS_TYPE_A)->add_rr(3600000, 4, dat + 1);
      break;
    case '6':
      domn = create_domainname(cache_root_domain, d3, di, ZF_DONOTREMOVE);
      domn->create_rrset(DNS_TYPE_AAAA)->add_rr(3600000, 16, dat + 1);
      break;
  }
}

void cachefw_set(CacheZone *z, void *dat2, const char *value) {
  _addr a;
  txt_to_addr(&a, value);
  z->forwarders->push_front(a);
}

void conf_set(const char *optname, void *u2, const char *value) {
  if (!feed_setting(optname, value))
    throw PException(true, "Unknown setting %s", optname);
}

/* ----- main posadisrc reading function ----------------------------------- */
void read_posadisrc(const char *fname) {
  FILE *f = try_fopen_r(fname);
  char buff[1024];
  stl_string item;
  char *ptr;
  Zone *z;
  domainname dom, d2, d3;
  char command[32];
  int linenum_new = 1, linenum;

  if (!f) throw PException(true, "Failed to open configuration file %s!", fname);

  try {
    while (!feof(f)) {
      read_line(buff, f, &linenum_new, &linenum);

handle_config_line:
      ptr = buff;

      if (buff[0] == 0) continue;
      if (buff[0] == '\t' || buff[0] == ' ') {
        /* what is this, whitespace? */
        read_entry(ptr);
        if (buff[0] != '\0') throw PException(true, "posadisrc:%d: Line should not begin with whitespace", linenum);
      }
      item = read_entry(ptr);
      if (item == "") {
        if (ptr && ptr[0]) throw PException(true, "posadisrc:%d: No whitespace expected at beginning of line", linenum);
        else continue;
      }
      if (strlen(item.c_str()) + 1 > 31) throw PException(true, "posadisrc:%d: Command name %s too long", linenum, item.c_str());
      strcpy(command, item.c_str());

      if (strcmpi(command, "zone") == 0) {
        /* zone statement */
        try {
          z = create_zone(read_entry(ptr).c_str());
          dom = read_entry(ptr).c_str();
          add_authoritative_zone(dom, z);
          while (!feof(f)) {
            read_line(buff, f, &linenum_new, &linenum);
            if (!buff[0]) continue;
            if (!is_whitespace(buff[0])) break;
            skip_whitespace(buff, ptr);
            if (*ptr == '\0') continue;
            item = read_entry(ptr); /* setting name */
            try {
              set_setting((setting_fn)zone_set, z, (void *)item.c_str(), ptr);
            } catch (PException p) {
              throw PException(true, "Error in setting \"%s\": %s", item.c_str(), p.message);
            }
          }
          if (!feof(f)) goto handle_config_line;
        } catch (PException p) {
          throw PException("Error creating zone: ", p);
        }
      } else if (strcmpi(command, "cache-ns") == 0) {
        dom = read_entry(ptr).c_str();
        while (!feof(f)) {
          read_line(buff, f, &linenum_new, &linenum);
          if (!buff[0]) continue;
          if (!is_whitespace(buff[0])) goto handle_config_line;
          skip_whitespace(buff, ptr);
          if (*ptr == '\0') continue;
          try {
            set_setting((setting_fn)cachens_set, &dom, NULL, ptr);
          } catch (PException p) {
            throw PException("Error in cache NS list: ", p);
          }
        }
      } else if (strcmpi(command, "cache-forward") == 0) {
        z = NULL;
        try {
          dom = read_entry(ptr).c_str();
          if (dom == "") {
            z = (Zone *)cache_root_zone;
            if (!((CacheZone *)z)->forwarders)
              ((CacheZone *)z)->forwarders = new stl_slist(_addr);
          } else {
            z = NULL;
            try {
              z = (Zone *)new CacheZone();
              ((CacheZone *)z)->forwarders = new stl_slist(_addr);
              add_cache_zone(dom, (CacheZone *)z);
            } catch (PException p) { delete z; throw p; }
          }
          while (!feof(f)) {
            read_line(buff, f, &linenum_new, &linenum);
            if (!buff[0]) continue;
            if (!is_whitespace(buff[0])) goto handle_config_line;
            skip_whitespace(buff, ptr);
            if (*ptr == '\0') continue;
            try {
              set_setting((setting_fn)cachefw_set, z, NULL, ptr);
            } catch (PException p) {
              throw PException(true, "Could not set cache forward data: %s", p.message);
            }
          }
        } catch (PException p) {
          throw PException("Could not set forwarding info: ", p);
        }
      } else {
        try {
          set_setting((setting_fn)conf_set, (void *)item.c_str(), NULL, ptr);
        } catch (PException p) {
          throw PException(true, "setting %s: %s", command, p.message);
        }
      }
    }
  } catch (PException p) {
    fclose(f);
    throw PException(true, "error: posadisrc:%d: %s", linenum, p.message);
  }

  fclose(f);
}

void posadisrc_finalize() {
  try {
    end_setting();
    /* now, call end_setting for all zones recursively */
    recursive_zone_end_setting(NULL, "", auth_root_zone);
  } catch (PException p) {
    throw PException("Error finalizing configuration settings: ", p);
  }
}


syntax highlighted by Code2HTML, v. 0.9.1