/* *************************************************************
   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.
**************************************************************** */
#ifndef _RWHOISLIB_H_
#define _RWHOISLIB_H_

#include "common.h"
#include "dl_list.h"
#include "xmem.h"

/*************************************
*
*  This is the header file for RWHOIS API.
*
*************************************/

/*
*  Some definitions
*/

#ifndef TRUE
#define TRUE                            1
#endif
#ifndef FALSE
#define FALSE                           0
#endif

#define MAX_MSG_LEN                     256

#define EXT_REFERRALS_GROUP_NAME        "EXT_REFERRALS"
#define ROOT_GROUP_NAME                 "."

/* memory management */
#define FREE(x)         ( free(x) )
#define MALLOC(x)       ( xmalloc(x) )
#define CALLOC(x,y)     ( xcalloc(x,y) )
#define REALLOC(x,y)    ( xrealloc(x,y) )
#define STRDUP(str)     ( xstrdup(str) )


#define RW_NONFATAL_ERROR -2 /* over hit limit, etc   */
#define RW_ERROR          -1 /* includes fatal errors */
#define RW_OK             1  /* directive ok          */
#define RW_DONE           2  /* last record finished  */
#define RW_FETCH_MORE     3  /* more data to read     */
/*
*  Data Structures
*/

typedef enum {
  RW_OFF = 0,
  RW_ON
} rw_switch_enum;


typedef enum {
  RW_CONN_GOOD,
  RW_CONN_BADADDR,
  RW_CONN_BADSOCK,
  RW_CONN_BADCON,
  RW_CONN_BADMODE,
  RW_CONN_NOTRW
} rw_connect_state_enum;

typedef enum {
  VER_UNKNOWN = -1,
  VER_1_0,
  VER_1_5,
  VER_2_0
} rw_server_version_enum;

typedef enum {
  TEXT,
  ID,
  SEE_ALSO
} rw_attr_value_enum;

typedef enum {
  RW_NO_RECURSE,
  RW_RECURSE
} rw_recurse_mode_enum;

/* This structure holds the results of the '-status' directive */
typedef struct {
  int    retcode;
  int    limit;
  int    holdconnect;
  int    forward;
  int    objects;
  char   *display;
  char   *contact;

  /* RWhois 1.0 status additional variables */
  double load;
  int    cache;
  char   *display_single;
  char   *display_multi;
  int    authority;
  int    cached;
} rw_server_status_struct;


/* This structure holds the results of parsing the capibility string
   sometimes found in the %rwhois banner. */
typedef struct {
  int load;
  int limit;
  int schema;
  int xfer;
  int quit;
  int status;
  int cache;
  int holdconnect;
  int forward;
  int soa;
  int notify;
  int reg;
  int object;
  int define;
  int private;
  int X;
  int directive;
  int display;
  int language;
} rw_server_cap_struct;

/* This structure encapsulates a connection to a rwhois server */
typedef struct {
  char                   *host;
  int                    port;
  int                    sock;
  int                    debug_level;
  rw_switch_enum         holdconnect_status;
  rw_server_version_enum version;
  rw_server_cap_struct   capability;
} rw_server_struct;

/* a base pair */
typedef struct {
  char *name;
  void *value;
} rw_pair_struct;

/* This structure contains additional information about an
   attribute-value pair */
typedef struct {
  char               *language;
  char               *charset;
  char               *encoding;
  rw_attr_value_enum type;
  rw_pair_struct     *other_headers;
} rw_header_struct;

/* An acutal attribute value pair */
typedef struct {
  rw_header_struct *attribute_header;
  char             *attribute;
  char             *value;
} rw_avpair_struct;

/* This structure contains the result of a parsed referral */
typedef struct {
  char *scheme;
  char *host;
  int  port;
  char *authority_area;
  char *url;
  char *old_style_line;
} rw_referral_struct;

/* This structure hold information on the source (which server) of a
   record. */
typedef struct {
  char *protocol;
  char *host;
  int  port;
} rw_record_source_struct;

/* This structure hold a RWhois record.  This structure is used both
   for responses to queries and for record-like responses to other
   directives. */
