/* *************************************************************
   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 "strutils.h"

#define COMPONENT_BUF_LEN       80

void
rwhois_set_response(rw_response_struct *response,
                    int                status,
                    char               *msg)
{
  assert(response);

  response->status = status;

  if (STR_EXISTS(msg)) {
    strncpy(response->msg, msg, sizeof(response->msg) - 1);
    response->msg[sizeof(response->msg) - 1] = '\0';
  } else if (msg) {
    response->msg[0] = '\0';
  }
}

/* parse URLs of the form:

   [URL:]scheme://[host[:port]]/otherstuff

   into scheme, host, port, and other. */
int
rwhois_parse_url(char   *url,
                 char   *schema_buf,
                 size_t schema_buf_len,
                 char   *host_buf,
                 size_t host_buf_len,
                 int    *port,
                 char   *other_buf,
                 size_t other_buf_len)
{
  char *p;
  char *q;
  char *term1 = NULL;
  char *term2 = NULL;

  /* skip optional URL: */
  if (STRN_EQ(url, "url:", 4)) {
    url += 4;
  }

  /* skip to first '/' */
  p = strchr(url,'/');

  /* all URLs must have a '/' */
  if (!p) return RW_ERROR;

  /* if the next character isn't another '/', error as well */
  if (*(p + 1) != '/') return RW_ERROR ;

  /* extract the schema by looking for the ':' before the first '/' */
  *p = '\0';
  q = strchr(url, ':');
  if (q) {
    *q = '\0';
    strncpy(schema_buf, url, schema_buf_len);
    *q = ':';
  } else {
    /* no colon before the first '/' */
    *p = '/';
    return RW_ERROR;
  }
  *p = '/';

  /* get the host:port by isolating bit between 'schema://' and '/' */

  q = p + 2;         /* q is just past // */
  p = strchr(q,'/'); /* get to / after host:port */
  if (p) {
    /* isolate host:port, anything following is other_buf material */
    term1 = p;
    *p++ = '\0';
    strncpy(other_buf, p, other_buf_len);
  }

  p = strchr(q, ':');
  if (p) {
    term2 = p;
    *p++ = '\0';
    *port = atoi(p);
  }

  /* if url is schema:///, then there is no host string */
  if (*q == '/') {
    host_buf[0] = '\0';
  }
  else {
    strncpy(host_buf, q, host_buf_len);
  }

  if (term1) {
    *term1 = '/';
  }
  if (term2) {
    *term2 = ':';
  }

  return RW_OK;
}

/* parse referral lines of the form:

   <host>[:port][:scheme]<SP>[authority area]

   into scheme, host, port, and other. */
int
rwhois_parse_old_style_ref(char   *ref,
                           char   *scheme_buf,
                           size_t scheme_buf_len,
                           char   *host_buf,
                           size_t host_buf_len,
                           int    *port,
                           char   *other_buf,
                           size_t other_buf_len)
{
  char *p;
  char *q;
  char *r;

  p = strchr(ref, ' ');

  /* find the space.  if there is one, the rest of the string is the
     'other' */
  if (p) {
    *p++ = '\0';
    strncpy(other_buf, p, other_buf_len);
  }

  /* find the colons */
  q = strchr(ref, ':');
  r = strrchr(ref, ':');

  /* if there is no space or colon, this doesn't match old style */
  if (!p && !q) {
    return RW_ERROR;
  }

  /* check for one colon */
  if (q == r) {
    *q++ = '\0';
    if (is_number_str(q)) {
      *port = atoi(q);
    } else {
      strncpy(scheme_buf, q, scheme_buf_len);
    }

    strncpy(host_buf, ref, host_buf_len);
    *(--q) = ':';
  } else {
    *(q++) = '\0';
    *(r++) = '\0';
    strncpy(scheme_buf, r, scheme_buf_len);
    if (is_number_str(q)) {
      *port = atoi(q);
    }
    strncpy(host_buf, ref, host_buf_len);
    *(--q) = ':';
    *(--r) = ':';
  }

  return RW_OK;
}


rw_referral_struct *
rwhois_parse_referral(char *referral_str,
                      rw_server_version_enum version,
                      rw_referral_struct *referral)
{
   char *url;
   char scheme[COMPONENT_BUF_LEN];
   char host[COMPONENT_BUF_LEN];
   int  port = 0;
   char auth_area[COMPONENT_BUF_LEN];

   assert(referral_str);

   if (!referral) {
     referral = (rw_referral_struct *) CALLOC(1, sizeof(*referral));
   }


   url = strchr(referral_str, ' ');
   if (!url) return NULL;
   url++;

   memset(scheme, 0, sizeof(scheme));
   memset(host, 0, sizeof(host));
   memset(auth_area, 0, sizeof(auth_area));

   /* old-style referrals will return an error here */
   if (rwhois_parse_url(url, scheme, sizeof(scheme),
                        host, sizeof(host),
                        &port,
                        auth_area, sizeof(auth_area)) >= 0) {
     referral->url            = STRDUP(url);
     referral->scheme         = STRDUP(scheme);
     referral->host           = STRDUP(host);
     referral->port           = port;
     referral->authority_area = STRDUP(auth_area);
   }
   else {
     /* old-style referral, hopefully */
     memset(scheme, 0, sizeof(scheme));
     memset(host, 0, sizeof(host));
     memset(auth_area, 0, sizeof(auth_area));

     if (rwhois_parse_old_style_ref(url, scheme, sizeof(scheme),
                                    host, sizeof(host),
                                    &port,
                                    auth_area, sizeof(auth_area)) >= 0) {
       referral->url            = NULL;
       referral->old_style_line = STRDUP(url);
       referral->host           = STRDUP(host);
       referral->port           = port;
       referral->authority_area = STRDUP(auth_area);
     }
     else {
       return NULL;
     }
   }

   return referral;
}


