/* *************************************************************
   RWhois Software

   Copyright (c) 1994 Scott Williamson and Mark Kosters
   Copyright (c) 1996-2000 Network Solutions, Inc.

   See the file LICENSE for conditions of use and distribution.
**************************************************************** */

#include "rwhois.h"
#include "rwhois_internal.h"
#include "strutils.h"

static rw_switch_enum string_to_enum(char *str);

char *
find_value_for_attribute(rw_record_struct *record, char *attribute_name)
{
  rw_avpair_struct *avpair = NULL;
  int              not_done = TRUE;

  assert(record);
  assert(STR_EXISTS(attribute_name));

  if (!record->av_pair_list) {
    return NULL;
  }

  not_done = dl_list_first(record->av_pair_list);

  while (not_done) {

    avpair = (rw_avpair_struct *) dl_list_value(record->av_pair_list);
    if (!avpair) {
      not_done = dl_list_next(record->av_pair_list);
      continue;
    }

    if (STR_EQ(avpair->attribute, attribute_name)) {
      return avpair->value;
    }
    not_done = dl_list_next(record->av_pair_list);
  }
  return NULL;
}

static rw_switch_enum
string_to_enum(char *str)
{
  if (NOT_STR_EXISTS(str)) return RW_OFF;

  if (STR_EQ(str, "ON") ||
      STR_EQ(str, " ON")) {
    return RW_ON;
  }

  return RW_OFF;
}


int
rwhois_store_status(rw_record_struct *record,
                    rw_server_status_struct *status)
{
  char *tmp;

  assert(record);
  assert(status);

  tmp = find_value_for_attribute(record, "limit");
  if (tmp == NULL) {
    status->limit = 0;
  }
  else {
    status->limit = atoi(tmp);
  }

  status->holdconnect
    = string_to_enum(find_value_for_attribute(record, "holdconnect"));

  status->forward
    = string_to_enum(find_value_for_attribute(record, "forward"));

  tmp = find_value_for_attribute(record, "objects");
  if (tmp == NULL) {
    status->objects = 0;
  }
  else {
    status->objects = atoi(tmp);
  }

  tmp = find_value_for_attribute(record, "display");
  if (tmp) status->display = STRDUP(tmp);

  tmp = find_value_for_attribute(record, "contact");
  if (tmp) status->contact= STRDUP(tmp);

  tmp = find_value_for_attribute(record, "display_single");
  if (tmp) status->display_single = STRDUP(tmp);

  tmp = find_value_for_attribute(record, "display_multi");
  if (tmp) status->display_multi = STRDUP(tmp);

  tmp = find_value_for_attribute(record, "authority");
  if (tmp == NULL) {
    status->authority = 0;
  }
  else {
    status->authority = atoi(tmp);
  }

  tmp = find_value_for_attribute(record, "cached");
  if (tmp == NULL) {
    status->cached = 0;
  }
  else {
    status->cached = atoi(tmp);
  }

  tmp = find_value_for_attribute(record, "load");
  if (tmp == NULL) {
    status->load = 0;
  }
  else {
    status->load = atoi(tmp);
  }

  tmp = find_value_for_attribute(record, "cache");
  if (tmp == NULL) {
     status->cache = 0;
  }
  else {
    status->cache = atoi(tmp);
  }

  return RW_OK;
}


rw_server_version_enum
get_version(char *str)
{
  char *version = NULL;
  int   i;

  assert(STR_EXISTS(str));

  if (!(version = strstr(str, "V-"))) {
    return VER_UNKNOWN;
  }

  for (i = 0; i < strlen(version); i++) {

    if ((version[i] != ':') && (version[i] != ' ')) continue;

    version[i] = '\0';

    if (STR_EQ(version, "V-1.0")) {
      return VER_1_0;
    }
    else if (STR_EQ(version, "V-1.5")) {
      return VER_1_5;
    }
    else {
      return VER_UNKNOWN;
    }
  }
  return VER_UNKNOWN;
}