typedef struct {
  char *schema_name;            /* the object/class */
  char *id;                     /* the RWhois ID */
  char *text;                   /* populated only when a %info appears
                                   in a stream */
  rw_record_source_struct *source; /* where this record came from */
  rw_referral_struct *referral; /* if not NULL then this record
                                   contains a referral */
  dl_list_type *av_pair_list;   /* The attribute/value pairs */
} rw_record_struct;

/* This structure forms a referral group, which consist of a bunch of
   equivalent referrals (except for external referrals, which,
   presumably are all distinct) */
typedef struct {
  char *group_name; /* the authority area name, or 'EXT_REFERRALS' */
  dl_list_type *referrals;
} rw_referral_group_struct;

/* This is the generic response structure.  Most API routine record
   success or failure and an error message in this structure */
typedef struct {
  int  status;
  char msg[MAX_MSG_LEN];
} rw_response_struct;

/* This structure holds the results of a '-load' directive (v1.0 only). */
typedef struct {
  int retcode;
  int curr_load;
  int avg_load;
} rw_load_res_struct;

/* This structure contains a basic RWhois query as well as limit
   arguments. */
typedef struct {
  char *query;
  int  limit_changed_flag;
  int  limit;
} rw_query_args_struct;

/*
 *  Prototype declarations.
 */

/****
 ****    Connection functions
 ****/

/* connect to the rwhois server, filling out the server struct.  This
   routine handles the version negotiation by sending a '-rwhois'
   directive.  If a %info block is encountered, the result is copied
   into the info_buffer.  This routine returns response->status. */
int rwhois_connect(rw_server_struct   *server,
                   char               *spec_version,
                   char               *imp_version,
                   char               *info_buffer,
                   size_t             info_buffer_len,
                   rw_response_struct *response);

/* read at most n characters from 'server' into buffer. Does not strip
   anything.  Marks the server connection as closed if it encounters a
   problem. */
ssize_t rwhois_prim_read(rw_server_struct *server,
                         char             *buffer,
                         size_t           n);

/* read at most n characters from 'server' into buffer. Strips
   trailing whitespace (include crlf).  Returns number of characters
   read (including stripped whitespace). Marks the server connection
   as close if it encounters a problem.*/
ssize_t rwhois_read(rw_server_struct *server,
                    char             *buffer,
                    size_t           n);

/* write at most n characters to 'server' from 'str'. Does not add
   line terminators.  Returns the number of characters written
   exactly.  Closes the connection if it encounters a fatal error. */
size_t rwhois_prim_write(rw_server_struct *server,
                    char             *str,
                    size_t           n);

/* write at most n characters to 'server' from 'str'.  Adds the line
   terminators.  Returns the number of characters written, not
   including line termination.  Closes the connection if it encounters
   a fatal errror. */
size_t rwhois_write(rw_server_struct *server,
                    char             *str,
                    size_t           n);

/* terminate the connection on 'rwhois_server' */
int rwhois_close(rw_server_struct *server);

/* returns true if the connection to the rwhois server is open */
int rwhois_is_open(rw_server_struct *rwhois_server);

int destroy_rw_server_struct(rw_server_struct *server);

/****
 ****    Queries
 ****/

/* issue a simple query to the rwhois server, returns reponse->status */
int rwhois_query(rw_server_struct   *rwhois_server,
                 char               *query,
                 rw_response_struct *response);

/* big query routine -- given query arguments (query + limit changes),
   a server (connected or not), some implementation info, a recursion
   int mode return a list of records (appending to the passed in list
   'record_list', if it exists), returning a list of referrals (if
   referral list isn\'t null).  Status is returned is response. */
dl_list_type *recursive_query_rwhois(rw_query_args_struct *query_args,
                                     rw_server_struct     *server,
                                     char                 *spec_version,
                                     char                 *imp_version,
                                     rw_recurse_mode_enum recurse_mode,
                                     dl_list_type         *referral_group_list,
                                     dl_list_type         *record_list,
                                     rw_response_struct   *response);

/*  common function to retrieve records */
rw_record_struct *rwhois_fetch_record(rw_server_struct   *rwhois_server,
                                      rw_response_struct *response);

