#include "sresponse.h"

#include "deadman.h"
#include "defines.h"
#include "log.h"
#include "misc.h"

static int processline PROTO((char         *line,
                              char         *delimiter,
                              dl_list_type *response));


/* ------------------- LOCAL FUNCTIONS -------------------- */


/* processline: This function processes a response line */
static int
processline(line, delimiter, response)
  char         *line;
  char         *delimiter;
  dl_list_type *response;
{
  char *p;

  if (strstr(line, delimiter))
  {
    if ((p = strchr(line, ' ')))
    {
      /* Response line: delimiter text
         For example:   %xfer domain:Auth-Area:a.com
         Parse text */
      p++;
      dl_list_append(response, NEW_STRING(p));
    }
    else
    {
      /* Response line: delimiter
         For example:   %xfer
         End of response */
      return(FALSE);
    }
  }
  else if (strstr(line, "%ok") ||
           strstr(line, "%error"))
  {
    /* End of response */
    return(FALSE);
  }

  return(TRUE);
}


/* ------------------- PUBLIC FUNCTIONS ------------------- */


/* connect_server: This function sets up a TCP connection to
   an RWhois server running at addr:port */
void
connect_server(addr, port, sockfd)
  char *addr;
  int  port;
  int  *sockfd;
{
#ifdef HAVE_IPV6
  struct addrinfo hints, *gai_result, *server_aip;
  char            portstr[MAX_LINE];
  int             connect_status = -1;

  memset( &hints, '\0', sizeof hints );
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  snprintf( portstr, sizeof portstr, "%d", port );
  if ( getaddrinfo( addr, portstr, &hints, &gai_result ) )
  {
    log( L_LOG_ERR, SECONDARY, "connect_server: bad address or port: %s", 
         strerror( errno ) );
    exit( 1 );
  }

  /* Try each returned address until we get a connection. */
  for( server_aip = gai_result; server_aip != NULL;
       server_aip = server_aip->ai_next )
  {
    /* Open socket */
    if ( ( *sockfd = socket( server_aip->ai_family, 
                             server_aip->ai_socktype,
                             server_aip->ai_protocol ) ) < 0 )
      continue;
 
    /* Connect */
    if ( ( connect_status = connect( *sockfd,
                                     (struct sockaddr *) server_aip->ai_addr, 
                                     server_aip->ai_addrlen ) ) == 0 )
      break;
  }

  if ( ! connect_status )
  {
    log(L_LOG_ERR, SECONDARY,
        "connect_server: connect error: %s", strerror(errno));
    exit(1);
  }

#else

  struct sockaddr_in  server;

  bzero((char *) &server, sizeof(server));

  server.sin_family      = AF_INET;
  server.sin_addr.s_addr = inet_addr(addr);
  server.sin_port        = htons(port);

  /* Open socket */
  if ((*sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
  {
    log(L_LOG_ERR, SECONDARY,
        "connect_server: could not open socket: %s", strerror(errno));
    exit(1);
  }
 
  /* Connect */
  if (connect(*sockfd, (struct sockaddr *) &server, sizeof(server)) < 0)
  {
    log(L_LOG_ERR, SECONDARY,
        "connect_server: connect error: %s", strerror(errno));
    exit(1);
  }
  
#endif
  /* Redirect stdin and stdout to socket */
  if (dup2(*sockfd, 0) == -1)
  {
    log(L_LOG_ERR, SECONDARY,
        "connect_server: dup error: %s", strerror(errno));
    exit(1);
  }
  if (dup2(*sockfd, 1) == -1)
  {
    log(L_LOG_ERR, SECONDARY,
        "connect_server: dup error: %s", strerror(errno));
    exit(1);
  }
}


/* send_directive: This function sends directive to
   an RWhois server */
void
send_directive(sockfd, directive)
  int  sockfd;
  char *directive;
{
  /* Write directive */
  if (write(sockfd, directive, strlen(directive)) < 0)
  {
    log(L_LOG_ERR, SECONDARY,
        "send_directive: write error: %s", strerror(errno));
    exit(1);
  }
}


/* recv_response: This functions receives response from
   an RWhois server */
void
recv_response(fp, delimiter, response)
  FILE         *fp;
  char         *delimiter;
  dl_list_type *response;
{
  char line[MAX_LINE];
  int  not_done        = TRUE;

  dl_list_default(response, FALSE, destroy_response_data);

  /* Read response line by line till delimiter */
  do
  {
    set_timer(get_deadman_time(), is_a_deadman);

    if (readline(fp, line, MAX_LINE) == NULL)
    {
      not_done = FALSE;
    }
    else
    {
      unset_timer();
      not_done = processline(line, delimiter, response);
    }
  } while (not_done);
}


/* destroy_response_data: This function frees a character string */
int
destroy_response_data(str)
  char *str;
{
  if (!str)
  {
    return(TRUE);
  }
 
  free(str);
 
  return(TRUE);
}
