documentation
diff --git a/README b/README
index 20ee2ba..97c84e7 100644
--- a/README
+++ b/README
@@ -2,8 +2,10 @@
   libtelnet - TELNET protocol handling library
 =====================================================================
 
-Sean Middleditch
-sean@sourcemud.org
+ http://github.com/elanthis/libtelnet
+
+ Sean Middleditch
+ sean@sourcemud.org
 
 ---------------------------------------------------------------------
 The author or authors of this code dedicate any and all copyright
@@ -35,23 +37,239 @@
 and disabling options, or processing subrequests) must be implemented
 by the application author.
 
+For more information on the TELNET protocol, see:
+
+ http://www.faqs.org/rfcs/rfc854.html
+
 II. LIBTELNET API
 =====================================================================
 
-FIXME: fill in notes about user-facing API
+The libtelnet API contains several distinct parts.  The first part is
+the basic initialization and deinitialization routines.  The second
+part is a single function for pushing received data into the
+libtelnet processor.  The third part is the libtelnet_send_*()
+functions, which generate TELNET commands and ensure data is properly
+formatted before sending over the wire.  The final part is the
+libtelnet_*_cb() functions.
+
+The libtelnet_*_cb() functions (callback fuctions from here out) are
+not actually implemented by libtelnet, but are used by it.  The
+libtelnet.h header includes declarations for the functions but it is
+the application's responsibility to provide implementations of these
+functions.
+
+IIa. Initialization
+
+ struct libtelnet_t;
+   This structure represents the state of the TELNET protocol for a
+   single connection.  Each connection utilizing TELNET must have
+   its own libtelnet_t structure, which is passed to all libtelnet
+   API calls.
+
+ void libtelnet_init(struct libtelnet_t *telnet,
+     enum libtelnet_mode_t mode);
+   The libtelnet_init() function is responsible for initializing
+   the data in a libtelnet_t structure.  It must be called
+   immediately after establishing a connection and before any other
+   libtelnet API calls are made.
+
+   The mode parameter must be one of LIBTELNET_MODE_SERVER or
+   LIBTELNET_MODE_CLIENT.  These slightly alter the behavior of
+   libtelnet in certain instances.  If you are implementing a
+   TELNET server, use the SERVER mode.  If you are implementing a
+   client, use the CLIENT mode.
+ 
+ boid libtelnet_free(struct libtelnet_t *telnet);
+   Releases any internal memory allocated by libtelnet.  This must
+   be called whenever a connection is closed, or you will incur
+   memory leaks.
+
+IIb. Receiving Data
+
+ void libtelnet_push(struct libtelnet_t *telnet,
+     unsigned char *buffer, unsigned int size, void *user_data);
+   When your application receives data over the socket from the
+   remote end, it must pass the received bytes into this function.
+   Callback functions will be invoked as the buffer is processed,
+   and the user_data parameter will be passed to each callback.
+
+IIc. Sending Data
+
+ Note that all of the libtelnet_send_*() functions will invoke
+ the libtelnet_send_cb() callback function.  The user_data parameter
+ to each of these functions is passed through to the callback.
+
+ void libtelnet_send_command(struct libtelnet_t *telnet,
+     unsigned char cmd, void *user_data);
+   Sends a single "simple" TELNET command, such as the GO-AHEAD
+   commands (255 249).
+
+ void libtelnet_send_negotiate(struct libtelnet_t *telnet,
+     unsigned char cmd, unsigned char opt, void *user_data);
+   Sends a TELNET negotiation command.  The cmd parameter must be
+   one of LIBTELNET_WILL, LIBTELNET_DONT, LIBTELNET_DO, or
+   LIBTELNET_DONT.  The opt parameter is the option to
+   negotiate.
+
+ void libtelnet_send_data(struct libtelnet_t *telnet,
+     unsigned char *buffer, unsigned int size, void *user_data);
+   Sends raw data, which would be either the process output from
+   a server or the user input from a client.
+
+ void libtelnet_send_subnegotiation(struct libtelnet_t *telnet,
+     unsigned char opt, unsigned char *buffer, unsigned int size,
+     void *user_data);
+   Sends a TELNET sub-negotiation command.  The opt parameter
+   is the sub-negotiation option.
+
+IId. Callbacks
+
+ The application is responsible for implementing these functions.
+ The function definitions are included in libtelnet.h.  If any of
+ these functions are not implemented and linked into the application
+ then libtelnet.o will generate linker errors for undefined symbols.
+
+ void libtelnet_data_cb(struct libtelnet_t *telnet,
+     unsigned char *buffer, unsigned int size, void *user_data);
+   Regular data has been received by the remote end.  For a server,
+   this would be input typed by the client; for a client, this is
+   process output generated by the server.
+
+   Note that data is not line-buffered by libtelnet.  A single
+   line of input may be broken into pieces and given to
+   consecutive calls to libtelnet_data_cb().  If you are doing
+   line-based processing of data, it is your responsibility to
+   buffer data and find the line breaks.
+
+ void libtelnet_send_cb(struct libtelnet_t *telnet,
+     unsigned char *buffer, unsigned int size, void *user_data);
+   This is called whenever libtelnet has generated output to be
+   send to the remote end of the connection.  In most cases this
+   will be a simple wrapper arround your applications network
+   output buffering/transmission code.
+
+   You can pass socket information through the user_data
+   parameter to libtelnet calls so that it is available in this
+   callback.
+
+ void libtelnet_command_cb(struct libtelnet_t *telnet,
+     unsigned char cmd, void *user_data);
+   Called whenever a "simpler" TELNET command has arrived, such
+   as GO-AHEAD commands (255 249).  The necessary processing
+   depends on the specific commands; see the TELNET RFC for
+   more information.
+
+ void libtelnet_negotiate_cb(struct libtelnet_t *telnet,
+     unsigned char cmd, unsigned char opt, void *user_data);
+   This function is called whenever a TELNET negotiation command
+   has been received.  The cmd parameter will be one of
+   LIBTELNET_WILL, LIBTELNET_WONT, LIBTELNET_DO, or LIBTELNET_DONT.
+   The opt parameter is the option being negotiated.
+
+   libtelnet does not currently manage negotiation for you.  For
+   best practice in implementing TELNET negotiation, see:
+
+    http://www.faqs.org/rfcs/rfc1143.html
+
+ void libtelnet_subnegotiation_cb(struct libtelnet_t *telnet,
+     unsigned char opt, unsigned char *data, unsigned int size,
+     void *user_data);
+   Called whenever a TELNET sub-negotiation has been received.
+   Sub-negotiations include the NAWS option for communicating
+   terminal size to a server, the NEW-ENVIRON and TTYPE options
+   for negotiating terminal features, and MUD-centric protocols
+   such as ZMP, MSSP, and MCCP2.
+
+   The opt parameter is the option under sub-negotiation.  The
+   remaining data (if any) is passed in the buffer.
+
+ void libtelnet_compress_cb(struct libtelnet_t *telnet,
+     char enabled, void *user_data);
+   The callback is invoked whenever the COMPRESS2 (MCCP2)
+   feature is enabled or disabled.  For servers, this is called
+   immediately after beginning compression after a client accepts
+   the COMPRESS2 option.  For clients, this is called immediately
+   after a compress stream begin or ends.
+
+   The enabled parameter is 1 if compression has begun and 0 if
+   compression has ended.
 
 III. INTEGRATING LIBTELNET
 =====================================================================
 
 FIXME: fill in notes about implementing the libtelnet_*_cb functions
 
