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

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

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

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

int
rwhois_command(rw_server_struct   *server,
               char               *command,
               rw_response_struct *response)
{
  size_t command_len;
  size_t wc;

  assert(server);
  assert(response);

  if (NOT_STR_EXISTS(command)) {
    rwhois_set_response(response, RW_OK, "");
    return RW_OK;
  }

  command_len = strlen(command);

  if ( (wc = rwhois_write(server, command, command_len)) <= 0 ) {
    rwhois_set_response(response, RW_ERROR, "Write error sending command");
    return RW_ERROR;
  }

  rwhois_set_response(response, RW_OK, "");
  return RW_OK;
}


int
rwhois_extended(rw_server_struct   *server,
                char               *directive,
                rw_response_struct *response)
{
  int ret_code;

  assert(server);
  assert(response);

  if (NOT_STR_EXISTS(directive)) {
    rwhois_set_response(response, RW_OK, "");
    return RW_OK;
  }

  if (STRN_EQ(directive, "-X-", 3) ||
      STRN_EQ(directive, "X-", 2)) {
    ret_code = rwhois_command(server, directive, response);
  }
  else {
    if ((rwhois_prim_write(server, "-X-", 3) > 0) &&
        (rwhois_write(server, directive, strlen(directive)) > 0)) {
      ret_code = RW_OK;
    } else {
      ret_code = RW_ERROR;
      return RW_ERROR;
    }
  }

  if (ret_code != RW_OK) {
    return response->status;
  }

  return RW_OK;
}


int
rwhois_query(rw_server_struct   *server,
             char               *query,
             rw_response_struct *response)
{
  char final_out[MAXBUFFER];
  char *actual_query;

  assert(server);
  assert(response);

  if (NOT_STR_EXISTS(query)) {
    return RW_OK;
  }

  memset(final_out, 0, sizeof(final_out));

  switch (server->version)
  {
  case VER_1_0:
    sprintf(final_out, "dump %s", query);
    break;
  case VER_2_0:
    sprintf(final_out, "query %s\r\n.", query);
    break;
    case VER_1_5:
    default:
      break;
  }

  if (STR_EXISTS(final_out)) {
    actual_query = final_out;
  } else {
    actual_query = query;
  }

  rwhois_command(server, actual_query, response);

  return response->status;
}


int
rwhois_limit(rw_server_struct   *server,
             int                value,
             rw_response_struct *response)
{
  char             outbuff[80];
  rw_record_struct *record = NULL;
  int              retcode;

  assert(server);
  assert(response);

  sprintf(outbuff, "-limit %d", value);
  retcode = rwhois_command(server, outbuff, response);
  /* did the command get sent? */
  if (retcode != RW_OK) {
    return RW_ERROR;
  }

  /* get the answer */
  record = rwhois_fetch_record(server, response);
  destroy_rw_record_struct(record);

  /* bad? */
  if (response->status != RW_DONE) {
    return RW_ERROR;
  }
  rwhois_set_response(response, RW_OK, "");
  return RW_OK;
}


rw_server_status_struct *
rwhois_status(rw_server_struct   *server,
              rw_response_struct *response)
{
  char                    outbuff[80];
  rw_record_struct        *record   = NULL;
  rw_server_status_struct *status;
  int                     retcode;

  assert(server);
  assert(response);

  sprintf(outbuff, "-status");

  retcode = rwhois_command(server, outbuff, response);

  if (retcode != RW_OK) {
    return NULL;
  }
  record = rwhois_fetch_record(server, response);
  if (response->status == RW_ERROR) {
    destroy_rw_record_struct(record);
    return NULL;
  }

  status = (rw_server_status_struct *) CALLOC(1, sizeof(*status));

  if (rwhois_store_status(record, status) != RW_OK) {
    destroy_rw_record_struct(record);
    destroy_rw_server_status_struct(status);
    rwhois_set_response(response, RW_ERROR, "Error parsing server status");
    return NULL;
  }

  destroy_rw_record_struct(record);
  rwhois_set_response(response, RW_OK, "");
  return status;
}


int
rwhois_forward(rw_server_struct   *server,
               int                action,
               rw_response_struct *response)
{
  rw_record_struct *record = NULL;
  int              retcode;

  assert(server);
  assert(response);

  if (action == RW_ON) {
    retcode = rwhois_command(server, "-forward on", response);
  }
  else {
    retcode = rwhois_command(server, "-forward off", response);
  }

  if (retcode != RW_OK) {
    return RW_ERROR;
  }

  /* get the answer */
  record = rwhois_fetch_record(server, response);

  /* bad? */
  if (response->status != RW_DONE) {
    destroy_rw_record_struct(record);
    return RW_ERROR;
  }

  destroy_rw_record_struct(record);
  rwhois_set_response(response, RW_OK, "");
  return RW_OK;
}

int
rwhois_holdconnect(rw_server_struct   *server,
                   int                action,
                   rw_response_struct *response)
{
  rw_record_struct *record = NULL;
  int              retcode;

  assert(server);
  assert(response);

  if (action == RW_ON) {
    retcode = rwhois_command(server, "-holdconnect on", response);
  }
  else {
    retcode = rwhois_command(server, "-holdconnect off", response);
  }

  if (retcode != RW_OK) {
    return RW_ERROR;
  }

  /* get the answer */
  record = rwhois_fetch_record(server, response);

  /* bad? */
  if (response->status != RW_DONE) {
    destroy_rw_record_struct(record);
    return RW_ERROR;
  }

  server->holdconnect_status = action;

  destroy_rw_record_struct(record);
  rwhois_set_response(response, RW_OK, "");
  return RW_OK;
}

int
rwhois_quit(rw_server_struct   *server,
            rw_response_struct *response)
{
  assert(server);
  assert(response);

  if (!rwhois_is_open(server)) {
    return RW_OK;
  }

  if (rwhois_command(server, "-quit", response) != RW_OK) {
    return RW_ERROR;
  }

  /* probably not worth it to wait for the response */
  rwhois_close(server);

  return RW_OK;
}



int
destroy_rw_server_status_struct(rw_server_status_struct *status)
{
  if (!status) return TRUE;

  if (status->display) FREE(status->display);
  if (status->contact) FREE(status->contact);
  if (status->display_multi) FREE(status->display_multi);
  if (status->display_single) FREE(status->display_single);

  FREE(status);

  return TRUE;
}