/* retrieve all of the records available. If 'record_list' is null, it
   will allocate a new list, otherwise, it will append to
   'record_list' and return it. */
dl_list_type *rwhois_fetch_all_records(rw_server_struct   *rwhois_server,
                                       dl_list_type       *record_list,
                                       rw_response_struct *response);

/* allocate and assign a record source structure to the given record
   using the rest of the information */
void rwhois_set_record_source(rw_record_struct   *record,
                              char               *protocol,
                              char               *host,
                              int                port);

/* allocate and assign a record source structure to the given record
   based on the server */
void rwhois_set_record_source_by_server(rw_record_struct   *record,
                                        rw_server_struct   *server);

int destroy_rw_record_struct(rw_record_struct *record);

int destroy_rw_record_source_struct(rw_record_source_struct *source);

int destroy_rw_avpair_struct(rw_avpair_struct *avpair);

int destroy_rw_header_struct(rw_header_struct *header);

/****
 **** Referrals
 ****/

/* given a record list, glean all of the referrals and return a list
   of rw_referral_group's. It will allocate a new group list if one
   isn't passed in. */
dl_list_type *rwhois_get_all_referrals(dl_list_type *record_list,
                                       dl_list_type *referral_group_list);

rw_referral_group_struct *
rwhois_find_referral_group(dl_list_type *referral_group_list,
                           char         *group_name);

rw_referral_struct *
rwhois_find_referral_in_group(rw_referral_group_struct *ref_group,
                              char *host,
                              int  port,
                              char *other);

int
rwhois_merge_referral_groups(rw_referral_group_struct *dest_group,
                             rw_referral_group_struct *source_group);

int destroy_rw_referral_group_struct(rw_referral_group_struct *group);

int destroy_rw_referral_struct(rw_referral_struct *ref);

/****
 **** Directives
 ****/

/* sets the hit limit to lim_value, returns response->status */
int rwhois_limit(rw_server_struct   *rwhois_server,
                 int                lim_value,
                 rw_response_struct *response );

/* returns the current hit limit, RW_ERROR if an error occurred */
int rwhois_get_limit(rw_server_struct *rwhois_server);

/* set the holdconnect state according to mode; returns response->status */
int rwhois_holdconnect(rw_server_struct   *rwhois_server,
                       int                mode,
                       rw_response_struct *response );

/* set the forward state according to mode; returns response->status */
int rwhois_forward(rw_server_struct   *rwhois_server,
                   int                mode,
                   rw_response_struct *response );

/* issues an soa directive for authority area 'auth_area'.  The
   results are retrieved using rwhois_fetch_record();
   returns response->status */
int rwhois_soa(rw_server_struct   *rwhois_server,
               char               *auth_area,
               rw_response_struct *response);


/* issues a quit directive and then closes the socket */
int rwhois_quit(rw_server_struct   *server,
                rw_response_struct *response);

/* issue an arbitrary rwhois directive; returns response->status */
int rwhois_command(rw_server_struct *server,
                   char *command,
                   rw_response_struct *response);

int destroy_rw_server_status_struct(rw_server_status_struct *status);

/****
 ****   Utility & Error functions
 ****/

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

/* given a referral URL (or 1.0 style referral string), parse it into
   the referral structure */
rw_referral_struct *rwhois_parse_referral(char *referral_str,
                                          rw_server_version_enum version,
                                          rw_referral_struct *referral);

/* more basic URL parsing algo. */
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);


/* given a record generated by a status command, load the status into
   the status structure */
int rwhois_store_status(rw_record_struct *status_record,
                        rw_server_status_struct *status);

/* given a '%error' response string, extract the error number */
int rwhois_extract_error_number(char *str);

/* given a '%error' response string, extract the error message */
char *rwhois_extract_error_msg(char *str);

/****
 ****   Display Functions
 ****/

void rwhois_print_record(rw_record_struct *record);

void rwhois_print_avlist(dl_list_type *av_list);

void rwhois_print_status(rw_server_struct        *server,
                         rw_server_status_struct *status);


#endif