-IV. OUTPUT PROCESSING
+IV. SAFETY AND CORRECTNESS CONSIDERATIONS
 =====================================================================
 
-FIXME: fill in notes about output buffering recommendations
+Your existing application may make heavy use of its own output
+buffering and transmission commands, including hand-made routines
+for sending TELNET commands and sub-negotiation requests.  There are
+at times subtle issues that need to be handled when communication
+over the TELNET protocol, not least of which is the need to escape
+any byte value 0xFF with a special TELNET command.
 
-V. SAFETY AND CORRECTNESS CONSIDERATIONS
+For these reasons, it is very important that applications making use
+of libtelnet always make use of the libtelnet_send_*() family of
+functions for all data being sent over the TELNET connection.
+
+V. MCCP2 COMPRESSION
 =====================================================================
 
-FIXME: fill in notes about recommending the user of libtelnet over
-all output functions for ensuring safety
+The MCCP2 (COMPRESS2) TELNET extension allows for the compression of
+all traffic sent from server to client.  For more information:
+
+ http://www.mudbytes.net/index.php?a=articles&s=mccp
+
+libtelnet transparently supports MCCP2.  For a server to support
+MCCP2, the application must begin negotiation of the COMPRESS2
+option using libtelnet_send_negotiate(), for example:
+
+ libtelnet_send_negotiate(&telnet, LIBTELNET_WILL,
+     LIBTELNET_OPTION_COMPRESS2, user_data);
+
+libtelnet will automatically detect if the client responds favoribly
+and will begin compressing data.  For clients, no action must be
+taken, as libtelnet will automatically handle the requests.
+
+NOTE: libtelnet will still invoke the callback functions for
+negotiation and sub-negotiation commands relating to MCCP2.  Do not
+respond to these.
+
+In order for libtelnet to support MCCP2, zlib must be installed and
+enabled when compiling libtelnet.  Use -DHAVE_ZLIB to enable zlib
+when compiling libtelnet.c and pass -lz to the linker to link in the
+zlib shared library.
+
+VI. TELNET PROXY UTILITY
+=====================================================================
+
+The telnet-proxy utility is a small application that serves both as
+a testbed for libtelnet and as a powerful debugging tool for TELNET
+servers and clients.
+
+To use telnet-proxy, you must first compile it using:
+
+ $ make
+
+If you do not have zlib installed and wish to disable MCCP2 support
+then you must first edit the Makefile and remove the -DHAVE_ZLIB and
+the -lz from the compile flags.
+
+To run telnet-proxy, you simply give it the server's IP address
+(telnet-proxy does not support hostname resolution, nor IPv6), the
+server's port number, and the port number that telnet-proxy should
+listen on.  For example, to connect to the server on 209.85.171.100
+port 7800 and to listen on port 5000, run:
+
+ $ ./telnet-proxy 209.85.171.100 7800 5000
+
+You can then connect to the host telnet-proxy is running on (e.g.
+127.0.0.1, or the machine's public IP) on port 500 and you will
+automatically be proxied into 209.85.171.100.
+
+telnet-proxy will display status information about the data
+passing through both ends of the tunnel.  Once either end
+disconnects, telnet-proxy will close.  telnet-proxy can only
+support a single tunnel at a time and must be restarted for each
+connection.