
  The routines in libwhois.a implement a protocol close to that defined in
  the "pre-alpha" version of the WHOIS++ draft.  The main differences are:

    - _all_ constraints must be of the form `foo=bar' (i.e. the `hold'
      constraint could be implemented as `hold=true'), lines beginning with
      a space in replies have the form `name=zot', rather than `name: zot'.

    - lines are terminated with a carriage return/line feed pair.

    - continuation lines are not currently supported.

    - currently only full replies are implemented.

    - timeouts are not currently implemented.

    - text lines not part of a reply are thrown away by wReplyParse().


  Strings to the left of `=' must start with a letter, and consist of
  letters, digits and the dash (`-'), while strings to the right of
  `=' must either conform to the preceding rule, or be surrounded by
  double quotes (`"').  Whitespace (spaces and/or tabs) may surround
  names, strings and `='.  Quoted strings follow the normal convention
  that a backslash (`\') quotes itself and a double quote.

  Search queries, system commands and replies are represented internally
  by a linked list of items, each of which is a WItem structure (WItem is
  really a typedef for a structure).  A number of routines are provided
  to construct these lists and access their values, among other things.

  Ordinarily, the programmer only manipulates these lists, while utility
  routines convert them to WHOIS++ conforming text strings for transmission
  over a network connection.

  The description of the routines is divided into sections corresponding
  to the construction of lists representing search queries, system commands,
  constraints (which are always associated with an existing search or
  command list), replies, the extraction of information from items within
  a list and those functions particular to clients, servers or both.

  Typical actions of a client are to construct a search query, or command,
  convert it to a WHOIS++ text string, send it over a network to a server,
  then await a reply.  The reply is received, converted to a list of items
  for processing.

  A server normally waits for text search querie or command to appear
  from a network connection, converting it to a list of items, upon receipt.
  Some server specific action is performed (e.g. searching a database), a
  list of items representing the result is constructed, converted to text
  and sent to a client.



  Include file:
  -------------

    To use any of these routines the file `whois.h' must be included in the
    source file.


  The routines are listed below:


  Constructing lists:
  -------------------

    Search queries:
    ---------------

      WItem *wCreateSearch(void)

        Returns a pointer to the start of a search query list, NULL if
        there was an error.


      WItem *wAppendTerm(WItem *lst, Val fmt, const char *lhs, const char *rhs)

        Append a search term to an existing list.

        `lst' is a pointer to an existing search list (such as that returned by
        `wCreateSearch()').

        `lhs' and `rhs' are strings whose meanings are determined by the value
        of `fmt' (see also wGetFormat()).

        `fmt' indicates how `lhs' and `rhs' are to be interpreted in terms of the
        search.  It may take one of the values:

          F_ALL      - `lhs' is a general serach , in the sense of SEARCH-ALL. `rhs'
                        is ignored.
          F_ATTR_VAL - `lhs' is an attribute, `rhs' is a value.
          F_ATTR     - `lhs' is an attribute.  `rhs' is ignored.
          F_VALUE    - `lhs' is a value.  `rhs' is ignored.
          F_TEMPL    - `lhs' is a template.  `rhs' is ignored.
          F_HAND     - `lhs' is a handle.  `rhs' is ignored.


    System commands:
    ----------------

      WItem *wCreateCommand(const char *cmd, const char *arg)

        Return a pointer to the start of a command list, NULL if
        there was an error.  Note that there may be only one command
        in a command list.

        `cmd' is the command name.

        `arg', if not NULL, is taken to be the argument to the command.


    Constraints:
    ------------

      WItem *wAppendConstraint(WItem *lst, const char *lhs, const char *rhs)

        Append a constraint to either a search term or a system command item.

        `lst' is a pointer to either the start of a search or command list, or
        one item within a search list.  If `lst' is the pointer returned by
        wCreateCommand() or wCreateSearch() then the constraints will be
        global, otherwise they will be local.  Of course, only terms in a
        search list may take local constraints.

        `lhs' and `rhs' are the left and right hand sides of the constraint
        string, for example in "language=francais".

        The value returned points to the new constraint, or is NULL if there
        was an error.


    Replies:
    --------

      WItem *wCreateReply(Val fmt, int hits)

        Return a pointer to the start of a reply list.

        `fmt' is the format of the reply; currently on the full format is
        supported, so the value of `fmt' should be R_FULL (even though
        items in this list may be a mix of type R_FULL and R_FULL_FMT).

        `hits' is the number of matches represented in the reply.  If it
        is less than zero wReply() (see below) will replace it with a count
        of the  number of matches.

        In the case of full replies the number of hits is considered to be
        the number of items with format R_FULL_FMT.


  Getting information from lists:
  -------------------------------

    WItem *wNextItem(WItem *lst)

      Return a pointer to the next item in a list (any type: search, command,
      reply or constraint).  Return NULL if there are no more elements.

      `lst' is a pointer to an item in a list of items.


    WItem *wFirstConstraint(WItem *lst)

      Return a pointer to the first constraint attached to an item.  Return NULL
      if the item has no constraints.

      If `lst' is a pointer returned by either wCreateCommand() or wCreateSearch(),
      then the constraint is global, otherwise the constraint is local to the term
      pointed to by `lst'.  (The returned value may be passed to wNextItem() to
      traverse the list of constraints.)

      It is an error for `lst' to point to a constraint or reply item.

      A NULL pointer is returned if an error is encountered.


    Val wGetType (const WItem *w)

      Return the type of the item pointed to.

      `lst' is a pointer to one item in a list of items.

      The returned value should be one of T_CONS (constraint), T_SEARCH (search
      term), T_SYSTEM (system command) or T_REPLY (reply). It is possible that
      a value of NO_VAL is returned, indicating the the type of the specified
      item is unknown.  This should not happen if only the routines described
      here are used.


    Val wGetFormat(const WItem *w)

      Return the format of the item pointed to.  The format indicates any special
      interpretation given to the strings obtained by wGetLHS() (call it's value
      LHS) and wGetRHS() (call it's value RHS).

      `lst' is a pointer to one item in a list of items.

      The possible return values are listed below, categorized by the type of
      the item to which `w' points:

        T_CONS (constraint)

          NO_VAL - since constraints have no need of formats (i.e. there is only
                   one interpretation of LHS and RHS).

        T_SEARCH (search)

          F_ALL this term's LHS is a search over all attributes, templates,
                etc. (a.k.a. a general search, or SEARCH-ALL).
          F_ATTR - restrict the search for LHS to the attribute fields of
                   templates.
          F_VALUE - restrict the search for LHS to the value fields of
                    attributes.
          F_TEMPL - restrict the search for LHS to the names of templates.
          F_HAND -  restrict the search for LHS to the values of handles.
          F_ATTR_VAL - restrict the search for RHS to those attributes whose
                       name is given by LHS. *Note that of all the _search_
                       formats, this is the only one that uses RHS.*

        T_SYSTEM (commands)

          NO_VAL - since have no need of formats.  LHS is always a command;
                   RHS, if it exists, is the command's argument.

        T_REPLY (reply)

          R_FULL_FMT - corresponds to the "# <template-name> <handle>" line of
                       a full reply.  LHS is the template name and RHS is the
                       handle.
          R_FULL - corresponds to the " <attribute-name> = <value>" line of a
                   full reply.  LHS is the attribute name, RHS is it's value.

          As full replies are the only kind currently implemented, the above
          are the only formats used in them.

      
    const char *wGetLHS(const WItem *w)

      Return a pointer to the string representing the leftmost string (or left
      hand side (LHS) of `=' in certain cases) of an item.

      `w' is a pointer to a search, command, constraint or reply item.

      If `w' points to an item of format F_HEAD, the return value is currently
      undefined (i.e. if non-NULL it should not be relied upon to have any
      particular meaning).


    const char *wGetRHS(const WItem *w)

      Return a pointer to the string representing the rightmost string (or
      right hand side (RHS) of `=' in certain cases) of an item.

      `w' is a pointer to a search, command, constraint or reply item.

      Return NULL if there is no RHS value.

      If the item pointed to is a command, then a non-NULL return value
      indicates the presence of an argument to the command given by the LHS.

      If `w' points to an item of format F_HEAD, the return value is currently
      undefined (i.e. if non-NULL it should not be relied upon to have any
      particular meaning).



  Other routines that are needed are those that convert between lists of items
  and text strings, for transmission between WHOIS++ clients and servers, as
  well as other ancillary routines.

  Descriptions have be grouped according to their primary domain of use: client
  or server, and those that are used in either.


  Routines for use by the client are:
  -----------------------------------

    int wConnect(const char *host, int port, FILE **ifp, FILE **ofp)

      `wConnect' establishes a two-way connection to a whois server.

      `host' is the name of machine on which the server runs.  It
      may be a fully qualified domain name, or a dotted decimal address.

      `port', if greater than zero, specifies the port to which to connect,
      on the server.  If it is less than or equal to zero the standard
      whois port (as specified in /etc/services) is used.

      The input and output file pointers are put in `ifp' and `ofp'
      respectively.

      0 is returned if the connection cannot be made, 1 otherwise.


    char *wQueryStr(const WItem *w)

      `wQueryStr' takes a pointer to a list of items, representing
      either a search query or a system command, and returns a string
      representation conforming to the WHOIS++ protocol.  The string can then
      be sent to the server (see wPutLine() and wConnect()).


v    int wPutLine(FILE *fp, const char *s)

      `wPutLine' writes a text string, terminating it with a carriage
      return and line feed, according to the WHOIS++ protocol.

      `fp' is usually the output file pointer set by wConnect().

      `s' is the string to be written; typically a command or search
      query.  It should _not_ already contain the terminating carriage
      return/line feed pair.

      1 is returned upon success, 0 otherwise (e.g. connection was closed
      by the other end).


    WItem *wReplyParse(FILE *ifp)

      `wReplyParse' reads a reply from the whois server, parses it, and
      returns a list of items representing the response.

      `ifp' is generally the file pointer returned by `wConnect'.



  Routines for use by the server are:
  -----------------------------------

    char *wGetLine(FILE *ifp, char *line, int len)

      Read a single carriage return/line feed terminated line, placing it
      in a buffer.  The terminating carriage return/line feed pair are
      first stripped off and the string is nul terminated.

      `ifp' is typically a connection to a client (e.g. stdin if the server
      is started by inetd(8)).

      `line' is a buffer large enough to contain a WHOIS++ query.  Its actual
      size is left to the discretion of the implementor, as the use of
      continuation lines (not yet implemented) put no upper limit on the total
      size of a query.

      `len' is the size of the buffer.

      Upon success a pointer to `line' is returned, otherwise NULL.


    WItem *wQueryParse(const char *s)

      `wQueryParse' converts a textual WHOIS++ command or search query into a
      list of items.

      `s' is a pointer to a textual query or command, typically that read by
      `wGetLine'.

      If successful, a pointer to a list of items is returned, otherwise NULL.


    int wReply(const WItem *w, int hits, FILE *ofp)

      `wReply' constructs a WHOIS++ conforming textual reply and writes it to
      the client.

      `w' is a pointer to a list of items representing the reply.

      `hits' is the number of matches found if the reply corresponds to a
      search query (otherwise it is ignored).  If `hits' is less than
      zero `wReply' will scan the list to determine the number. (This may be
      inefficient for large lists.)

      `ofp' is a file pointer typically connected to the client.  (At this
      time there is no server routine corresponding to `wConnect'.)


    Note that the reply parsing and generating routines can only handle the
    full format.


  Routines for use in both the client and server:

    void wFreeList((WItem *w)

      Free a list of items.  `wFreeList' may be passed a NULL pointer
      without harm.

      `w' is a list of items.  To avoid memory leaks, it should be the
      pointer returned by one of the `Create' commands (i.e. a pointer
      to the first in a list of items).


    int wGetDebug(void)

      Return the current debugging level.  (See wSetDebug().)


    int wSetDebug(int lev)

      Set the current debugging level to `lev' and return the old level.
      The default level is 1, which reports system call errors and the like.
      Higher levels are used mainly for debugging.  (Currently, levels 2 and
      3 are used.)

      Note that certain error messages (at level 2 and 3) may be misleading
      if you are not aware that text queries are first parsed as searches,
      then as commands if the former fails.  Thus, error messages may be
      generated for valid commands because the parse for a search query
      failed.


  For examples of the use of some of these routines see the program "wwrtest.c".


#
#
# WARNING: unfinished, and not entirely relevant material ahead!!!
#
#

  Construction and Interpretation of WItem lists:
  -----------------------------------------------

    All information passed to or received from the WHOIS routines is stored in a
    list of WItem structures.  The structure is defined thusly:
  
      typedef struct witem_ WItem;
      struct witem_
      {
        Val type;
        Val format;
        const char *lhs;
        const char *rhs;
        WItem *cons;
        WItem *next;
      };
  
    `type' identifies the type of list to which the structure belongs.  It has
    one of the following values:

      T_CONS    - a local or global constraint
      T_HEAD    - the head of a list of T_SEARCH or T_SYSTEM items
      T_SEARCH  - a search term
      T_SYSTEM  - a system command
      T_REPLY   - a reply to a search

    T_HEAD is a special case, in that its purpose it to provide an element to
    which global constraints may be attached for searches and system commands.
    It also starts the reply lists, in which case the `lhs' variable contains
    a pointer to a string representation of the number of hits.

    The value of `format' indicates how that particular item is to be
    interpreted.  It may take on mutually exclusive sets of values, depending
    on the value of `type':

      T_CONS

      T_HEAD

      T_SEARCH

      T_SYSTEM

      T_REPLY



    Both search and system (command) queries are stored as a liked list of WItem
    structures (called "items").  Each item corresponds to one component of a
    query, with a special header item at the beginning of the list.  As well,
    constraints are implemented as a list of items.  For example, the following
    query:
  
      ^user;name=Pooh,case=consider:maxhits=20,hold=true
  
    has the following components (separated by vertical bars):
  
      ^user  |  name=Pooh,case=consider  |  maxhits=20,hold=true
  
    Any list of local constraint items are attached to the corresponding search term,
    while the global constraints are attached to the header item.
  

  Copy of original string in the T_HEAD item (in case of mistaken parse).

---

  To create a search term containing a specifier (e.g. "attribute", "template", etc.)
  you must set the `format' value, and may either put the value of the search string
  in `rhs' or `lhs'.

---

  The WHOIS interface consists of the following routines...

___

  Timeouts not implemented in the library.

---