void
get_capability(char                 *str,
               rw_server_cap_struct *cap)
{
  char   *tmp    = NULL;
  char   *capstr = NULL;
  u_long capnum  = 0;
  int    i;


  if (!cap || NOT_STR_EXISTS(str)) {
    return;
  }

  if (!(tmp = strstr(str, ":"))) {
    return;
  }

  tmp++;

  capstr = (char *)CALLOC(1, sizeof(char)*(strlen(tmp) + 10));

  for (i = 0; i < strlen(tmp) - 1; i++) {
    if (tmp[i] == ':') {
      capstr[i] = '\0';
      break;
    }
    capstr[i] = tmp[i];
  }
  capstr[i] = '\0';

  sscanf(capstr, "%lu", &capnum);

  FREE(capstr);

  if (capnum & CAP_LOAD) {
    cap->load = ON;
  } else {
    cap->load = OFF;
  }

  if (capnum & CAP_LIMIT) {
    cap->limit = ON;
  } else {
    cap->limit = OFF;
  }

  if (capnum & CAP_SCHEMA) {
    cap->schema = ON;
  } else {
    cap->schema = OFF;
  }

  if (capnum & CAP_XFER) {
    cap->xfer = ON;
  } else {
    cap->xfer = OFF;
  }

  if (capnum & CAP_QUIT) {
    cap->quit = ON;
  } else {
    cap->quit = OFF;
  }

  if (capnum & CAP_STATUS) {
    cap->status = ON;
  } else {
    cap->status = OFF;
  }

  if (capnum & CAP_CACHE) {
    cap->cache = ON;
  } else {
    cap->cache = OFF;
  }

  if (capnum & CAP_HOLDCONNECT) {
    cap->holdconnect = ON;
  } else {
    cap->holdconnect = OFF;
  }

  if (capnum & CAP_FORWARD) {
    cap->forward = ON;
  } else {
    cap->forward = OFF;
  }

  if (capnum & CAP_SOA) {
    cap->soa = ON;
  } else {
    cap->soa = OFF;
  }

  if (capnum & CAP_NOTIFY) {
    cap->notify = ON;
  } else {
    cap->notify = OFF;
  }

  if (capnum & CAP_REGISTER) {
    cap->reg = ON;
  } else {
    cap->reg = OFF;
  }

  if (capnum & CAP_OBJECT) {
    cap->object = ON;
  } else {
    cap->object = OFF;
  }

  if (capnum & CAP_DEFINE) {
    cap->define = ON;
  } else {
    cap->define = OFF;
  }

  if (capnum & CAP_PRIVATE) {
    cap->private = ON;
  } else {
    cap->private = OFF;
  }

  if (capnum & CAP_X) {
    cap->X = ON;
  } else {
    cap->X = OFF;
  }

  if (capnum & CAP_DIRECTIVE) {
    cap->directive = ON;
  } else {
    cap->directive = OFF;
  }

  if (capnum & CAP_DISPLAY) {
    cap->display = ON;
  } else {
    cap->display = OFF;
  }

  if (capnum & CAP_LANGUAGE) {
    cap->language = ON;
  } else {
    cap->language = OFF;
  }
}

fetch_state_enum
decode_line(char *line, rw_server_version_enum version)
{
  assert(line);
  trim(line);

  if (STRN_EQ(line, "%rwhois", 7)) {
    return RW_STATE_RWHOIS;
  }


  switch(version) {
  case VER_1_0:
  case VER_1_5:
    {
      /* directive/query terminators */
      if (STRN_EQ(line, "%error", 6)) return RW_STATE_ERROR;
      if (STR_EQ(line, "%ok")) return RW_STATE_OK;

      /* content prefixes */
      if (STRN_EQ(line, "%referral", 9)) return RW_STATE_REFERRAL;

      /* info blocks */
      if (STR_EQ(line, "%info on")) return RW_STATE_INFO;

      /* -directive content */
      if (STR_EQ(line, "%directive")) return RW_STATE_DIRECTIVE_SEP;
      if (STRN_EQ(line, "%directive ", 11)) return RW_STATE_IN_DIRECTIVE;

      /* -schema content */
      if (STR_EQ(line, "%schema")) return RW_STATE_SCHEMA_SEP;
      if (STRN_EQ(line, "%schema ", 8)) return RW_STATE_IN_SCHEMA;

      /* -class content */
      if (STR_EQ(line, "%class")) return RW_STATE_CLASS_SEP;
      if (STRN_EQ(line, "%class ", 7)) return RW_STATE_IN_CLASS;

      /* -define content */
      if (STR_EQ(line, "%define")) return RW_STATE_DEFINE_SEP;
      if (STRN_EQ(line, "%define ", 8)) return RW_STATE_IN_DEFINE;

      /* -display content */
      if (STR_EQ(line, "%display")) return RW_STATE_DISPLAY_SEP;
      if (STRN_EQ(line, "%display ", 9)) return RW_STATE_IN_DISPLAY;

      /* -object content */
      if (STR_EQ(line, "%object")) return RW_STATE_OBJECT_SEP;
      if (STRN_EQ(line, "%object ", 8)) return RW_STATE_IN_OBJECT;

      /* -soa content */
      if (STR_EQ(line, "%soa")) return RW_STATE_SOA_SEP;
      if (STRN_EQ(line, "%soa ", 5)) return RW_STATE_IN_SOA;

      /* -status content */
      if (STR_EQ(line, "%status")) return RW_STATE_STATUS_SEP;
      if (STRN_EQ(line, "%status ", 8)) return RW_STATE_IN_STATUS;

      /* -xfer content */
      if (STR_EQ(line, "%xfer")) return RW_STATE_XFER_SEP;
      if (STRN_EQ(line, "%xfer ", 6)) return RW_STATE_IN_XFER;

      /* -register content */
      if (STRN_EQ(line, "%register ", 10)) return RW_STATE_IN_REGISTER;

      /* query response content */
      if (STR_EQ(line, "")) return RW_STATE_END_OF_RECORD;

      if (line[0] != '%') return RW_STATE_IN_RECORD;

    }
    break;
  case VER_2_0:
  default:
    break;
  }
  return RW_STATE_ERROR;
}

