gnome-mud r797 - in trunk: . src src/handlers src/zmp



Author: lharris
Date: Tue Mar 17 18:08:13 2009
New Revision: 797
URL: http://svn.gnome.org/viewvc/gnome-mud?rev=797&view=rev

Log:
Telnet Handlers are now compiled as a static library and linked in.

Added:
   trunk/src/handlers/
   trunk/src/handlers/Makefile.am
   trunk/src/handlers/mud-telnet-charset.c
   trunk/src/handlers/mud-telnet-charset.h
   trunk/src/handlers/mud-telnet-echo.c
   trunk/src/handlers/mud-telnet-echo.h
   trunk/src/handlers/mud-telnet-eor.c
   trunk/src/handlers/mud-telnet-eor.h
   trunk/src/handlers/mud-telnet-handler-interface.c
   trunk/src/handlers/mud-telnet-handler-interface.h
   trunk/src/handlers/mud-telnet-handlers.h
   trunk/src/handlers/mud-telnet-mccp.c
   trunk/src/handlers/mud-telnet-mccp.h
   trunk/src/handlers/mud-telnet-msp.c
   trunk/src/handlers/mud-telnet-msp.h
   trunk/src/handlers/mud-telnet-mssp.c
   trunk/src/handlers/mud-telnet-mssp.h
   trunk/src/handlers/mud-telnet-naws.c
   trunk/src/handlers/mud-telnet-naws.h
   trunk/src/handlers/mud-telnet-new-environ.c
   trunk/src/handlers/mud-telnet-new-environ.h
   trunk/src/handlers/mud-telnet-ttype.c
   trunk/src/handlers/mud-telnet-ttype.h
   trunk/src/handlers/mud-telnet-zmp.c
   trunk/src/handlers/mud-telnet-zmp.h
   trunk/src/zmp/
   trunk/src/zmp/Makefile.am
   trunk/src/zmp/zmp-subwindow.c
   trunk/src/zmp/zmp-subwindow.h
Removed:
   trunk/src/mud-telnet-charset.c
   trunk/src/mud-telnet-charset.h
   trunk/src/mud-telnet-echo.c
   trunk/src/mud-telnet-echo.h
   trunk/src/mud-telnet-eor.c
   trunk/src/mud-telnet-eor.h
   trunk/src/mud-telnet-handler-interface.c
   trunk/src/mud-telnet-handler-interface.h
   trunk/src/mud-telnet-mccp.c
   trunk/src/mud-telnet-mccp.h
   trunk/src/mud-telnet-msp.c
   trunk/src/mud-telnet-msp.h
   trunk/src/mud-telnet-mssp.c
   trunk/src/mud-telnet-mssp.h
   trunk/src/mud-telnet-naws.c
   trunk/src/mud-telnet-naws.h
   trunk/src/mud-telnet-new-environ.c
   trunk/src/mud-telnet-new-environ.h
   trunk/src/mud-telnet-ttype.c
   trunk/src/mud-telnet-ttype.h
   trunk/src/mud-telnet-zmp.c
   trunk/src/mud-telnet-zmp.h
Modified:
   trunk/ChangeLog
   trunk/autogen.sh
   trunk/configure.ac
   trunk/src/Makefile.am
   trunk/src/mud-connection-view.c
   trunk/src/mud-telnet.c
   trunk/src/mud-telnet.h

Modified: trunk/autogen.sh
==============================================================================
--- trunk/autogen.sh	(original)
+++ trunk/autogen.sh	Tue Mar 17 18:08:13 2009
@@ -4,18 +4,13 @@
 srcdir=`dirname $0`
 test -z "$srcdir" && srcdir=.
 
-PKG_NAME="gnome-mud"
-REQUIRED_AUTOMAKE_VERSION=1.7
+REQUIRED_AUTOMAKE_VERSION=1.9
 
-(test -f $srcdir/configure.ac) || {
-    echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
-    echo " top-level $PKG_NAME directory"
-    exit 1
-}
+PKG_NAME="gnome-mud"
 
 which gnome-autogen.sh || {
-	echo "You need to install gnome-common from the GNOME CVS"
+	echo "You need to install gnome-common from the GNOME SVN"
 	exit 1
 }
 
-USE_GNOME2_MACROS=1 . gnome-autogen.sh
+. gnome-autogen.sh

Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac	(original)
+++ trunk/configure.ac	Tue Mar 17 18:08:13 2009
@@ -55,6 +55,7 @@
 
 dnl Checks for programs.
 AC_PROG_CC
+AC_PROG_LIBTOOL
 AM_PROG_CC_STDC
 AC_ISC_POSIX
 AC_PROG_LN_S
@@ -141,6 +142,8 @@
   data/icons/Makefile
   doc/Makefile
   src/Makefile
+  src/handlers/Makefile
+  src/zmp/Makefile
   po/Makefile.in
   ui/Makefile
 ])

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Tue Mar 17 18:08:13 2009
@@ -1,5 +1,10 @@
+SUBDIRS = handlers zmp
+
+bin_PROGRAMS = gnome-mud
+
 localedir = $(datadir)/locale
-INCLUDES =								\
+
+gnome_mud_CPPFLAGS =							\
 	-DLOCALEDIR=\"$(localedir)\"					\
 	-DPIXMAPSDIR=\""$(datadir)/pixmaps"\"				\
 	-DGMPIXMAPSDIR=\""$(datadir)/icons/hicolor/scalable/apps"\"	\
@@ -8,11 +13,18 @@
 	-DDATADIR=\""$(datadir)"\"					\
 	-DLIBDIR=\""$(libdir)"\"					\
 	-DGLADEDIR=\""$(pkgdatadir)"\"					\
-	$(GMUD_CFLAGS) $(MSP_CFLAGS)
-LDADD   = $(GMUD_LIBS) $(Z_LIBS) $(MSP_LIBS)
-AM_CPPFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\"
+	-DPKGDATADIR=\""$(pkgdatadir)"\"
 
-bin_PROGRAMS = gnome-mud
+gnome_mud_CFLAGS = \
+	$(GMUD_CFLAGS) \
+	$(MSP_CFLAGS)
+
+gnome_mud_LDADD = \
+	handlers/libtelnethandlers.la \
+	zmp/libzmpcommands.la \
+	$(GMUD_LIBS)	\
+	$(Z_LIBS)	\
+	$(MSP_LIBS)
 
 gnome_mud_SOURCES =				\
 	gconf-helper.c				\
@@ -46,28 +58,6 @@
 	mud-regex.h				\
 	mud-telnet.c				\
 	mud-telnet.h				\
-	mud-telnet-handler-interface.c		\
-	mud-telnet-handler-interface.h		\
-	mud-telnet-ttype.c			\
-	mud-telnet-ttype.h			\
-	mud-telnet-naws.c			\
-	mud-telnet-naws.h			\
-	mud-telnet-echo.c			\
-	mud-telnet-echo.h			\
-	mud-telnet-eor.c			\
-	mud-telnet-eor.h			\
-	mud-telnet-charset.c			\
-	mud-telnet-charset.h			\
-	mud-telnet-mccp.c			\
-	mud-telnet-mccp.h			\
-	mud-telnet-msp.c			\
-	mud-telnet-msp.h			\
-	mud-telnet-mssp.c			\
-	mud-telnet-mssp.h			\
-	mud-telnet-new-environ.c		\
-	mud-telnet-new-environ.h		\
-	mud-telnet-zmp.c			\
-	mud-telnet-zmp.h			\
 	mud-tray.c				\
 	mud-tray.h				\
 	mud-window.c				\
@@ -88,10 +78,14 @@
 	$(BUILT_SOURCES)
 
 gnome-mud-marshallers.h: gnome-mud-marshallers.list
-	$(GLIB_GENMARSHAL) --prefix gnome_mud_cclosure --header \
-	    gnome-mud-marshallers.list > gnome-mud-marshallers.h
+	( $(GLIB_GENMARSHAL) --prefix gnome_mud_cclosure --header \
+	    gnome-mud-marshallers.list > gnome-mud-marshallers.h.tmp \
+	    && mv gnome-mud-marshallers.h.tmp gnome-mud-marshallers.h ) \
+	    || ( rm -f gnome-mud-marshallers.h.tmp && exit 1 )
 
 gnome-mud-marshallers.c: gnome-mud-marshallers.list
-	$(GLIB_GENMARSHAL) --prefix gnome_mud_cclosure --body \
-	    gnome-mud-marshallers.list > gnome-mud-marshallers.c
+	( $(GLIB_GENMARSHAL) --prefix gnome_mud_cclosure --body \
+	    gnome-mud-marshallers.list > gnome-mud-marshallers.c.tmp \
+	    && mv gnome-mud-marshallers.c.tmp gnome-mud-marshallers.c ) \
+	    || ( rm -f gnome-mud-marshallers.c.tmp && exit 1 )
 

Added: trunk/src/handlers/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/src/handlers/Makefile.am	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,45 @@
+NULL =
+
+noinst_LTLIBRARIES = libtelnethandlers.la
+
+libtelnethandlers_la_SOURCES = \
+	mud-telnet-charset.c \
+	mud-telnet-charset.h \
+	mud-telnet-echo.c \
+	mud-telnet-echo.h \
+	mud-telnet-eor.c \
+	mud-telnet-eor.h \
+	mud-telnet-handlers.h \
+	mud-telnet-handler-interface.c \
+	mud-telnet-handler-interface.h \
+	mud-telnet-mccp.c \
+	mud-telnet-mccp.h \
+	mud-telnet-msp.c \
+	mud-telnet-msp.h \
+	mud-telnet-mssp.c \
+	mud-telnet-mssp.h \
+	mud-telnet-naws.c \
+	mud-telnet-naws.h \
+	mud-telnet-new-environ.c \
+	mud-telnet-new-environ.h \
+	mud-telnet-ttype.c \
+	mud-telnet-ttype.h \
+	mud-telnet-zmp.c \
+	mud-telnet-zmp.h \
+	$(NULL)
+
+libtelnethandlers_la_CPPFLAGS = \
+	-I$(srcdir)/.. \
+	$(AM_CPPFLAGS)
+
+libtelnethandlers_la_CFLAGS = \
+	$(GMUD_CFLAGS) \
+	$(MSP_CFLAGS)
+
+libtelnethandlers_la_LDFLAGS =
+
+libtelnethandlers_la_LIBADD = \
+	$(GMUD_LIBS) \
+	$(MSP_LIBS) \
+	$(Z_LIBS)
+

Added: trunk/src/handlers/mud-telnet-charset.c
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-charset.c	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,378 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-charset.c
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include <gnet.h>
+
+#include "gnome-mud.h"
+#include "mud-telnet.h"
+#include "mud-telnet-handler-interface.h"
+#include "mud-telnet-charset.h"
+
+struct _MudTelnetCharsetPrivate
+{
+    /* Interface Properties */
+    MudTelnet *telnet;
+    gboolean enabled;
+    gint option;
+
+    /* Private Instance Members */
+};
+
+/* Property Identifiers */
+enum
+{
+    PROP_MUD_TELNET_CHARSET_0,
+    PROP_ENABLED,
+    PROP_HANDLES_OPTION,
+    PROP_TELNET
+};
+
+/* Class Functions */
+static void mud_telnet_charset_init (MudTelnetCharset *self);
+static void mud_telnet_charset_class_init (MudTelnetCharsetClass *klass);
+static void mud_telnet_charset_interface_init(MudTelnetHandlerInterface *iface);
+static void mud_telnet_charset_finalize (GObject *object);
+static GObject *mud_telnet_charset_constructor (GType gtype,
+                                             guint n_properties,
+                                             GObjectConstructParam *properties);
+static void mud_telnet_charset_set_property(GObject *object,
+                                         guint prop_id,
+                                         const GValue *value,
+                                         GParamSpec *pspec);
+static void mud_telnet_charset_get_property(GObject *object,
+                                         guint prop_id,
+                                         GValue *value,
+                                         GParamSpec *pspec);
+
+/* Interface Implementation */
+void mud_telnet_charset_enable(MudTelnetHandler *self);
+void mud_telnet_charset_disable(MudTelnetHandler *self);
+void mud_telnet_charset_handle_sub_neg(MudTelnetHandler *self,
+                                    guchar *buf,
+                                    guint len);
+
+/* Private Methods */
+static void mud_telnet_charset_send(MudTelnetCharset *self, gchar *encoding);
+
+/* Create the Type. We implement MudTelnetHandlerInterface */
+G_DEFINE_TYPE_WITH_CODE(MudTelnetCharset, mud_telnet_charset, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (MUD_TELNET_HANDLER_TYPE,
+                                               mud_telnet_charset_interface_init));
+/* MudTelnetCharset class functions */
+static void
+mud_telnet_charset_class_init (MudTelnetCharsetClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    /* Override base object constructor */
+    object_class->constructor = mud_telnet_charset_constructor;
+
+    /* Override base object's finalize */
+    object_class->finalize = mud_telnet_charset_finalize;
+
+    /* Override base object property methods */
+    object_class->set_property = mud_telnet_charset_set_property;
+    object_class->get_property = mud_telnet_charset_get_property;
+
+    /* Add private data to class */
+    g_type_class_add_private(klass, sizeof(MudTelnetCharsetPrivate));
+
+    /* Override Implementation Properties */
+    g_object_class_override_property(object_class,
+                                     PROP_ENABLED,
+                                     "enabled");
+
+    g_object_class_override_property(object_class,
+                                     PROP_HANDLES_OPTION,
+                                     "handles-option");
+
+    g_object_class_override_property(object_class,
+                                     PROP_TELNET,
+                                     "telnet");
+}
+
+static void
+mud_telnet_charset_interface_init(MudTelnetHandlerInterface *iface)
+{
+    iface->Enable = mud_telnet_charset_enable;
+    iface->Disable = mud_telnet_charset_disable;
+    iface->HandleSubNeg = mud_telnet_charset_handle_sub_neg;
+}
+
+static void
+mud_telnet_charset_init (MudTelnetCharset *self)
+{
+    /* Get our private data */
+    self->priv = MUD_TELNET_CHARSET_GET_PRIVATE(self);
+
+    /* Set the defaults */
+    self->priv->telnet = NULL;
+    self->priv->option = TELOPT_CHARSET;
+    self->priv->enabled = FALSE;
+}
+
+static GObject *
+mud_telnet_charset_constructor (GType gtype,
+                              guint n_properties,
+                              GObjectConstructParam *properties)
+{
+    MudTelnetCharset *self;
+    GObject *obj;
+    MudTelnetCharsetClass *klass;
+    GObjectClass *parent_class;
+
+    /* Chain up to parent constructor */
+    klass = MUD_TELNET_CHARSET_CLASS( g_type_class_peek(MUD_TYPE_TELNET_CHARSET) );
+    parent_class = G_OBJECT_CLASS( g_type_class_peek_parent(klass) );
+    obj = parent_class->constructor(gtype, n_properties, properties);
+
+    self = MUD_TELNET_CHARSET(obj);
+
+    if(!self->priv->telnet)
+    {
+        g_printf("ERROR: Tried to instantiate MudTelnetCharset without passing parent MudTelnet\n");
+        g_error("Tried to instantiate MudTelnetCharset without passing parent MudTelnet");
+    }
+
+    return obj;
+}
+
+static void
+mud_telnet_charset_finalize (GObject *object)
+{
+    MudTelnetCharset *self;
+    GObjectClass *parent_class;
+
+    self = MUD_TELNET_CHARSET(object);
+
+    parent_class = g_type_class_peek_parent(G_OBJECT_GET_CLASS(object));
+    parent_class->finalize(object);
+}
+
+static void
+mud_telnet_charset_set_property(GObject *object,
+                              guint prop_id,
+                              const GValue *value,
+                              GParamSpec *pspec)
+{
+    MudTelnetCharset *self;
+
+    self = MUD_TELNET_CHARSET(object);
+
+    switch(prop_id)
+    {
+        case PROP_TELNET:
+            self->priv->telnet = MUD_TELNET(g_value_get_object(value));
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+static void
+mud_telnet_charset_get_property(GObject *object,
+                              guint prop_id,
+                              GValue *value,
+                              GParamSpec *pspec)
+{
+    MudTelnetCharset *self;
+
+    self = MUD_TELNET_CHARSET(object);
+
+    switch(prop_id)
+    {
+        case PROP_ENABLED:
+            g_value_set_boolean(value, self->priv->enabled);
+            break;
+
+        case PROP_HANDLES_OPTION:
+            g_value_set_int(value, self->priv->option);
+            break;
+
+        case PROP_TELNET:
+            g_value_take_object(value, self->priv->telnet);
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+/* Interface Implementation */
+void 
+mud_telnet_charset_enable(MudTelnetHandler *handler)
+{
+    MudTelnetCharset *self;
+
+    self = MUD_TELNET_CHARSET(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_CHARSET(self));
+
+    self->priv->enabled = TRUE;
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "CHARSET Enabled");
+}
+
+void
+mud_telnet_charset_disable(MudTelnetHandler *handler)
+{
+    MudTelnetCharset *self;
+    MudConnectionView *view;
+
+    self = MUD_TELNET_CHARSET(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_CHARSET(self));
+
+    self->priv->enabled = FALSE;
+
+    g_object_get(self->priv->telnet, "parent-view", &view, NULL);
+
+    g_object_set(view,
+                 "remote-encode", FALSE,
+                 "remote-encoding", NULL,
+                 NULL);
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "CHARSET Disabled");
+}
+
+void
+mud_telnet_charset_handle_sub_neg(MudTelnetHandler *handler,
+                               guchar *buf,
+                               guint len)
+{
+    gint index = 0;
+    guchar sep;
+    guchar tbuf[9];
+    gchar sep_buf[2];
+    GString *encoding;
+    gchar **encodings;
+    MudTelnetCharset *self;
+
+    self = MUD_TELNET_CHARSET(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_CHARSET(self));
+
+    switch(buf[index])
+    {
+        case TEL_CHARSET_REQUEST:
+            // Check for [TTABLE] and
+            // reject if found.
+            memcpy(&buf[1], tbuf, 8);
+            tbuf[8] = '\0';
+
+            if(strcmp((gchar *)tbuf, "[TTABLE]") == 0)
+            {
+                mud_telnet_send_sub_req(self->priv->telnet, 2,
+                        (guchar)TELOPT_CHARSET,
+                        (guchar)TEL_CHARSET_TTABLE_REJECTED);
+                return;
+            }
+
+            sep = buf[++index];
+            index++;
+
+            encoding = g_string_new(NULL);
+
+            while(buf[index] != (guchar)TEL_SE)
+                encoding = g_string_append_c(encoding, buf[index++]);
+
+            sep_buf[0] = (gchar)sep;
+            sep_buf[1] = '\0';
+            encodings = g_strsplit(encoding->str, sep_buf, -1);
+
+            /* We are using VTE's locale fallback function
+               to handle a charset we do not support so we
+               just take the first returned and use it.
+
+               This is potentially stupid. Fix me? */
+
+            if(g_strv_length(encodings) != 0)
+            {
+                MudConnectionView *view;
+                g_object_get(self->priv->telnet, "parent-view", &view, NULL);
+
+                g_object_set(view,
+                        "remote-encode", TRUE,
+                        "remote-encoding", encodings[0],
+                        NULL);
+
+
+                mud_telnet_charset_send(self, encodings[0]);
+            }
+
+            g_string_free(encoding, TRUE);
+            g_strfreev(encodings);
+
+            break;
+    }
+}
+
+/* Private Methods */
+static void
+mud_telnet_charset_send(MudTelnetCharset *self, gchar *encoding)
+{
+    guchar byte;
+    guint32 i;
+    GConn *conn;
+
+    g_return_if_fail(MUD_IS_TELNET_CHARSET(self));
+
+    if(!encoding)
+	return;
+
+    g_log("Telnet", G_LOG_LEVEL_DEBUG, "Sending Charset Accepted SubReq");
+
+    g_object_get(self->priv->telnet, "connection", &conn, NULL);
+
+    /* Writes IAC SB CHARSET ACCEPTED <charset> IAC SE to server */
+    byte = (guchar)TEL_IAC;
+
+    gnet_conn_write(conn, (gchar *)&byte, 1);
+    byte = (guchar)TEL_SB;
+    gnet_conn_write(conn, (gchar *)&byte, 1);
+    byte = (guchar)TELOPT_CHARSET;
+    gnet_conn_write(conn, (gchar *)&byte, 1);
+    byte = (guchar)TEL_CHARSET_ACCEPT;
+    gnet_conn_write(conn, (gchar *)&byte, 1);
+
+    for (i = 0; i < strlen(encoding); ++i)
+    {
+	byte = (guchar)encoding[i];
+	gnet_conn_write(conn, (gchar *)&byte, 1);
+
+	if (byte == (guchar)TEL_IAC)
+	    gnet_conn_write(conn, (gchar *)&byte, 1);
+    }
+
+    byte = (guchar)TEL_IAC;
+    gnet_conn_write(conn, (gchar *)&byte, 1);
+    byte = (guchar)TEL_SE;
+    gnet_conn_write(conn, (gchar *)&byte, 1);
+}
+

Added: trunk/src/handlers/mud-telnet-charset.h
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-charset.h	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,57 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-charset.h
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MUD_TELNET_CHARSET_H
+#define MUD_TELNET_CHARSET_H
+
+G_BEGIN_DECLS
+
+#include <glib.h>
+
+#define MUD_TYPE_TELNET_CHARSET              (mud_telnet_charset_get_type ())
+#define MUD_TELNET_CHARSET(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), MUD_TYPE_TELNET_CHARSET, MudTelnetCharset))
+#define MUD_TELNET_CHARSET_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), MUD_TYPE_TELNET_CHARSET, MudTelnetCharsetClass))
+#define MUD_IS_TELNET_CHARSET(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), MUD_TYPE_TELNET_CHARSET))
+#define MUD_IS_TELNET_CHARSET_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), MUD_TYPE_TELNET_CHARSET))
+#define MUD_TELNET_CHARSET_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), MUD_TYPE_TELNET_CHARSET, MudTelnetCharsetClass))
+#define MUD_TELNET_CHARSET_GET_PRIVATE(obj)  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUD_TYPE_TELNET_CHARSET, MudTelnetCharsetPrivate))
+
+typedef struct _MudTelnetCharset            MudTelnetCharset;
+typedef struct _MudTelnetCharsetClass       MudTelnetCharsetClass;
+typedef struct _MudTelnetCharsetPrivate     MudTelnetCharsetPrivate;
+
+struct _MudTelnetCharsetClass
+{
+    GObjectClass parent_class;
+};
+
+struct _MudTelnetCharset
+{
+    GObject parent_instance;
+
+    /*< private >*/
+    MudTelnetCharsetPrivate *priv;
+};
+
+GType mud_telnet_charset_get_type (void);
+
+G_END_DECLS
+
+#endif // MUD_TELNET_CHARSET_H
+

Added: trunk/src/handlers/mud-telnet-echo.c
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-echo.c	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,278 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-echo.c
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+
+#include "gnome-mud.h"
+#include "mud-telnet.h"
+#include "mud-telnet-handler-interface.h"
+#include "mud-telnet-echo.h"
+
+struct _MudTelnetEchoPrivate
+{
+    /* Interface Properties */
+    MudTelnet *telnet;
+    gboolean enabled;
+    gint option;
+
+    /* Private Instance Members */
+};
+
+/* Property Identifiers */
+enum
+{
+    PROP_MUD_TELNET_ECHO_0,
+    PROP_ENABLED,
+    PROP_HANDLES_OPTION,
+    PROP_TELNET
+};
+
+/* Class Functions */
+static void mud_telnet_echo_init (MudTelnetEcho *self);
+static void mud_telnet_echo_class_init (MudTelnetEchoClass *klass);
+static void mud_telnet_echo_interface_init(MudTelnetHandlerInterface *iface);
+static void mud_telnet_echo_finalize (GObject *object);
+static GObject *mud_telnet_echo_constructor (GType gtype,
+                                             guint n_properties,
+                                             GObjectConstructParam *properties);
+static void mud_telnet_echo_set_property(GObject *object,
+                                         guint prop_id,
+                                         const GValue *value,
+                                         GParamSpec *pspec);
+static void mud_telnet_echo_get_property(GObject *object,
+                                         guint prop_id,
+                                         GValue *value,
+                                         GParamSpec *pspec);
+
+/*Interface Implementation */
+void mud_telnet_echo_enable(MudTelnetHandler *self);
+void mud_telnet_echo_disable(MudTelnetHandler *self);
+void mud_telnet_echo_handle_sub_neg(MudTelnetHandler *self,
+                                    guchar *buf,
+                                    guint len);
+
+/* Create the Type. We implement MudTelnetHandlerInterface */
+G_DEFINE_TYPE_WITH_CODE(MudTelnetEcho, mud_telnet_echo, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (MUD_TELNET_HANDLER_TYPE,
+                                               mud_telnet_echo_interface_init));
+/* MudTelnetEcho class functions */
+static void
+mud_telnet_echo_class_init (MudTelnetEchoClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    /* Override base object constructor */
+    object_class->constructor = mud_telnet_echo_constructor;
+
+    /* Override base object's finalize */
+    object_class->finalize = mud_telnet_echo_finalize;
+
+    /* Override base object property methods */
+    object_class->set_property = mud_telnet_echo_set_property;
+    object_class->get_property = mud_telnet_echo_get_property;
+
+    /* Add private data to class */
+    g_type_class_add_private(klass, sizeof(MudTelnetEchoPrivate));
+
+    /* Override Implementation Properties */
+    g_object_class_override_property(object_class,
+                                     PROP_ENABLED,
+                                     "enabled");
+
+    g_object_class_override_property(object_class,
+                                     PROP_HANDLES_OPTION,
+                                     "handles-option");
+
+    g_object_class_override_property(object_class,
+                                     PROP_TELNET,
+                                     "telnet");
+}
+
+static void
+mud_telnet_echo_interface_init(MudTelnetHandlerInterface *iface)
+{
+    iface->Enable = mud_telnet_echo_enable;
+    iface->Disable = mud_telnet_echo_disable;
+    iface->HandleSubNeg = mud_telnet_echo_handle_sub_neg;
+}
+
+static void
+mud_telnet_echo_init (MudTelnetEcho *self)
+{
+    /* Get our private data */
+    self->priv = MUD_TELNET_ECHO_GET_PRIVATE(self);
+
+    /* Set the defaults */
+    self->priv->telnet = NULL;
+    self->priv->option = TELOPT_ECHO;
+    self->priv->enabled = FALSE;
+}
+
+static GObject *
+mud_telnet_echo_constructor (GType gtype,
+                              guint n_properties,
+                              GObjectConstructParam *properties)
+{
+    MudTelnetEcho *self;
+    GObject *obj;
+    MudTelnetEchoClass *klass;
+    GObjectClass *parent_class;
+
+    /* Chain up to parent constructor */
+    klass = MUD_TELNET_ECHO_CLASS( g_type_class_peek(MUD_TYPE_TELNET_ECHO) );
+    parent_class = G_OBJECT_CLASS( g_type_class_peek_parent(klass) );
+    obj = parent_class->constructor(gtype, n_properties, properties);
+
+    self = MUD_TELNET_ECHO(obj);
+
+    if(!self->priv->telnet)
+    {
+        g_printf("ERROR: Tried to instantiate MudTelnetEcho without passing parent MudTelnet\n");
+        g_error("Tried to instantiate MudTelnetEcho without passing parent MudTelnet");
+    }
+
+    return obj;
+}
+
+static void
+mud_telnet_echo_finalize (GObject *object)
+{
+    MudTelnetEcho *self;
+    GObjectClass *parent_class;
+
+    self = MUD_TELNET_ECHO(object);
+
+    parent_class = g_type_class_peek_parent(G_OBJECT_GET_CLASS(object));
+    parent_class->finalize(object);
+}
+
+static void
+mud_telnet_echo_set_property(GObject *object,
+                              guint prop_id,
+                              const GValue *value,
+                              GParamSpec *pspec)
+{
+    MudTelnetEcho *self;
+
+    self = MUD_TELNET_ECHO(object);
+
+    switch(prop_id)
+    {
+        case PROP_TELNET:
+            self->priv->telnet = MUD_TELNET(g_value_get_object(value));
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+static void
+mud_telnet_echo_get_property(GObject *object,
+                              guint prop_id,
+                              GValue *value,
+                              GParamSpec *pspec)
+{
+    MudTelnetEcho *self;
+
+    self = MUD_TELNET_ECHO(object);
+
+    switch(prop_id)
+    {
+        case PROP_ENABLED:
+            g_value_set_boolean(value, self->priv->enabled);
+            break;
+
+        case PROP_HANDLES_OPTION:
+            g_value_set_int(value, self->priv->option);
+            break;
+
+        case PROP_TELNET:
+            g_value_take_object(value, self->priv->telnet);
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+/* Interface Implementation */
+void 
+mud_telnet_echo_enable(MudTelnetHandler *handler)
+{
+    MudTelnetEcho *self;
+    MudConnectionView *view;
+
+    self = MUD_TELNET_ECHO(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_ECHO(self));
+
+    self->priv->enabled = TRUE;
+
+    g_object_get(self->priv->telnet, "parent-view", &view, NULL);
+    g_object_set(view,
+                 "local-echo", FALSE,
+                 NULL);
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "ECHO Enabled");
+}
+
+void
+mud_telnet_echo_disable(MudTelnetHandler *handler)
+{
+    MudTelnetEcho *self;
+    MudConnectionView *view;
+
+    self = MUD_TELNET_ECHO(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_ECHO(self));
+
+    self->priv->enabled = FALSE;
+
+    g_object_get(self->priv->telnet, "parent-view", &view, NULL);
+    g_object_set(view,
+                 "local-echo", TRUE,
+                 NULL);
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "ECHO Disabled");
+}
+
+void
+mud_telnet_echo_handle_sub_neg(MudTelnetHandler *handler,
+                               guchar *buf,
+                               guint len)
+{
+    MudTelnetEcho *self;
+
+    self = MUD_TELNET_ECHO(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_ECHO(self));
+
+    /* There is no ECHO subreq.*/
+    return;
+}
+

Added: trunk/src/handlers/mud-telnet-echo.h
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-echo.h	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,57 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-echo.h
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MUD_TELNET_ECHO_H
+#define MUD_TELNET_ECHO_H
+
+G_BEGIN_DECLS
+
+#include <glib.h>
+
+#define MUD_TYPE_TELNET_ECHO              (mud_telnet_echo_get_type ())
+#define MUD_TELNET_ECHO(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), MUD_TYPE_TELNET_ECHO, MudTelnetEcho))
+#define MUD_TELNET_ECHO_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), MUD_TYPE_TELNET_ECHO, MudTelnetEchoClass))
+#define MUD_IS_TELNET_ECHO(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), MUD_TYPE_TELNET_ECHO))
+#define MUD_IS_TELNET_ECHO_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), MUD_TYPE_TELNET_ECHO))
+#define MUD_TELNET_ECHO_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), MUD_TYPE_TELNET_ECHO, MudTelnetEchoClass))
+#define MUD_TELNET_ECHO_GET_PRIVATE(obj)  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUD_TYPE_TELNET_ECHO, MudTelnetEchoPrivate))
+
+typedef struct _MudTelnetEcho            MudTelnetEcho;
+typedef struct _MudTelnetEchoClass       MudTelnetEchoClass;
+typedef struct _MudTelnetEchoPrivate     MudTelnetEchoPrivate;
+
+struct _MudTelnetEchoClass
+{
+    GObjectClass parent_class;
+};
+
+struct _MudTelnetEcho
+{
+    GObject parent_instance;
+
+    /*< private >*/
+    MudTelnetEchoPrivate *priv;
+};
+
+GType mud_telnet_echo_get_type (void);
+
+G_END_DECLS
+
+#endif // MUD_TELNET_ECHO_H
+

Added: trunk/src/handlers/mud-telnet-eor.c
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-eor.c	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,266 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-eor.c
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+
+#include "gnome-mud.h"
+#include "mud-telnet.h"
+#include "mud-telnet-handler-interface.h"
+#include "mud-telnet-eor.h"
+
+struct _MudTelnetEorPrivate
+{
+    /* Interface Properties */
+    MudTelnet *telnet;
+    gboolean enabled;
+    gint option;
+
+    /* Private Instance Members */
+};
+
+/* Property Identifiers */
+enum
+{
+    PROP_MUD_TELNET_EOR_0,
+    PROP_ENABLED,
+    PROP_HANDLES_OPTION,
+    PROP_TELNET
+};
+
+/* Class Functions */
+static void mud_telnet_eor_init (MudTelnetEor *self);
+static void mud_telnet_eor_class_init (MudTelnetEorClass *klass);
+static void mud_telnet_eor_interface_init(MudTelnetHandlerInterface *iface);
+static void mud_telnet_eor_finalize (GObject *object);
+static GObject *mud_telnet_eor_constructor (GType gtype,
+                                             guint n_properties,
+                                             GObjectConstructParam *properties);
+static void mud_telnet_eor_set_property(GObject *object,
+                                         guint prop_id,
+                                         const GValue *value,
+                                         GParamSpec *pspec);
+static void mud_telnet_eor_get_property(GObject *object,
+                                         guint prop_id,
+                                         GValue *value,
+                                         GParamSpec *pspec);
+
+/*Interface Implementation */
+void mud_telnet_eor_enable(MudTelnetHandler *self);
+void mud_telnet_eor_disable(MudTelnetHandler *self);
+void mud_telnet_eor_handle_sub_neg(MudTelnetHandler *self,
+                                    guchar *buf,
+                                    guint len);
+
+/* Create the Type. We implement MudTelnetHandlerInterface */
+G_DEFINE_TYPE_WITH_CODE(MudTelnetEor, mud_telnet_eor, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (MUD_TELNET_HANDLER_TYPE,
+                                               mud_telnet_eor_interface_init));
+/* MudTelnetEor class functions */
+static void
+mud_telnet_eor_class_init (MudTelnetEorClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    /* Override base object constructor */
+    object_class->constructor = mud_telnet_eor_constructor;
+
+    /* Override base object's finalize */
+    object_class->finalize = mud_telnet_eor_finalize;
+
+    /* Override base object property methods */
+    object_class->set_property = mud_telnet_eor_set_property;
+    object_class->get_property = mud_telnet_eor_get_property;
+
+    /* Add private data to class */
+    g_type_class_add_private(klass, sizeof(MudTelnetEorPrivate));
+
+    /* Override Implementation Properties */
+    g_object_class_override_property(object_class,
+                                     PROP_ENABLED,
+                                     "enabled");
+
+    g_object_class_override_property(object_class,
+                                     PROP_HANDLES_OPTION,
+                                     "handles-option");
+
+    g_object_class_override_property(object_class,
+                                     PROP_TELNET,
+                                     "telnet");
+}
+
+static void
+mud_telnet_eor_interface_init(MudTelnetHandlerInterface *iface)
+{
+    iface->Enable = mud_telnet_eor_enable;
+    iface->Disable = mud_telnet_eor_disable;
+    iface->HandleSubNeg = mud_telnet_eor_handle_sub_neg;
+}
+
+static void
+mud_telnet_eor_init (MudTelnetEor *self)
+{
+    /* Get our private data */
+    self->priv = MUD_TELNET_EOR_GET_PRIVATE(self);
+
+    /* Set the defaults */
+    self->priv->telnet = NULL;
+    self->priv->option = TELOPT_EOR;
+    self->priv->enabled = FALSE;
+}
+
+static GObject *
+mud_telnet_eor_constructor (GType gtype,
+                              guint n_properties,
+                              GObjectConstructParam *properties)
+{
+    MudTelnetEor *self;
+    GObject *obj;
+    MudTelnetEorClass *klass;
+    GObjectClass *parent_class;
+
+    /* Chain up to parent constructor */
+    klass = MUD_TELNET_EOR_CLASS( g_type_class_peek(MUD_TYPE_TELNET_EOR) );
+    parent_class = G_OBJECT_CLASS( g_type_class_peek_parent(klass) );
+    obj = parent_class->constructor(gtype, n_properties, properties);
+
+    self = MUD_TELNET_EOR(obj);
+
+    if(!self->priv->telnet)
+    {
+        g_printf("ERROR: Tried to instantiate MudTelnetEor without passing parent MudTelnet\n");
+        g_error("Tried to instantiate MudTelnetEor without passing parent MudTelnet");
+    }
+
+    return obj;
+}
+
+static void
+mud_telnet_eor_finalize (GObject *object)
+{
+    MudTelnetEor *self;
+    GObjectClass *parent_class;
+
+    self = MUD_TELNET_EOR(object);
+
+    parent_class = g_type_class_peek_parent(G_OBJECT_GET_CLASS(object));
+    parent_class->finalize(object);
+}
+
+static void
+mud_telnet_eor_set_property(GObject *object,
+                              guint prop_id,
+                              const GValue *value,
+                              GParamSpec *pspec)
+{
+    MudTelnetEor *self;
+
+    self = MUD_TELNET_EOR(object);
+
+    switch(prop_id)
+    {
+        case PROP_TELNET:
+            self->priv->telnet = MUD_TELNET(g_value_get_object(value));
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+static void
+mud_telnet_eor_get_property(GObject *object,
+                              guint prop_id,
+                              GValue *value,
+                              GParamSpec *pspec)
+{
+    MudTelnetEor *self;
+
+    self = MUD_TELNET_EOR(object);
+
+    switch(prop_id)
+    {
+        case PROP_ENABLED:
+            g_value_set_boolean(value, self->priv->enabled);
+            break;
+
+        case PROP_HANDLES_OPTION:
+            g_value_set_int(value, self->priv->option);
+            break;
+
+        case PROP_TELNET:
+            g_value_take_object(value, self->priv->telnet);
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+/* Interface Implementation */
+void 
+mud_telnet_eor_enable(MudTelnetHandler *handler)
+{
+    MudTelnetEor *self;
+
+    self = MUD_TELNET_EOR(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_EOR(self));
+
+    self->priv->enabled = TRUE;
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "EOR Enabled");
+}
+
+void
+mud_telnet_eor_disable(MudTelnetHandler *handler)
+{
+    MudTelnetEor *self;
+
+    self = MUD_TELNET_EOR(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_EOR(self));
+
+    self->priv->enabled = FALSE;
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "EOR Disabled");
+}
+
+void
+mud_telnet_eor_handle_sub_neg(MudTelnetHandler *handler,
+                               guchar *buf,
+                               guint len)
+{
+    MudTelnetEor *self;
+
+    self = MUD_TELNET_EOR(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_EOR(self));
+
+    /* There is no EOR subreq.*/
+    return;
+}
+

Added: trunk/src/handlers/mud-telnet-eor.h
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-eor.h	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,57 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-eor.h
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MUD_TELNET_EOR_H
+#define MUD_TELNET_EOR_H
+
+G_BEGIN_DECLS
+
+#include <glib.h>
+
+#define MUD_TYPE_TELNET_EOR              (mud_telnet_eor_get_type ())
+#define MUD_TELNET_EOR(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), MUD_TYPE_TELNET_EOR, MudTelnetEor))
+#define MUD_TELNET_EOR_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), MUD_TYPE_TELNET_EOR, MudTelnetEorClass))
+#define MUD_IS_TELNET_EOR(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), MUD_TYPE_TELNET_EOR))
+#define MUD_IS_TELNET_EOR_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), MUD_TYPE_TELNET_EOR))
+#define MUD_TELNET_EOR_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), MUD_TYPE_TELNET_EOR, MudTelnetEorClass))
+#define MUD_TELNET_EOR_GET_PRIVATE(obj)  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUD_TYPE_TELNET_EOR, MudTelnetEorPrivate))
+
+typedef struct _MudTelnetEor            MudTelnetEor;
+typedef struct _MudTelnetEorClass       MudTelnetEorClass;
+typedef struct _MudTelnetEorPrivate     MudTelnetEorPrivate;
+
+struct _MudTelnetEorClass
+{
+    GObjectClass parent_class;
+};
+
+struct _MudTelnetEor
+{
+    GObject parent_instance;
+
+    /*< private >*/
+    MudTelnetEorPrivate *priv;
+};
+
+GType mud_telnet_eor_get_type (void);
+
+G_END_DECLS
+
+#endif // MUD_TELNET_EOR_H
+

Added: trunk/src/handlers/mud-telnet-handler-interface.c
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-handler-interface.c	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,119 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-handler-interface.c
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "mud-telnet-handler-interface.h"
+#include "mud-telnet.h"
+
+/* Interface Prototypes */
+static void mud_telnet_handler_base_init (gpointer klass);
+
+/* Define the Dummy Type */
+GType
+mud_telnet_handler_get_type (void)
+{
+    static GType mud_telnet_handler_iface_type = 0;
+
+    if(mud_telnet_handler_iface_type == 0)
+    {
+        static const GTypeInfo info =
+        {
+            sizeof (MudTelnetHandlerInterface),
+            mud_telnet_handler_base_init, /* base_init */
+            NULL                          /* base_finalize */
+        };
+
+        mud_telnet_handler_iface_type =
+            g_type_register_static(G_TYPE_INTERFACE,
+                                   "MudTelnetHandler",
+                                   &info,
+                                   0);
+    }
+
+    return mud_telnet_handler_iface_type;
+}
+
+/* Interface Functions */
+static void
+mud_telnet_handler_base_init(gpointer klass)
+{
+    static gboolean initialized = FALSE;
+
+    if(!initialized)
+    {
+        g_object_interface_install_property(klass,
+                                            g_param_spec_boolean(
+                                                "enabled",
+                                                "Enabled",
+                                                "Is handler enabled",
+                                                FALSE,
+                                                G_PARAM_READABLE));
+
+        g_object_interface_install_property(klass,
+                                            g_param_spec_int(
+                                                "handles-option",
+                                                "Handles Option",
+                                                "The TelOpt Number it handles",
+                                                -1, 50000,-1,
+                                                G_PARAM_READABLE));
+
+        g_object_interface_install_property(klass,
+                                            g_param_spec_object(
+                                                "telnet",
+                                                "Telnet",
+                                                "The parent telnet object",
+                                                MUD_TYPE_TELNET,
+                                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+        initialized = TRUE;
+    }
+}
+
+/* Interface Methods */
+void
+mud_telnet_handler_enable(MudTelnetHandler *self)
+{
+    g_return_if_fail(MUD_IS_TELNET_HANDLER(self));
+
+    MUD_TELNET_HANDLER_GET_INTERFACE (self)->Enable(self);
+}
+
+void
+mud_telnet_handler_disable(MudTelnetHandler *self)
+{
+    g_return_if_fail(MUD_IS_TELNET_HANDLER(self));
+
+    MUD_TELNET_HANDLER_GET_INTERFACE(self)->Disable(self);
+}
+
+void
+mud_telnet_handler_handle_sub_neg(MudTelnetHandler *self,
+                                  guchar *buf,
+                                  guint len)
+{
+    g_return_if_fail(MUD_IS_TELNET_HANDLER(self));
+
+    MUD_TELNET_HANDLER_GET_INTERFACE (self)->HandleSubNeg (self, buf, len);
+}
+

Added: trunk/src/handlers/mud-telnet-handler-interface.h
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-handler-interface.h	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,69 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-handler-interface.h
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MUD_TELNET_HANDLER_INTERFACE_H
+#define MUD_TELNET_HANDLER_INTERFACE_H
+
+G_BEGIN_DECLS
+
+#define MUD_TELNET_HANDLER_TYPE                (mud_telnet_handler_get_type ())
+#define MUD_TELNET_HANDLER(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), MUD_TELNET_HANDLER_TYPE, MudTelnetHandler))
+#define MUD_IS_TELNET_HANDLER(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MUD_TELNET_HANDLER_TYPE))
+#define MUD_TELNET_HANDLER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), MUD_TELNET_HANDLER_TYPE, MudTelnetHandlerInterface))
+
+typedef struct _MudTelnetHandler MudTelnetHandler; // Dummy object
+typedef struct _MudTelnetHandlerInterface MudTelnetHandlerInterface;
+
+#include <glib.h>
+#include "mud-telnet.h"
+
+struct _MudTelnetHandlerInterface
+{
+    GTypeInterface parent;
+
+    /* Interface Methods */
+    void (*Enable)      (MudTelnetHandler *self);
+    void (*Disable)     (MudTelnetHandler *self);
+    void (*HandleSubNeg)(MudTelnetHandler *self,
+                         guchar *buf,
+                         guint len);
+
+};
+
+GType mud_telnet_handler_get_type (void);
+
+/* Typedefs for Casting */
+typedef void (*MudTelnetHandlerEnableFunc)(MudTelnetHandler *self);
+typedef void (*MudTelnetHandlerDisableFunc)(MudTelnetHandler *self);
+typedef void (*MudTelnetHandlerHandleSubNeg)(MudTelnetHandler *self,
+                                            guchar *buf,
+                                            guint len);
+
+/* Interface Method Prototypes */
+
+void mud_telnet_handler_enable(MudTelnetHandler *self);
+void mud_telnet_handler_disable(MudTelnetHandler *self);
+void mud_telnet_handler_handle_sub_neg(MudTelnetHandler *self,
+                                       guchar *buf,
+                                       guint len);
+
+G_END_DECLS
+
+#endif // MUD_TELNET_HANDLER_INTERFACE_H
+

Added: trunk/src/handlers/mud-telnet-handlers.h
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-handlers.h	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,51 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-handlers.h
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MUD_TELNET_HANDLERS_H
+#define MUD_TELNET_HANDLERS_H
+
+G_BEGIN_DECLS
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mud-telnet-handler-interface.h"
+#include "mud-telnet-charset.h"
+#include "mud-telnet-echo.h"
+#include "mud-telnet-eor.h"
+
+#ifdef ENABLE_MCCP
+#include "mud-telnet-mccp.h"
+#endif
+
+#ifdef ENABLE_GST
+#include "mud-telnet-msp.h"
+#endif
+
+#include "mud-telnet-mssp.h"
+#include "mud-telnet-naws.h"
+#include "mud-telnet-new-environ.h"
+#include "mud-telnet-ttype.h"
+#include "mud-telnet-zmp.h"
+
+G_END_DECLS
+
+#endif // MUD_TELNET_HANDLERS_H
+

Added: trunk/src/handlers/mud-telnet-mccp.c
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-mccp.c	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,442 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-mccp.c
+ * Copyright (C) 2008-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#ifdef ENABLE_MCCP
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <zlib.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gnome-mud.h"
+#include "mud-connection-view.h"
+#include "mud-telnet.h"
+#include "mud-telnet-handler-interface.h"
+#include "mud-telnet-mccp.h"
+
+struct _MudTelnetMccpPrivate
+{
+    /* Interface Properties */
+    MudTelnet *telnet;
+    gboolean enabled;
+    gint option;
+
+    /* Private Instance Members */
+    z_stream *compress_out;
+    guchar *compress_out_buf;
+    gboolean mccp_new;
+    gboolean mccp;
+};
+
+/* Property Identifiers */
+enum
+{
+    PROP_MUD_TELNET_MCCP_0,
+    PROP_ENABLED,
+    PROP_HANDLES_OPTION,
+    PROP_TELNET,
+    PROP_MCCP_NEW,
+    PROP_MCCP
+};
+
+/* Class Functions */
+static void mud_telnet_mccp_init (MudTelnetMccp *self);
+static void mud_telnet_mccp_class_init (MudTelnetMccpClass *klass);
+static void mud_telnet_mccp_interface_init(MudTelnetHandlerInterface *iface);
+static void mud_telnet_mccp_finalize (GObject *object);
+static GObject *mud_telnet_mccp_constructor (GType gtype,
+                                             guint n_properties,
+                                             GObjectConstructParam *properties);
+static void mud_telnet_mccp_set_property(GObject *object,
+                                         guint prop_id,
+                                         const GValue *value,
+                                         GParamSpec *pspec);
+static void mud_telnet_mccp_get_property(GObject *object,
+                                         guint prop_id,
+                                         GValue *value,
+                                         GParamSpec *pspec);
+
+/*Interface Implementation */
+void mud_telnet_mccp_enable(MudTelnetHandler *self);
+void mud_telnet_mccp_disable(MudTelnetHandler *self);
+void mud_telnet_mccp_handle_sub_neg(MudTelnetHandler *self,
+                                    guchar *buf,
+                                    guint len);
+
+/* Create the Type. We implement MudTelnetHandlerInterface */
+G_DEFINE_TYPE_WITH_CODE(MudTelnetMccp, mud_telnet_mccp, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (MUD_TELNET_HANDLER_TYPE,
+                                               mud_telnet_mccp_interface_init));
+/* MudTelnetMccp class functions */
+static void
+mud_telnet_mccp_class_init (MudTelnetMccpClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    /* Override base object constructor */
+    object_class->constructor = mud_telnet_mccp_constructor;
+
+    /* Override base object's finalize */
+    object_class->finalize = mud_telnet_mccp_finalize;
+
+    /* Override base object property methods */
+    object_class->set_property = mud_telnet_mccp_set_property;
+    object_class->get_property = mud_telnet_mccp_get_property;
+
+    /* Add private data to class */
+    g_type_class_add_private(klass, sizeof(MudTelnetMccpPrivate));
+
+    /* Override Implementation Properties */
+    g_object_class_override_property(object_class,
+                                     PROP_ENABLED,
+                                     "enabled");
+
+    g_object_class_override_property(object_class,
+                                     PROP_HANDLES_OPTION,
+                                     "handles-option");
+
+    g_object_class_override_property(object_class,
+                                     PROP_TELNET,
+                                     "telnet");
+
+    g_object_class_install_property(object_class,
+                            PROP_MCCP_NEW,
+                            g_param_spec_boolean("mccp-new",
+                                "MCCP New",
+                                "Is MCCP newly enabled.",
+                                FALSE,
+                                G_PARAM_READWRITE));
+
+    g_object_class_install_property(object_class,
+                            PROP_MCCP,
+                            g_param_spec_boolean("mccp-active",
+                                "MCCP Active",
+                                "Is MCCP Active.",
+                                FALSE,
+                                G_PARAM_READABLE));
+}
+
+static void
+mud_telnet_mccp_interface_init(MudTelnetHandlerInterface *iface)
+{
+    iface->Enable = mud_telnet_mccp_enable;
+    iface->Disable = mud_telnet_mccp_disable;
+    iface->HandleSubNeg = mud_telnet_mccp_handle_sub_neg;
+}
+
+static void
+mud_telnet_mccp_init (MudTelnetMccp *self)
+{
+    /* Get our private data */
+    self->priv = MUD_TELNET_MCCP_GET_PRIVATE(self);
+
+    /* Set the defaults */
+    self->priv->telnet = NULL;
+    self->priv->option = TELOPT_MCCP2;
+    self->priv->enabled = FALSE;
+
+    self->priv->mccp_new = TRUE;
+    self->priv->mccp = FALSE;
+}
+
+static GObject *
+mud_telnet_mccp_constructor (GType gtype,
+                              guint n_properties,
+                              GObjectConstructParam *properties)
+{
+    MudTelnetMccp *self;
+    GObject *obj;
+    MudTelnetMccpClass *klass;
+    GObjectClass *parent_class;
+
+    /* Chain up to parent constructor */
+    klass = MUD_TELNET_MCCP_CLASS( g_type_class_peek(MUD_TYPE_TELNET_MCCP) );
+    parent_class = G_OBJECT_CLASS( g_type_class_peek_parent(klass) );
+    obj = parent_class->constructor(gtype, n_properties, properties);
+
+    self = MUD_TELNET_MCCP(obj);
+
+    if(!self->priv->telnet)
+    {
+        g_printf("ERROR: Tried to instantiate MudTelnetMccp without passing parent MudTelnet\n");
+        g_error("Tried to instantiate MudTelnetMccp without passing parent MudTelnet");
+    }
+
+    return obj;
+}
+
+static void
+mud_telnet_mccp_finalize (GObject *object)
+{
+    MudTelnetMccp *self;
+    GObjectClass *parent_class;
+
+    self = MUD_TELNET_MCCP(object);
+
+    if(self->priv->compress_out != NULL)
+    {
+        inflateEnd(self->priv->compress_out);
+
+        g_free(self->priv->compress_out);
+        g_free(self->priv->compress_out_buf);
+    }
+
+    parent_class = g_type_class_peek_parent(G_OBJECT_GET_CLASS(object));
+    parent_class->finalize(object);
+}
+
+static void
+mud_telnet_mccp_set_property(GObject *object,
+                              guint prop_id,
+                              const GValue *value,
+                              GParamSpec *pspec)
+{
+    MudTelnetMccp *self;
+
+    self = MUD_TELNET_MCCP(object);
+
+    switch(prop_id)
+    {
+        case PROP_TELNET:
+            self->priv->telnet = MUD_TELNET(g_value_get_object(value));
+            break;
+
+        case PROP_MCCP_NEW:
+            self->priv->mccp_new = g_value_get_boolean(value);
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+static void
+mud_telnet_mccp_get_property(GObject *object,
+                              guint prop_id,
+                              GValue *value,
+                              GParamSpec *pspec)
+{
+    MudTelnetMccp *self;
+
+    self = MUD_TELNET_MCCP(object);
+
+    switch(prop_id)
+    {
+        case PROP_ENABLED:
+            g_value_set_boolean(value, self->priv->enabled);
+            break;
+
+        case PROP_HANDLES_OPTION:
+            g_value_set_int(value, self->priv->option);
+            break;
+
+        case PROP_TELNET:
+            g_value_take_object(value, self->priv->telnet);
+            break;
+
+        case PROP_MCCP_NEW:
+            g_value_set_boolean(value, self->priv->mccp_new);
+            break;
+
+        case PROP_MCCP:
+            g_value_set_boolean(value, self->priv->mccp);
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+/* Interface Implementation */
+void 
+mud_telnet_mccp_enable(MudTelnetHandler *handler)
+{
+    MudTelnetMccp *self;
+
+    self = MUD_TELNET_MCCP(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_MCCP(self));
+
+    self->priv->enabled = TRUE;
+    self->priv->mccp = FALSE;
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "MCCP Requested");
+}
+
+void
+mud_telnet_mccp_disable(MudTelnetHandler *handler)
+{
+    MudTelnetMccp *self;
+
+    self = MUD_TELNET_MCCP(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_MCCP(self));
+
+    self->priv->enabled = FALSE;
+    self->priv->mccp = FALSE;
+
+    if (self->priv->compress_out != NULL)
+    {
+        inflateEnd(self->priv->compress_out);
+
+        g_free(self->priv->compress_out);
+        g_free(self->priv->compress_out_buf);
+        
+        self->priv->compress_out = NULL;
+    }
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "MCCP Disabled");
+}
+
+void
+mud_telnet_mccp_handle_sub_neg(MudTelnetHandler *handler,
+                               guchar *buf,
+                               guint len)
+{
+    MudTelnetMccp *self;
+
+    self = MUD_TELNET_MCCP(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_MCCP(self));
+
+    self->priv->mccp_new = TRUE;
+    self->priv->mccp = TRUE;
+
+    self->priv->compress_out = g_new0(z_stream, 1);
+    self->priv->compress_out_buf = g_new0(guchar, 4096);
+
+    self->priv->compress_out->next_out = self->priv->compress_out_buf;
+    self->priv->compress_out->avail_out = 4096;
+
+    if(inflateInit(self->priv->compress_out) != Z_OK)
+    {
+        MudConnectionView *view;
+        g_object_get(self->priv->telnet, "parent-view", &view, NULL);
+
+        g_printf("failed to init compression\n");
+        g_critical("Failed to initialize compression.");
+
+        g_free(self->priv->compress_out);
+        g_free(self->priv->compress_out_buf);
+
+        self->priv->compress_out = NULL;
+        self->priv->compress_out_buf = NULL;
+
+        mud_connection_view_disconnect(view);
+    }
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "MCCP Enabled.");
+}
+
+/* Public Methods */
+GString *
+mud_mccp_decompress(MudTelnetMccp *self, guchar *buffer, guint32 length)
+{
+    GString *ret = NULL;
+    gint zstatus;
+    gint i;
+    MudConnectionView *view;
+
+    g_return_if_fail(MUD_IS_TELNET_MCCP(self));
+
+    if(!self->priv->compress_out)
+        return NULL;
+
+    g_object_get(self->priv->telnet, "parent-view", &view, NULL);
+
+    self->priv->compress_out->next_in = buffer;
+    self->priv->compress_out->avail_in = length;
+
+    ret = g_string_new(NULL);
+
+    while(1)
+    {
+        if(self->priv->compress_out->avail_in < 1)
+            break;
+
+        self->priv->compress_out->avail_out = 4096;
+        self->priv->compress_out->next_out = self->priv->compress_out_buf;
+
+        /* Inflating */
+        zstatus = inflate(self->priv->compress_out, Z_SYNC_FLUSH);
+
+        if(zstatus == Z_OK)
+        {
+            ret = g_string_append_len(ret, 
+                    self->priv->compress_out_buf, 
+                    (4096 - self->priv->compress_out->avail_out));
+
+            continue;
+        }
+
+        if(zstatus == Z_STREAM_END)
+        {
+            ret = g_string_append_len(ret, 
+                    self->priv->compress_out_buf, 
+                    (4096 - self->priv->compress_out->avail_out));
+
+            if(self->priv->compress_out->avail_in > 0)
+                ret = g_string_append_len(ret, 
+                        self->priv->compress_out->next_in, 
+                        self->priv->compress_out->avail_in);
+
+            inflateEnd(self->priv->compress_out);
+
+            g_free(self->priv->compress_out);
+            g_free(self->priv->compress_out_buf);
+
+            self->priv->compress_out = NULL;
+            self->priv->compress_out_buf = NULL;
+
+            self->priv->mccp = FALSE;
+            self->priv->mccp_new = TRUE;
+
+            break;
+        }
+
+        if(zstatus == Z_BUF_ERROR)
+        {
+            break;
+        }
+
+        if(zstatus == Z_DATA_ERROR)
+        {
+            mud_connection_view_add_text(view,
+                    _("\nMCCP data corrupted. Aborting connection.\n"),
+                    Error);
+            mud_connection_view_disconnect (view);
+
+            g_printf("Z DATA ERROR!\n");
+
+            return NULL; 
+        }
+    }
+
+    return ret;
+}
+
+#endif // ENABLE_MCCP
+

Added: trunk/src/handlers/mud-telnet-mccp.h
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-mccp.h	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,66 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-mccp.h
+ * Copyright (C) 2008-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MUD_TELNET_MCCP_H
+#define MUD_TELNET_MCCP_H
+
+#ifdef ENABLE_MCCP
+
+G_BEGIN_DECLS
+
+#include <glib.h>
+#include <zlib.h>
+
+#define MUD_TYPE_TELNET_MCCP              (mud_telnet_mccp_get_type ())
+#define MUD_TELNET_MCCP(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), MUD_TYPE_TELNET_MCCP, MudTelnetMccp))
+#define MUD_TELNET_MCCP_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), MUD_TYPE_TELNET_MCCP, MudTelnetMccpClass))
+#define MUD_IS_TELNET_MCCP(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), MUD_TYPE_TELNET_MCCP))
+#define MUD_IS_TELNET_MCCP_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), MUD_TYPE_TELNET_MCCP))
+#define MUD_TELNET_MCCP_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), MUD_TYPE_TELNET_MCCP, MudTelnetMccpClass))
+#define MUD_TELNET_MCCP_GET_PRIVATE(obj)  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUD_TYPE_TELNET_MCCP, MudTelnetMccpPrivate))
+
+typedef struct _MudTelnetMccp            MudTelnetMccp;
+typedef struct _MudTelnetMccpClass       MudTelnetMccpClass;
+typedef struct _MudTelnetMccpPrivate     MudTelnetMccpPrivate;
+
+typedef struct z_stream_s z_stream;
+
+struct _MudTelnetMccpClass
+{
+    GObjectClass parent_class;
+};
+
+struct _MudTelnetMccp
+{
+    GObject parent_instance;
+
+    /*< private >*/
+    MudTelnetMccpPrivate *priv;
+};
+
+GType mud_telnet_mccp_get_type (void);
+
+GString *mud_mccp_decompress(MudTelnetMccp *self, guchar *buffer, guint32 length);
+
+G_END_DECLS
+
+#endif // ENABLE_MCCP
+
+#endif // MUD_TELNET_MCCP_H
+

Added: trunk/src/handlers/mud-telnet-msp.c
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-msp.c	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,1242 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-msp.c
+ * Copyright (C) 2008-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#ifdef ENABLE_GST
+
+#include <glib.h>
+#include <gnet.h>
+#include <string.h>
+#include <gst/gst.h>
+#include <ctype.h>
+
+#include "gnome-mud.h"
+#include "mud-telnet.h"
+#include "mud-telnet-handler-interface.h"
+#include "mud-telnet-msp.h"
+
+struct _MudTelnetMspPrivate
+{
+    /* Interface Properties */
+    MudTelnet *telnet;
+    gboolean enabled;
+    gint option;
+
+    /* Private Instance Members */
+    MudMSPParser msp_parser;
+    MudMSPTypes msp_type;
+    MudMSPSound sound[2];
+    gchar *base_url;
+    GString *prev_buffer;
+};
+
+/* Property Identifiers */
+enum
+{
+    PROP_MUD_TELNET_MSP_0,
+    PROP_ENABLED,
+    PROP_HANDLES_OPTION,
+    PROP_TELNET
+};
+
+/* Class Functions */
+static void mud_telnet_msp_init (MudTelnetMsp *self);
+static void mud_telnet_msp_class_init (MudTelnetMspClass *klass);
+static void mud_telnet_msp_interface_init(MudTelnetHandlerInterface *iface);
+static void mud_telnet_msp_finalize (GObject *object);
+static GObject *mud_telnet_msp_constructor (GType gtype,
+                                             guint n_properties,
+                                             GObjectConstructParam *properties);
+static void mud_telnet_msp_set_property(GObject *object,
+                                         guint prop_id,
+                                         const GValue *value,
+                                         GParamSpec *pspec);
+static void mud_telnet_msp_get_property(GObject *object,
+                                         guint prop_id,
+                                         GValue *value,
+                                         GParamSpec *pspec);
+
+/*Interface Implementation */
+void mud_telnet_msp_enable(MudTelnetHandler *self);
+void mud_telnet_msp_disable(MudTelnetHandler *self);
+void mud_telnet_msp_handle_sub_neg(MudTelnetHandler *self,
+                                    guchar *buf,
+                                    guint len);
+
+
+/* Create the Type. We implement MudTelnetHandlerInterface */
+G_DEFINE_TYPE_WITH_CODE(MudTelnetMsp, mud_telnet_msp, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (MUD_TELNET_HANDLER_TYPE,
+                                               mud_telnet_msp_interface_init));
+
+/* Private Methods */
+static void mud_telnet_msp_parser_reset(MudTelnetMsp *self);
+static void mud_telnet_msp_parser_args(MudTelnetMsp *self);
+static void mud_telnet_msp_command_free(MudMSPCommand *command);
+static gboolean mud_telnet_msp_parser_is_param_char(gchar c);
+static gboolean mud_telnet_msp_parser_switch_on_param_char(gint *state,
+        gchar *buf,
+        gint index,
+        gint len);
+static void mud_telnet_msp_process_command(MudTelnetMsp *self,
+                                           MudMSPCommand *command);
+static void mud_telnet_msp_start_playing(MudTelnetMsp *self, MudMSPTypes type);
+static gboolean mud_telnet_msp_get_files(MudTelnetMsp *self, MudMSPTypes type);
+static gboolean mud_telnet_msp_sound_bus_call (GstBus *bus,
+                                               GstMessage *msg,
+                                               gpointer data);
+static gboolean mud_telnet_msp_music_bus_call (GstBus *bus,
+                                               GstMessage *msg,
+                                               gpointer data);
+
+/* MudTelnetMsp class functions */
+static void
+mud_telnet_msp_class_init (MudTelnetMspClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    /* Override base object constructor */
+    object_class->constructor = mud_telnet_msp_constructor;
+
+    /* Override base object's finalize */
+    object_class->finalize = mud_telnet_msp_finalize;
+
+    /* Override base object property methods */
+    object_class->set_property = mud_telnet_msp_set_property;
+    object_class->get_property = mud_telnet_msp_get_property;
+
+    /* Add private data to class */
+    g_type_class_add_private(klass, sizeof(MudTelnetMspPrivate));
+
+    /* Override Implementation Properties */
+    g_object_class_override_property(object_class,
+                                     PROP_ENABLED,
+                                     "enabled");
+
+    g_object_class_override_property(object_class,
+                                     PROP_HANDLES_OPTION,
+                                     "handles-option");
+
+    g_object_class_override_property(object_class,
+                                     PROP_TELNET,
+                                     "telnet");
+}
+
+static void
+mud_telnet_msp_interface_init(MudTelnetHandlerInterface *iface)
+{
+    iface->Enable = mud_telnet_msp_enable;
+    iface->Disable = mud_telnet_msp_disable;
+    iface->HandleSubNeg = mud_telnet_msp_handle_sub_neg;
+}
+
+static void
+mud_telnet_msp_init (MudTelnetMsp *self)
+{
+    /* Get our private data */
+    self->priv = MUD_TELNET_MSP_GET_PRIVATE(self);
+
+    /* Set the defaults */
+    self->priv->telnet = NULL;
+    self->priv->option = TELOPT_MSP;
+    self->priv->enabled = FALSE;
+
+    self->priv->sound[0].files = NULL;
+    self->priv->sound[0].current_command = NULL;
+    self->priv->sound[0].playing = FALSE;
+    self->priv->sound[0].files_len = 0;
+
+    self->priv->sound[1].files = NULL;
+    self->priv->sound[1].current_command = NULL;
+    self->priv->sound[1].playing = FALSE;
+    self->priv->sound[1].files_len = 0;
+
+    self->priv->prev_buffer = NULL;
+    self->priv->base_url = NULL;
+}
+
+static GObject *
+mud_telnet_msp_constructor (GType gtype,
+                            guint n_properties,
+                            GObjectConstructParam *properties)
+{
+    MudTelnetMsp *self;
+    GObject *obj;
+    MudTelnetMspClass *klass;
+    GObjectClass *parent_class;
+
+    /* Chain up to parent constructor */
+    klass = MUD_TELNET_MSP_CLASS( g_type_class_peek(MUD_TYPE_TELNET_MSP) );
+    parent_class = G_OBJECT_CLASS( g_type_class_peek_parent(klass) );
+    obj = parent_class->constructor(gtype, n_properties, properties);
+
+    self = MUD_TELNET_MSP(obj);
+
+    if(!self->priv->telnet)
+    {
+        g_printf("ERROR: Tried to instantiate MudTelnetMsp without passing parent MudTelnet\n");
+        g_error("Tried to instantiate MudTelnetMsp without passing parent MudTelnet");
+    }
+
+    self->priv->msp_parser.enabled = FALSE;
+    self->priv->msp_parser.state = MSP_STATE_TEXT;
+    self->priv->msp_parser.lex_pos_start = 0;
+    self->priv->msp_parser.lex_pos_end = 0;
+    self->priv->msp_parser.output = NULL;
+    self->priv->msp_parser.arg_buffer = NULL;
+
+    return obj;
+}
+
+static void
+mud_telnet_msp_finalize (GObject *object)
+{
+    MudTelnetMsp *self;
+    GObjectClass *parent_class;
+
+    self = MUD_TELNET_MSP(object);
+
+    mud_telnet_msp_stop_playing(self, MSP_TYPE_SOUND);
+    mud_telnet_msp_stop_playing(self, MSP_TYPE_MUSIC);
+    
+    if(self->priv->prev_buffer)
+        g_string_free(self->priv->prev_buffer, TRUE);
+    if(self->priv->base_url)
+        g_free(self->priv->base_url);
+
+    parent_class = g_type_class_peek_parent(G_OBJECT_GET_CLASS(object));
+    parent_class->finalize(object);
+}
+
+static void
+mud_telnet_msp_set_property(GObject *object,
+                            guint prop_id,
+                            const GValue *value,
+                            GParamSpec *pspec)
+{
+    MudTelnetMsp *self;
+
+    self = MUD_TELNET_MSP(object);
+
+    switch(prop_id)
+    {
+        case PROP_TELNET:
+            self->priv->telnet = MUD_TELNET(g_value_get_object(value));
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+static void
+mud_telnet_msp_get_property(GObject *object,
+                            guint prop_id,
+                            GValue *value,
+                            GParamSpec *pspec)
+{
+    MudTelnetMsp *self;
+
+    self = MUD_TELNET_MSP(object);
+
+    switch(prop_id)
+    {
+        case PROP_ENABLED:
+            g_value_set_boolean(value, self->priv->enabled);
+            break;
+
+        case PROP_HANDLES_OPTION:
+            g_value_set_int(value, self->priv->option);
+            break;
+
+        case PROP_TELNET:
+            g_value_take_object(value, self->priv->telnet);
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+/* Interface Implementation */
+void 
+mud_telnet_msp_enable(MudTelnetHandler *handler)
+{
+    MudTelnetMsp *self;
+
+    self = MUD_TELNET_MSP(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_MSP(self));
+
+    self->priv->enabled = TRUE;
+
+    if(self->priv->msp_parser.output)
+        g_string_free(self->priv->msp_parser.output, TRUE);
+
+    if(self->priv->msp_parser.arg_buffer)
+        g_string_free(self->priv->msp_parser.arg_buffer, TRUE);
+
+    self->priv->msp_parser.enabled = TRUE;
+    self->priv->msp_parser.state = MSP_STATE_TEXT;
+    self->priv->msp_parser.lex_pos_start = 0;
+    self->priv->msp_parser.lex_pos_end = 0;
+    self->priv->msp_parser.output = g_string_new(NULL);
+    self->priv->msp_parser.arg_buffer = NULL;
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "MSP Enabled");
+}
+
+void
+mud_telnet_msp_disable(MudTelnetHandler *handler)
+{
+    MudTelnetMsp *self;
+
+    self = MUD_TELNET_MSP(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_MSP(self));
+
+    self->priv->enabled = FALSE;
+
+    mud_telnet_msp_stop_playing(self, MSP_TYPE_SOUND);
+    mud_telnet_msp_stop_playing(self, MSP_TYPE_MUSIC);
+    
+    if(self->priv->prev_buffer)
+        g_string_free(self->priv->prev_buffer, TRUE);
+    if(self->priv->base_url)
+        g_free(self->priv->base_url);
+    if(self->priv->msp_parser.output)
+        g_string_free(self->priv->msp_parser.output, TRUE);
+    if(self->priv->msp_parser.arg_buffer)
+        g_string_free(self->priv->msp_parser.arg_buffer, TRUE);
+
+    self->priv->msp_parser.enabled = FALSE;
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "MSP Disabled");
+}
+
+void
+mud_telnet_msp_handle_sub_neg(MudTelnetHandler *handler,
+                              guchar *buf,
+                              guint len)
+{
+    MudTelnetMsp *self;
+
+    self = MUD_TELNET_MSP(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_MSP(self));
+
+    /* There is no MSP subreq.*/
+    return;
+}
+
+/* Public Methods */
+void
+mud_telnet_msp_parser_clear(MudTelnetMsp *self)
+{
+    g_return_if_fail(MUD_IS_TELNET_MSP(self));
+
+    if(self->priv->msp_parser.output)
+	g_string_free(self->priv->msp_parser.output, TRUE);
+
+    self->priv->msp_parser.lex_pos_start = 0;
+    self->priv->msp_parser.lex_pos_end = 0;
+    self->priv->msp_parser.output = g_string_new(NULL);
+}
+
+GString *
+mud_telnet_msp_parse(MudTelnetMsp *self, GString *buf, gint *len)
+{
+    gint count;
+    GString *ret = NULL;
+    gchar *temp;
+
+    g_return_if_fail(MUD_IS_TELNET_MSP(self));
+
+    mud_telnet_msp_parser_reset(self);
+
+    if(self->priv->prev_buffer)
+    {
+        buf = g_string_prepend(buf, self->priv->prev_buffer->str);
+        g_string_free(self->priv->prev_buffer, TRUE);
+        self->priv->prev_buffer = NULL;
+    }
+
+    while(self->priv->msp_parser.lex_pos_start < *len)
+    {
+        switch(self->priv->msp_parser.state)
+        {
+            case MSP_STATE_TEXT:
+                if(buf->str[self->priv->msp_parser.lex_pos_start] == '!')
+                    self->priv->msp_parser.state = MSP_STATE_POSSIBLE_COMMAND;
+                else
+                {
+                    self->priv->msp_parser.output = 
+                        g_string_append_c(self->priv->msp_parser.output,
+                                buf->str[self->priv->msp_parser.lex_pos_start++]);
+                }
+                break;
+
+            case MSP_STATE_POSSIBLE_COMMAND:
+                if(self->priv->msp_parser.lex_pos_start + 1 == *len)
+                    continue;
+                else if(buf->str[self->priv->msp_parser.lex_pos_start + 1] != '!')
+                {
+                    self->priv->msp_parser.output = 
+                        g_string_append_c(self->priv->msp_parser.output,
+                                buf->str[self->priv->msp_parser.lex_pos_start++]);
+                    self->priv->msp_parser.state = MSP_STATE_TEXT;
+                    continue;
+                }
+
+                self->priv->msp_parser.state = MSP_STATE_COMMAND;
+                break;
+
+            case MSP_STATE_COMMAND:
+                if(self->priv->msp_parser.lex_pos_start + 8 >= *len)
+                {
+                    self->priv->prev_buffer = g_string_new(NULL);
+
+                    count = self->priv->msp_parser.lex_pos_start;
+
+                    while(count != buf->len)
+                        self->priv->prev_buffer = 
+                            g_string_append_c(self->priv->prev_buffer, buf->str[count++]);
+
+                    self->priv->msp_parser.lex_pos_start += count;
+                    continue;
+                }
+
+                if(buf->str[self->priv->msp_parser.lex_pos_start + 2] == 'S' &&
+                        buf->str[self->priv->msp_parser.lex_pos_start + 3] == 'O' &&
+                        buf->str[self->priv->msp_parser.lex_pos_start + 4] == 'U' &&
+                        buf->str[self->priv->msp_parser.lex_pos_start + 5] == 'N' &&
+                        buf->str[self->priv->msp_parser.lex_pos_start + 6] == 'D')
+                    self->priv->msp_type = MSP_TYPE_SOUND;
+                else if(buf->str[self->priv->msp_parser.lex_pos_start + 2] == 'M' &&
+                        buf->str[self->priv->msp_parser.lex_pos_start + 3] == 'U' &&
+                        buf->str[self->priv->msp_parser.lex_pos_start + 4] == 'S' &&
+                        buf->str[self->priv->msp_parser.lex_pos_start + 5] == 'I' &&
+                        buf->str[self->priv->msp_parser.lex_pos_start + 6] == 'C')
+                    self->priv->msp_type = MSP_TYPE_MUSIC;
+                else
+                {
+                    /* Not an msp command, bail out. */
+                    self->priv->msp_parser.output = 
+                        g_string_append_c(self->priv->msp_parser.output,
+                                buf->str[self->priv->msp_parser.lex_pos_start++]);
+                    self->priv->msp_parser.output = 
+                        g_string_append_c(self->priv->msp_parser.output,
+                                buf->str[self->priv->msp_parser.lex_pos_start++]);
+
+                    self->priv->msp_parser.state = MSP_STATE_TEXT;
+                    continue;
+                }
+
+                // Skip leading (
+                self->priv->msp_parser.lex_pos_start += 8;
+                self->priv->msp_parser.state = MSP_STATE_GET_ARGS;
+                continue;
+                break;
+
+            case MSP_STATE_GET_ARGS:
+                self->priv->msp_parser.lex_pos_end = self->priv->msp_parser.lex_pos_start;
+
+                if(self->priv->msp_parser.arg_buffer == NULL)
+                    self->priv->msp_parser.arg_buffer = g_string_new(NULL);
+
+                while(self->priv->msp_parser.lex_pos_end < *len &&
+                        buf->str[self->priv->msp_parser.lex_pos_end] != ')')
+                    self->priv->msp_parser.arg_buffer = 
+                        g_string_append_c(self->priv->msp_parser.arg_buffer,
+                                buf->str[self->priv->msp_parser.lex_pos_end++]);
+
+                if(self->priv->msp_parser.lex_pos_end >= *len &&
+                        buf->str[self->priv->msp_parser.lex_pos_end - 1] != ')')
+                {
+                    self->priv->msp_parser.lex_pos_start =
+                        self->priv->msp_parser.lex_pos_end;
+                    continue;
+                }
+
+                self->priv->msp_parser.state = MSP_STATE_PARSE_ARGS;
+
+                break;
+
+            case MSP_STATE_PARSE_ARGS:
+                mud_telnet_msp_parser_args(self);
+
+                g_string_free(self->priv->msp_parser.arg_buffer, TRUE);
+                self->priv->msp_parser.arg_buffer = NULL;
+                self->priv->msp_parser.lex_pos_start =
+                    self->priv->msp_parser.lex_pos_end + 1;
+                self->priv->msp_parser.state = MSP_STATE_TEXT;
+                break;
+        }
+    }
+
+    if(self->priv->msp_parser.state == MSP_STATE_TEXT)
+    {
+        ret = g_string_new(g_strdup(self->priv->msp_parser.output->str));
+        *len = self->priv->msp_parser.output->len;
+    }
+
+    g_string_free(buf, TRUE);
+    *(&buf) = NULL;
+
+    return ret;
+}
+
+void
+mud_telnet_msp_download_item_free(MudMSPDownloadItem *item)
+{
+    if(!item)
+        return;
+
+    if(item->url)
+        g_free(item->url);
+
+    if(item->file)
+        g_free(item->file);
+
+    g_free(item);
+}
+
+void
+mud_telnet_msp_stop_playing(MudTelnetMsp *self, MudMSPTypes type)
+{
+    g_return_if_fail(MUD_IS_TELNET_MSP(self));
+
+    self->priv->sound[type].playing = FALSE;
+
+    if(GST_IS_ELEMENT(self->priv->sound[type].play))
+    {
+        gst_element_set_state (self->priv->sound[type].play, GST_STATE_NULL);
+        gst_object_unref (GST_OBJECT (self->priv->sound[type].play));
+    }
+
+    if(self->priv->sound[type].files)
+    {
+        g_strfreev(self->priv->sound[type].files);
+        self->priv->sound[type].files = NULL;
+    }
+
+    self->priv->sound[type].files_len = 0;
+
+    mud_telnet_msp_command_free(self->priv->sound[type].current_command);
+    self->priv->sound[type].current_command = NULL;
+}
+
+/* Private Methods */
+static void
+mud_telnet_msp_parser_reset(MudTelnetMsp *self)
+{
+    g_return_if_fail(MUD_IS_TELNET_MSP(self));
+
+    self->priv->msp_parser.lex_pos_start = 0;
+    self->priv->msp_parser.lex_pos_end = 0;
+}
+
+static void
+mud_telnet_msp_parser_args(MudTelnetMsp *self)
+{
+    gint state = ARG_STATE_FILE;
+    gint i;
+    GString *buffer;
+    gchar *args;
+    gint len;
+    MudMSPCommand *command;
+    MudConnectionView *view;
+
+    g_return_if_fail(MUD_IS_TELNET_MSP(self));
+
+    buffer = g_string_new(NULL);
+    args =  g_strdup(self->priv->msp_parser.arg_buffer->str);
+    len = strlen(args);;
+
+    command = g_new0(MudMSPCommand, 1);
+
+    g_object_get(self->priv->telnet, "parent-view", &view, NULL);
+
+    command->type = self->priv->msp_type;
+    command->fName = NULL;
+    command->V = NULL;
+    command->L = NULL;
+    command->C = NULL;
+    command->T = NULL;
+    command->U = NULL;
+    command->P = NULL;
+
+    g_object_get(view, "mud-name", &command->mud_name, NULL);
+    command->sfx_type = NULL;
+
+    /* Load defaults */
+    command->volume = 100;
+    command->priority = 50;
+    command->initial_repeat_count = 1;
+    command->current_repeat_count = 1;
+    command->loop = FALSE;
+    command->cont = (self->priv->msp_type == MSP_TYPE_MUSIC);
+
+    for(i = 0; i < len; ++i)
+    {
+        if(args[i] == ' ' || args[i] == '=' || args[i] == '"')
+            continue;
+
+        switch(state)
+        {
+            case ARG_STATE_FILE:
+                if(mud_telnet_msp_parser_is_param_char(args[i]) &&
+                        mud_telnet_msp_parser_switch_on_param_char(&state, args, i, len))
+                {
+                    command->fName = g_strdup(buffer->str);
+                    g_string_free(buffer, TRUE);
+                    buffer = g_string_new(NULL);
+                }
+                else
+                    buffer = g_string_append_c(buffer, args[i]);
+                break;
+
+            case ARG_STATE_V:
+                if(mud_telnet_msp_parser_is_param_char(args[i]) &&
+                        mud_telnet_msp_parser_switch_on_param_char(&state, args, i, len))
+                {
+                    command->V = g_strdup(buffer->str);
+                    g_string_free(buffer, TRUE);
+                    buffer = g_string_new(NULL);
+                }
+                else
+                    buffer = g_string_append_c(buffer, args[i]);
+                break;
+
+            case ARG_STATE_L:
+                if(mud_telnet_msp_parser_is_param_char(args[i]) &&
+                        mud_telnet_msp_parser_switch_on_param_char(&state, args, i, len))
+                {
+                    command->L = g_strdup(buffer->str);
+                    g_string_free(buffer, TRUE);
+                    buffer = g_string_new(NULL);
+                }
+                else
+                    buffer = g_string_append_c(buffer, args[i]);
+                break;
+
+            case ARG_STATE_C:
+                if(mud_telnet_msp_parser_is_param_char(args[i]) &&
+                        mud_telnet_msp_parser_switch_on_param_char(&state, args, i, len))
+                {
+                    command->C = g_strdup(buffer->str);
+                    g_string_free(buffer, TRUE);
+                    buffer = g_string_new(NULL);
+                }
+                else
+                    buffer = g_string_append_c(buffer, args[i]);
+                break;
+
+            case ARG_STATE_T:
+                if(mud_telnet_msp_parser_is_param_char(args[i]) &&
+                        mud_telnet_msp_parser_switch_on_param_char(&state, args, i, len))
+                {
+                    command->T = g_strdup(buffer->str);
+                    g_string_free(buffer, TRUE);
+                    buffer = g_string_new(NULL);
+                }
+                else
+                    buffer = g_string_append_c(buffer, args[i]);
+                break;
+
+            case ARG_STATE_U:
+                if(mud_telnet_msp_parser_is_param_char(args[i]) &&
+                        mud_telnet_msp_parser_switch_on_param_char(&state, args, i, len))
+                {
+                    if(buffer->str[buffer->len - 1] != '/')
+                        buffer = g_string_append_c(buffer, '/');
+
+                    command->U = g_strdup(buffer->str);
+                    g_string_free(buffer, TRUE);
+                    buffer = g_string_new(NULL);
+                }
+                else
+                    buffer = g_string_append_c(buffer, args[i]);
+                break;
+
+            case ARG_STATE_P:
+                if(mud_telnet_msp_parser_is_param_char(args[i]) &&
+                        mud_telnet_msp_parser_switch_on_param_char(&state, args, i, len))
+                {
+                    command->P = g_strdup(buffer->str);
+                    g_string_free(buffer, TRUE);
+                    buffer = g_string_new(NULL);
+                }
+                else
+                    buffer = g_string_append_c(buffer, args[i]);
+                break;
+        }
+    }
+
+    switch(state)
+    {
+        case ARG_STATE_FILE:
+            command->fName = g_strdup(buffer->str);
+            break;
+
+        case ARG_STATE_V:
+            command->V = g_strdup(buffer->str);
+            break;
+
+        case ARG_STATE_L:
+            command->L = g_strdup(buffer->str);
+            break;
+
+        case ARG_STATE_C:
+            command->C = g_strdup(buffer->str);
+            break;
+
+        case ARG_STATE_T:
+            command->T = g_strdup(buffer->str);
+            break;
+
+        case ARG_STATE_U:
+            if(buffer->str[buffer->len - 1] != '/')
+                buffer = g_string_append_c(buffer, '/');
+
+            command->U = g_strdup(buffer->str);
+            break;
+
+        case ARG_STATE_P:
+            command->P = g_strdup(buffer->str);
+            break;
+    }
+
+    if(command->C)
+        command->cont = atoi(command->C);
+
+    if(command->T)
+        command->sfx_type = g_strdup(command->T);
+
+    if(command->V)
+        command->volume = atoi(command->V);
+
+    if(command->P)
+        command->priority = atoi(command->P);
+
+    if(command->L)
+    {
+        command->initial_repeat_count = atoi(command->L);
+
+        if(command->initial_repeat_count == 0)
+            command->initial_repeat_count = 1;
+
+        command->current_repeat_count = command->initial_repeat_count;
+
+        if(command->current_repeat_count == -1)
+            command->loop = TRUE;
+    }
+
+    mud_telnet_msp_process_command(self, command);
+
+    g_free(args);
+    g_string_free(buffer, TRUE);
+}
+
+static gboolean
+mud_telnet_msp_parser_is_param_char(gchar c)
+{
+    return (c == 'V' || c == 'L' || c == 'C' ||
+            c == 'T' || c == 'U' || c == 'P');
+}
+
+static gboolean
+mud_telnet_msp_parser_switch_on_param_char(gint *state, gchar *buf,
+					   gint index, gint len)
+{
+    if(index + 1 == len)
+        return FALSE;
+
+    if(buf[index + 1] != '=')
+        return FALSE;
+
+    switch(buf[index])
+    {
+        case 'V':
+            *state = ARG_STATE_V;
+            return TRUE;
+            break;
+
+        case 'L':
+            *state = ARG_STATE_L;
+            return TRUE;
+            break;
+
+        case 'C':
+            *state = ARG_STATE_C;
+            return TRUE;
+            break;
+
+        case 'T':
+            *state = ARG_STATE_T;
+            return TRUE;
+            break;
+
+        case 'U':
+            *state = ARG_STATE_U;
+            return TRUE;
+            break;
+
+        case 'P':
+            *state = ARG_STATE_P;
+            return TRUE;
+            break;
+    }
+
+    return FALSE;
+}
+
+static void
+mud_telnet_msp_command_free(MudMSPCommand *command)
+{
+    if(command == NULL)
+        return;
+
+    if(command->fName)
+        g_free(command->fName);
+
+    if(command->mud_name)
+        g_free(command->mud_name);
+
+    if(command->sfx_type)
+        g_free(command->sfx_type);
+
+    if(command->V)
+        g_free(command->V);
+
+    if(command->L)
+        g_free(command->L);
+
+    if(command->P)
+        g_free(command->P);
+
+    if(command->C)
+        g_free(command->C);
+
+    if(command->T)
+        g_free(command->T);
+
+    if(command->U)
+        g_free(command->U);
+
+    g_free(command);
+
+}
+
+static void
+mud_telnet_msp_process_command(MudTelnetMsp *self, MudMSPCommand *command)
+{
+    g_return_if_fail(MUD_IS_TELNET_MSP(self));
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "MSP Command Parse Results");
+    g_log("Telnet", G_LOG_LEVEL_INFO, 
+            "Type: %s", (command->type == MSP_TYPE_SOUND) ? "Sound" :
+            "Music" );
+    g_log("Telnet", G_LOG_LEVEL_INFO,
+            "Filename: %s", (command->fName != NULL) ? command->fName :
+            "<null>");
+    g_log("Telnet", G_LOG_LEVEL_INFO,
+            "V: %s", (command->V != NULL) ? command->V : "<null>");
+    g_log("Telnet", G_LOG_LEVEL_INFO,
+            "L: %s", (command->L != NULL) ? command->L : "<null>");
+    g_log("Telnet", G_LOG_LEVEL_INFO,
+            "C: %s", (command->C != NULL) ? command->C : "<null>");
+    g_log("Telnet", G_LOG_LEVEL_INFO, 
+            "T: %s", (command->T != NULL) ? command->T : "<null>");
+    g_log("Telnet", G_LOG_LEVEL_INFO,
+            "U: %s", (command->U != NULL) ? command->U : "<null>");
+    g_log("Telnet", G_LOG_LEVEL_INFO,
+            "P: %s", (command->P != NULL) ? command->P : "<null>");
+    g_log("Telnet", G_LOG_LEVEL_INFO,
+            "Sfx Type: %s Volume: %d  Priority: %d  Repeat %d times. %s %s",
+            (command->sfx_type) ? command->sfx_type:"None", command->volume,
+            command->priority, command->initial_repeat_count, (command->loop) ?
+            "Looping" : "Not Looping",
+            (command->cont) ? "Continue" : "Stop");
+
+    if(command->fName && strcmp(command->fName, "Off") == 0)
+    {
+        if(command->U)
+        {
+            if(self->priv->base_url)
+                g_free(self->priv->base_url);
+
+            self->priv->base_url = g_strdup(command->U);
+        }
+        else
+            mud_telnet_msp_stop_playing(self, command->type);
+
+        mud_telnet_msp_command_free(command);
+
+        return;
+    }
+
+    if(self->priv->sound[command->type].current_command)
+    {
+        if(self->priv->sound[command->type].playing)
+        {
+            if(command->priority >
+                   self->priv->sound[command->type].current_command->priority)
+            {
+                mud_telnet_msp_stop_playing(self, command->type);
+                self->priv->sound[command->type].current_command = command;
+                mud_telnet_msp_start_playing(self, command->type);
+            }
+            else
+                mud_telnet_msp_command_free(command);
+        }
+        else
+        {
+            mud_telnet_msp_stop_playing(self, command->type);
+            self->priv->sound[command->type].current_command = command;
+            mud_telnet_msp_start_playing(self, command->type);
+        }
+    }
+    else
+    {
+        self->priv->sound[command->type].current_command = command;
+        mud_telnet_msp_start_playing(self, command->type);
+    }
+}
+
+static void
+mud_telnet_msp_start_playing(MudTelnetMsp *self, MudMSPTypes type)
+{
+    g_return_if_fail(MUD_IS_TELNET_MSP(self));
+
+    if(!self->priv->sound[type].current_command)
+        return;
+
+    if(mud_telnet_msp_get_files(self, type))
+    {
+        gint num = 0;
+
+        self->priv->sound[type].playing = TRUE;
+
+        if(self->priv->sound[type].files_len != 0)
+            num = rand() % self->priv->sound[type].files_len;
+
+        self->priv->sound[type].play = gst_element_factory_make ("playbin", "play");
+        g_object_set (G_OBJECT(self->priv->sound[type].play),
+                "uri", self->priv->sound[type].files[num], NULL);
+        g_object_set(G_OBJECT(self->priv->sound[type].play),
+                "volume",
+                (double)self->priv->sound[type].current_command->volume/100,
+                NULL);
+
+        self->priv->sound[type].bus =
+            gst_pipeline_get_bus (GST_PIPELINE (self->priv->sound[type].play));
+
+        if(type == MSP_TYPE_SOUND)
+            gst_bus_add_watch (self->priv->sound[type].bus,
+                    mud_telnet_msp_sound_bus_call, self);
+        else
+            gst_bus_add_watch (self->priv->sound[type].bus,
+                    mud_telnet_msp_music_bus_call, self);
+
+        gst_object_unref (self->priv->sound[type].bus);
+
+        gst_element_set_state (self->priv->sound[type].play, GST_STATE_PLAYING);
+    }
+}
+
+static gboolean
+mud_telnet_msp_get_files(MudTelnetMsp *self, MudMSPTypes type)
+{
+    gchar sound_dir[2048];
+    const gchar *file;
+    gchar **files;
+    gchar **structure;
+    GString *file_output;
+    GString *url_output;
+    GString *file_name;
+    GString *subdir;
+    GString *full_dir;
+    gchar *mud_name;
+    GDir *dir;
+    gint i, depth;
+    GPatternSpec *regex;
+    MudConnectionView *view;
+
+    g_return_if_fail(MUD_IS_TELNET_MSP(self));
+
+    g_object_get(self->priv->telnet, "parent-view", &view, NULL);
+    g_object_get(view, "mud-name", &mud_name, NULL);
+
+    if(!self->priv->sound[type].current_command)
+        return FALSE;
+
+    g_snprintf(sound_dir, 2048, "%s/.gnome-mud/audio/%s/",
+            g_get_home_dir(), mud_name);
+    if(!g_file_test(sound_dir, G_FILE_TEST_IS_DIR))
+        mkdir(sound_dir, 0777 );
+
+    g_free(mud_name);
+
+    structure = g_strsplit(self->priv->sound[type].current_command->fName, "/", 0);
+    depth = g_strv_length(structure);
+
+    subdir = g_string_new(NULL);
+
+    for(i = 0; i < depth - 1; ++i)
+    {
+        subdir = g_string_append(subdir, structure[i]);
+        subdir = g_string_append_c(subdir, '/');
+    }
+
+    file_name = g_string_new(structure[depth - 1]);
+
+    g_strfreev(structure);
+
+    full_dir = g_string_new(sound_dir);
+    full_dir = g_string_append(full_dir, subdir->str);
+
+    if(self->priv->sound[type].current_command->T)
+        full_dir = g_string_append(full_dir, self->priv->sound[type].current_command->T);
+
+    if(!g_file_test(full_dir->str, G_FILE_TEST_IS_DIR))
+        g_mkdir_with_parents(full_dir->str, 0777);
+
+    file_output = g_string_new(NULL);
+
+    regex = g_pattern_spec_new(file_name->str);
+
+    dir = g_dir_open(full_dir->str, 0, NULL);
+
+    while((file = g_dir_read_name(dir)) != NULL)
+    {
+        if(g_pattern_match_string(regex, file))
+        {
+            file_output = g_string_append(file_output, "file://");
+            file_output = g_string_append(file_output, full_dir->str);
+            file_output = g_string_append_c(file_output, '/');
+            file_output = g_string_append(file_output, file);
+            file_output = g_string_append_c(file_output, '\n');
+        }
+    }
+
+    g_dir_close(dir);
+
+    // Try searching again in main directory since
+    // some servers ignore the standard concering the
+    // T parameter and don't put the sound in a T-named
+    // subdir.
+    if(file_output->len == 0 && self->priv->sound[type].current_command->T)
+    {
+        g_string_free(full_dir, TRUE);
+        full_dir = g_string_new(sound_dir);
+        full_dir = g_string_append(full_dir, subdir->str);
+
+        dir = g_dir_open(full_dir->str, 0, NULL);
+
+        while((file = g_dir_read_name(dir)) != NULL)
+        {
+            if(g_pattern_match_string(regex, file))
+            {
+                file_output = g_string_append(file_output, "file://");
+                file_output = g_string_append(file_output, full_dir->str);
+                file_output = g_string_append_c(file_output, '/');
+                file_output = g_string_append(file_output, file);
+                file_output = g_string_append_c(file_output, '\n');
+            }
+        }
+
+        g_dir_close(dir);
+    }
+
+    g_pattern_spec_free(regex);
+
+    if(file_output->len == 0) // no matches, file doesn't exist.
+    {
+        url_output = g_string_new(NULL);
+
+        if(self->priv->base_url || self->priv->sound[type].current_command->U)
+        {
+            if(self->priv->base_url)
+                url_output = g_string_append(url_output, self->priv->base_url);
+            else
+                url_output = g_string_append(url_output, self->priv->sound[type].current_command->U);
+
+            if(subdir->len != 0)
+                url_output = g_string_append(url_output, subdir->str);
+
+            /*	    if(self->priv->sound[type].current_command->T)
+                    {
+                    url_output = g_string_append(url_output, self->priv->sound[type].current_command->T);
+                    url_output = g_string_append_c(url_output, '/');
+                    }
+                    */
+            url_output = g_string_append(url_output, file_name->str);
+
+            file_output = g_string_append(file_output, full_dir->str);
+            if(self->priv->sound[type].current_command->T)
+                file_output = g_string_append_c(file_output, '/');
+            file_output = g_string_append(file_output, file_name->str);
+
+            self->priv->sound[type].current_command->priority = 0;
+
+            mud_connection_view_queue_download(view, url_output->str, file_output->str);
+        }
+
+        g_string_free(url_output, TRUE);
+        g_string_free(file_output, TRUE);
+        g_string_free(full_dir, TRUE);
+        g_string_free(subdir, TRUE);
+        g_string_free(file_name, TRUE);
+
+        return FALSE;
+    }
+
+    files = g_strsplit(file_output->str, "\n", 0);
+
+    if(self->priv->sound[type].files)
+        g_strfreev(self->priv->sound[type].files);
+
+    self->priv->sound[type].files = files;
+    self->priv->sound[type].files_len = g_strv_length(files) - 1;
+
+    g_string_free(file_output, TRUE);
+    g_string_free(full_dir, TRUE);
+    g_string_free(subdir, TRUE);
+    g_string_free(file_name, TRUE);
+
+    return TRUE;
+}
+
+static gboolean
+mud_telnet_msp_sound_bus_call (GstBus *bus, GstMessage *msg, gpointer data)
+{
+    MudTelnetMsp *self = MUD_TELNET_MSP(data);
+
+    switch (GST_MESSAGE_TYPE (msg))
+    {
+        case GST_MESSAGE_EOS:
+            self->priv->sound[MSP_TYPE_SOUND].playing = FALSE;
+
+            self->priv->sound[MSP_TYPE_SOUND].current_command->current_repeat_count--;
+
+            gst_element_set_state (self->priv->sound[MSP_TYPE_SOUND].play, GST_STATE_NULL);
+
+            if(self->priv->sound[MSP_TYPE_SOUND].current_command->loop ||
+                    self->priv->sound[MSP_TYPE_SOUND].current_command->current_repeat_count != 0)
+            {
+                gint num = 0;
+
+                if(self->priv->sound[MSP_TYPE_SOUND].files_len != 0)
+                    num = rand() % self->priv->sound[MSP_TYPE_SOUND].files_len;
+
+                g_object_set (G_OBJECT(self->priv->sound[MSP_TYPE_SOUND].play),
+                        "uri", self->priv->sound[MSP_TYPE_SOUND].files[num], NULL);
+                g_object_set(G_OBJECT(self->priv->sound[MSP_TYPE_SOUND].play),
+                        "volume", (double)self->priv->sound[MSP_TYPE_SOUND].current_command->volume/100.0, NULL);
+
+                gst_element_set_state (self->priv->sound[MSP_TYPE_SOUND].play, GST_STATE_PLAYING);
+            }
+            else
+                mud_telnet_msp_stop_playing(self, MSP_TYPE_SOUND);
+            break;
+
+        case GST_MESSAGE_ERROR:
+            {
+                gchar *debug;
+                GError *err;
+
+                gst_message_parse_error (msg, &err, &debug);
+                g_free (debug);
+
+                g_warning ("Error: %s", err->message);
+                g_error_free (err);
+
+                break;
+            }
+
+        default:
+            break;
+    }
+
+    return TRUE;
+}
+
+static gboolean
+mud_telnet_msp_music_bus_call (GstBus *bus, GstMessage *msg, gpointer data)
+{
+    MudTelnetMsp *self = MUD_TELNET_MSP(data);
+
+    switch (GST_MESSAGE_TYPE (msg))
+    {
+        case GST_MESSAGE_EOS:
+            self->priv->sound[MSP_TYPE_MUSIC].playing = FALSE;
+
+            self->priv->sound[MSP_TYPE_MUSIC].current_command->current_repeat_count--;
+
+            gst_element_set_state (self->priv->sound[MSP_TYPE_MUSIC].play, GST_STATE_NULL);
+
+            if(self->priv->sound[MSP_TYPE_MUSIC].current_command->loop ||
+                    self->priv->sound[MSP_TYPE_MUSIC].current_command->current_repeat_count != 0)
+            {
+                gint num = 0;
+
+                if(self->priv->sound[MSP_TYPE_MUSIC].files_len != 0)
+                    num = rand() % self->priv->sound[MSP_TYPE_MUSIC].files_len;
+
+                g_object_set (G_OBJECT(self->priv->sound[MSP_TYPE_MUSIC].play),
+                        "uri", self->priv->sound[MSP_TYPE_MUSIC].files[num], NULL);
+                g_object_set(G_OBJECT(self->priv->sound[MSP_TYPE_MUSIC].play),
+                        "volume", (double)self->priv->sound[MSP_TYPE_MUSIC].current_command->volume/100.0, NULL);
+
+                gst_element_set_state (self->priv->sound[MSP_TYPE_MUSIC].play, GST_STATE_PLAYING);
+            }
+            else
+                mud_telnet_msp_stop_playing(self, MSP_TYPE_MUSIC);
+
+            break;
+
+        case GST_MESSAGE_ERROR:
+            {
+                gchar *debug;
+                GError *err;
+
+                gst_message_parse_error (msg, &err, &debug);
+                g_free (debug);
+
+                g_warning ("Error: %s", err->message);
+                g_error_free (err);
+
+                break;
+            }
+
+        default:
+            break;
+    }
+
+    return TRUE;
+}
+
+#endif
+

Added: trunk/src/handlers/mud-telnet-msp.h
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-msp.h	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,151 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-msp.h
+ * Copyright (C) 2008-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MUD_TELNET_MSP_H
+#define MUD_TELNET_MSP_H
+
+#ifdef ENABLE_GST
+
+G_BEGIN_DECLS
+
+#include <glib.h>
+#include <gst/gst.h>
+
+#include "mud-telnet.h"
+
+#define MUD_TYPE_TELNET_MSP              (mud_telnet_msp_get_type ())
+#define MUD_TELNET_MSP(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), MUD_TYPE_TELNET_MSP, MudTelnetMsp))
+#define MUD_TELNET_MSP_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), MUD_TYPE_TELNET_MSP, MudTelnetMspClass))
+#define MUD_IS_TELNET_MSP(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), MUD_TYPE_TELNET_MSP))
+#define MUD_IS_TELNET_MSP_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), MUD_TYPE_TELNET_MSP))
+#define MUD_TELNET_MSP_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), MUD_TYPE_TELNET_MSP, MudTelnetMspClass))
+#define MUD_TELNET_MSP_GET_PRIVATE(obj)  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUD_TYPE_TELNET_MSP, MudTelnetMspPrivate))
+
+typedef struct _MudTelnetMsp            MudTelnetMsp;
+typedef struct _MudTelnetMspClass       MudTelnetMspClass;
+typedef struct _MudTelnetMspPrivate     MudTelnetMspPrivate;
+
+struct _MudTelnetMspClass
+{
+    GObjectClass parent_class;
+};
+
+struct _MudTelnetMsp
+{
+    GObject parent_instance;
+
+    /*< private >*/
+    MudTelnetMspPrivate *priv;
+};
+
+typedef enum
+{
+    MSP_TYPE_SOUND,
+    MSP_TYPE_MUSIC
+} MudMSPTypes;
+
+typedef enum
+{
+    MSP_STATE_TEXT,
+    MSP_STATE_POSSIBLE_COMMAND,
+    MSP_STATE_COMMAND,
+    MSP_STATE_GET_ARGS,
+    MSP_STATE_PARSE_ARGS
+} MudMSPStates;
+
+typedef enum
+{
+    ARG_STATE_FILE,
+    ARG_STATE_V,
+    ARG_STATE_L,
+    ARG_STATE_C,
+    ARG_STATE_T,
+    ARG_STATE_U,
+    ARG_STATE_P
+} MudMSPArgStates;
+
+typedef struct MudMSPParser
+{
+    gboolean enabled;
+
+    MudMSPStates state;
+
+    gint lex_pos_start;
+    gint lex_pos_end;
+
+    GString *output;
+    GString *arg_buffer;
+} MudMSPParser;
+
+typedef struct MudMSPCommand
+{
+    MudMSPTypes type;
+
+    gchar *fName;
+
+    gchar *V;
+    gchar *L;
+    gchar *P;
+    gchar *C;
+    gchar *T;
+    gchar *U;
+
+    gchar *mud_name;
+    gchar *sfx_type;
+
+    gint volume;
+    gint priority;
+    gint initial_repeat_count;
+    gint current_repeat_count;
+    gboolean loop;
+    gboolean cont;
+
+} MudMSPCommand;
+
+typedef struct MudMSPDownloadItem
+{
+    gchar *url;
+    gchar *file;
+} MudMSPDownloadItem;
+
+typedef struct MudMSPSound
+{
+    gboolean playing;
+    gchar **files;
+    gint files_len;
+
+    GstElement *play;
+    GstBus *bus;
+
+    MudMSPCommand *current_command;
+} MudMSPSound;
+
+GType mud_telnet_msp_get_type (void);
+
+void mud_telnet_msp_download_item_free(MudMSPDownloadItem *item);
+GString *mud_telnet_msp_parse(MudTelnetMsp *self, GString *buf, gint *len);
+void mud_telnet_msp_stop_playing(MudTelnetMsp *self, MudMSPTypes type);
+void mud_telnet_msp_parser_clear(MudTelnetMsp *self);
+
+G_END_DECLS
+
+#endif // ENABLE_MSP
+
+#endif // MUD_TELNET_MSP_H
+

Added: trunk/src/handlers/mud-telnet-mssp.c
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-mssp.c	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,410 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-mssp.c
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+
+#include "gnome-mud.h"
+#include "mud-telnet.h"
+#include "mud-telnet-handler-interface.h"
+#include "mud-telnet-mssp.h"
+
+struct _MudTelnetMsspPrivate
+{
+    /* Interface Properties */
+    MudTelnet *telnet;
+    gboolean enabled;
+    gint option;
+
+    /* Private Instance Members */
+    GHashTable *mssp_data;
+};
+
+/* Property Identifiers */
+enum
+{
+    PROP_MUD_TELNET_MSSP_0,
+    PROP_ENABLED,
+    PROP_HANDLES_OPTION,
+    PROP_TELNET,
+    PROP_MSSP
+};
+
+enum
+{
+    PARSE_STATE_VAR,
+    PARSE_STATE_VAR_STRING,
+    PARSE_STATE_VAL,
+    PARSE_STATE_VAL_STRING
+};
+
+/* Class Functions */
+static void mud_telnet_mssp_init (MudTelnetMssp *self);
+static void mud_telnet_mssp_class_init (MudTelnetMsspClass *klass);
+static void mud_telnet_mssp_interface_init(MudTelnetHandlerInterface *iface);
+static void mud_telnet_mssp_finalize (GObject *object);
+static GObject *mud_telnet_mssp_constructor (GType gtype,
+                                             guint n_properties,
+                                             GObjectConstructParam *properties);
+static void mud_telnet_mssp_set_property(GObject *object,
+                                         guint prop_id,
+                                         const GValue *value,
+                                         GParamSpec *pspec);
+static void mud_telnet_mssp_get_property(GObject *object,
+                                         guint prop_id,
+                                         GValue *value,
+                                         GParamSpec *pspec);
+
+/*Interface Implementation */
+void mud_telnet_mssp_enable(MudTelnetHandler *self);
+void mud_telnet_mssp_disable(MudTelnetHandler *self);
+void mud_telnet_mssp_handle_sub_neg(MudTelnetHandler *self,
+                                    guchar *buf,
+                                    guint len);
+
+/* Private Methods */
+static void mud_telnet_mssp_destroy_key(gpointer k);
+static void mud_telnet_mssp_destroy_value(gpointer c);
+
+/* Create the Type. We implement MudTelnetHandlerInterface */
+G_DEFINE_TYPE_WITH_CODE(MudTelnetMssp, mud_telnet_mssp, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (MUD_TELNET_HANDLER_TYPE,
+                                               mud_telnet_mssp_interface_init));
+/* MudTelnetMssp class functions */
+static void
+mud_telnet_mssp_class_init (MudTelnetMsspClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    /* Override base object constructor */
+    object_class->constructor = mud_telnet_mssp_constructor;
+
+    /* Override base object's finalize */
+    object_class->finalize = mud_telnet_mssp_finalize;
+
+    /* Override base object property methods */
+    object_class->set_property = mud_telnet_mssp_set_property;
+    object_class->get_property = mud_telnet_mssp_get_property;
+
+    /* Add private data to class */
+    g_type_class_add_private(klass, sizeof(MudTelnetMsspPrivate));
+
+    /* Override Implementation Properties */
+    g_object_class_override_property(object_class,
+                                     PROP_ENABLED,
+                                     "enabled");
+
+    g_object_class_override_property(object_class,
+                                     PROP_HANDLES_OPTION,
+                                     "handles-option");
+
+    g_object_class_override_property(object_class,
+                                     PROP_TELNET,
+                                     "telnet");
+    /* Custom Class Properties */
+    g_object_class_install_property(object_class,
+                            PROP_MSSP,
+                            g_param_spec_pointer("mssp-data",
+                                                 "MSSP Data",
+                                                 "The MSSP data provided by the mud.",
+                                                 G_PARAM_READABLE));
+}
+
+static void
+mud_telnet_mssp_interface_init(MudTelnetHandlerInterface *iface)
+{
+    iface->Enable = mud_telnet_mssp_enable;
+    iface->Disable = mud_telnet_mssp_disable;
+    iface->HandleSubNeg = mud_telnet_mssp_handle_sub_neg;
+}
+
+static void
+mud_telnet_mssp_init (MudTelnetMssp *self)
+{
+    /* Get our private data */
+    self->priv = MUD_TELNET_MSSP_GET_PRIVATE(self);
+
+    /* Set the defaults */
+    self->priv->telnet = NULL;
+    self->priv->option = TELOPT_MSSP;
+    self->priv->enabled = FALSE;
+
+    self->priv->mssp_data = NULL;
+}
+
+static GObject *
+mud_telnet_mssp_constructor (GType gtype,
+                             guint n_properties,
+                             GObjectConstructParam *properties)
+{
+    MudTelnetMssp *self;
+    GObject *obj;
+    MudTelnetMsspClass *klass;
+    GObjectClass *parent_class;
+
+    /* Chain up to parent constructor */
+    klass = MUD_TELNET_MSSP_CLASS( g_type_class_peek(MUD_TYPE_TELNET_MSSP) );
+    parent_class = G_OBJECT_CLASS( g_type_class_peek_parent(klass) );
+    obj = parent_class->constructor(gtype, n_properties, properties);
+
+    self = MUD_TELNET_MSSP(obj);
+
+    if(!self->priv->telnet)
+    {
+        g_printf("ERROR: Tried to instantiate MudTelnetMssp without passing parent MudTelnet\n");
+        g_error("Tried to instantiate MudTelnetMssp without passing parent MudTelnet");
+    }
+
+    self->priv->mssp_data = g_hash_table_new_full(g_str_hash,
+                                                  g_str_equal,
+                                                  mud_telnet_mssp_destroy_key,
+                                                  mud_telnet_mssp_destroy_value);
+
+    return obj;
+}
+
+static void
+mud_telnet_mssp_finalize (GObject *object)
+{
+    MudTelnetMssp *self;
+    GObjectClass *parent_class;
+
+    self = MUD_TELNET_MSSP(object);
+
+    if(self->priv->mssp_data)
+        g_hash_table_destroy(self->priv->mssp_data);
+
+    parent_class = g_type_class_peek_parent(G_OBJECT_GET_CLASS(object));
+    parent_class->finalize(object);
+}
+
+static void
+mud_telnet_mssp_set_property(GObject *object,
+                             guint prop_id,
+                             const GValue *value,
+                             GParamSpec *pspec)
+{
+    MudTelnetMssp *self;
+
+    self = MUD_TELNET_MSSP(object);
+
+    switch(prop_id)
+    {
+        case PROP_TELNET:
+            self->priv->telnet = MUD_TELNET(g_value_get_object(value));
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+static void
+mud_telnet_mssp_get_property(GObject *object,
+                             guint prop_id,
+                             GValue *value,
+                             GParamSpec *pspec)
+{
+    MudTelnetMssp *self;
+
+    self = MUD_TELNET_MSSP(object);
+
+    switch(prop_id)
+    {
+        case PROP_ENABLED:
+            g_value_set_boolean(value, self->priv->enabled);
+            break;
+
+        case PROP_HANDLES_OPTION:
+            g_value_set_int(value, self->priv->option);
+            break;
+
+        case PROP_TELNET:
+            g_value_take_object(value, self->priv->telnet);
+            break;
+
+        case PROP_MSSP:
+            g_value_set_pointer(value, self->priv->mssp_data);
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+/* Interface Implementation */
+void 
+mud_telnet_mssp_enable(MudTelnetHandler *handler)
+{
+    MudTelnetMssp *self;
+
+    self = MUD_TELNET_MSSP(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_MSSP(self));
+
+    self->priv->enabled = TRUE;
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "MSSP Enabled");
+}
+
+void
+mud_telnet_mssp_disable(MudTelnetHandler *handler)
+{
+    MudTelnetMssp *self;
+
+    self = MUD_TELNET_MSSP(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_MSSP(self));
+
+    self->priv->enabled = FALSE;
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "MSSP Disabled");
+}
+
+void
+mud_telnet_mssp_handle_sub_neg(MudTelnetHandler *handler,
+                               guchar *buf,
+                               guint len)
+{
+    MudTelnetMssp *self;
+    guint i, state;
+    GString *key, *value;
+
+    self = MUD_TELNET_MSSP(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_MSSP(self));
+
+    state = PARSE_STATE_VAR;
+
+    for(i = 0; i < len - 1; ++i)
+    {
+        switch(state)
+        {
+            case PARSE_STATE_VAR:
+                key = g_string_new(NULL);
+
+                state = PARSE_STATE_VAR_STRING;
+                break;
+
+            case PARSE_STATE_VAR_STRING:
+                if( buf[i] != TEL_MSSP_VAL )
+                    key = g_string_append_c(key, buf[i]);
+                else
+                {
+                    state = PARSE_STATE_VAL;
+                    i--;
+                } 
+                break;
+
+            case PARSE_STATE_VAL:
+                value = g_string_new(NULL);
+
+                state = PARSE_STATE_VAL_STRING;
+                break;
+
+            case PARSE_STATE_VAL_STRING:
+                if( buf[i] != TEL_MSSP_VAR && buf[i] != TEL_MSSP_VAL )
+                    value = g_string_append_c(value, buf[i]);
+                else
+                {
+                    switch( buf[i] )
+                    {
+                        /* VAR's can have multiple VALs assigned to them. */
+                        case TEL_MSSP_VAL:
+                            g_hash_table_replace(self->priv->mssp_data,
+                                    g_strdup(key->str),
+                                    g_string_free(value, FALSE));
+
+                            state = PARSE_STATE_VAL;
+                            i--;
+                            break;
+
+                        case TEL_MSSP_VAR:
+                            g_hash_table_replace(self->priv->mssp_data,
+                                    g_string_free(key, FALSE),
+                                    g_string_free(value, FALSE));
+
+                            state = PARSE_STATE_VAR;
+                            i--;
+                            break;
+                    }
+                }
+
+                if( i + 1 == len - 1) // Last value in subnegotiation.
+                    g_hash_table_replace(self->priv->mssp_data,
+                                         g_string_free(key, FALSE),
+                                         g_string_free(value, FALSE));
+
+                break;
+        }
+    }
+
+    /* Log the results */
+    {
+        GList *key_list, *entry;
+
+        g_log("Telnet", G_LOG_LEVEL_MESSAGE, "%s", "MSSP Data:");
+
+        key_list = g_hash_table_get_keys(self->priv->mssp_data);
+
+        entry = key_list;
+
+        while(entry)
+        {
+            const gchar *keyv = entry->data;
+            const gchar *valv = g_hash_table_lookup(self->priv->mssp_data, keyv);
+
+            g_log("Telnet",
+                  G_LOG_LEVEL_MESSAGE,
+                  "\t%s = %s",
+                  keyv, (valv) ? valv : "<null>");
+
+            entry = g_list_next(entry);
+        }
+
+        g_list_free(key_list);
+    }
+}
+
+/* Private Methods */
+static void
+mud_telnet_mssp_destroy_key(gpointer k)
+{
+    gchar *key = (gchar *)k;
+
+    if(key)
+        g_free(key);
+}
+
+static void
+mud_telnet_mssp_destroy_value(gpointer v)
+{
+    gchar *value = (gchar *)v;
+
+    if(value)
+        g_free(value);
+}
+

Added: trunk/src/handlers/mud-telnet-mssp.h
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-mssp.h	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,57 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-mssp.h
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MUD_TELNET_MSSP_H
+#define MUD_TELNET_MSSP_H
+
+G_BEGIN_DECLS
+
+#include <glib.h>
+
+#define MUD_TYPE_TELNET_MSSP              (mud_telnet_mssp_get_type ())
+#define MUD_TELNET_MSSP(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), MUD_TYPE_TELNET_MSSP, MudTelnetMssp))
+#define MUD_TELNET_MSSP_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), MUD_TYPE_TELNET_MSSP, MudTelnetMsspClass))
+#define MUD_IS_TELNET_MSSP(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), MUD_TYPE_TELNET_MSSP))
+#define MUD_IS_TELNET_MSSP_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), MUD_TYPE_TELNET_MSSP))
+#define MUD_TELNET_MSSP_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), MUD_TYPE_TELNET_MSSP, MudTelnetMsspClass))
+#define MUD_TELNET_MSSP_GET_PRIVATE(obj)  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUD_TYPE_TELNET_MSSP, MudTelnetMsspPrivate))
+
+typedef struct _MudTelnetMssp            MudTelnetMssp;
+typedef struct _MudTelnetMsspClass       MudTelnetMsspClass;
+typedef struct _MudTelnetMsspPrivate     MudTelnetMsspPrivate;
+
+struct _MudTelnetMsspClass
+{
+    GObjectClass parent_class;
+};
+
+struct _MudTelnetMssp
+{
+    GObject parent_instance;
+
+    /*< private >*/
+    MudTelnetMsspPrivate *priv;
+};
+
+GType mud_telnet_mssp_get_type (void);
+
+G_END_DECLS
+
+#endif // MUD_TELNET_MSSP_H
+

Added: trunk/src/handlers/mud-telnet-naws.c
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-naws.c	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,357 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-naws.c
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include <vte/vte.h>
+#include <gnet.h>
+
+#include "gnome-mud.h"
+#include "mud-telnet.h"
+#include "mud-telnet-handler-interface.h"
+#include "mud-telnet-naws.h"
+
+struct _MudTelnetNawsPrivate
+{
+    /* Interface Properties */
+    MudTelnet *telnet;
+    gboolean enabled;
+    gint option;
+
+    /* Private Instance Members */
+    gulong resized_signal;
+};
+
+/* Property Identifiers */
+enum
+{
+    PROP_MUD_TELNET_NAWS_0,
+    PROP_ENABLED,
+    PROP_HANDLES_OPTION,
+    PROP_TELNET
+};
+
+/* Class Functions */
+static void mud_telnet_naws_init (MudTelnetNaws *self);
+static void mud_telnet_naws_class_init (MudTelnetNawsClass *klass);
+static void mud_telnet_naws_interface_init(MudTelnetHandlerInterface *iface);
+static void mud_telnet_naws_finalize (GObject *object);
+static GObject *mud_telnet_naws_constructor (GType gtype,
+                                             guint n_properties,
+                                             GObjectConstructParam *properties);
+static void mud_telnet_naws_set_property(GObject *object,
+                                         guint prop_id,
+                                         const GValue *value,
+                                         GParamSpec *pspec);
+static void mud_telnet_naws_get_property(GObject *object,
+                                         guint prop_id,
+                                         GValue *value,
+                                         GParamSpec *pspec);
+
+/*Interface Implementation */
+void mud_telnet_naws_enable(MudTelnetHandler *self);
+void mud_telnet_naws_disable(MudTelnetHandler *self);
+void mud_telnet_naws_handle_sub_neg(MudTelnetHandler *self,
+                                    guchar *buf,
+                                    guint len);
+
+/* Callbacks */
+static void mud_telnet_naws_resized_cb(MudWindow *window,
+                                       gint width,
+                                       gint height,
+                                       MudTelnetNaws *self);
+
+/* Private Methods */
+static void mud_telnet_naws_send(MudTelnetNaws *self, gint width, gint height);
+
+/* Create the Type. We implement MudTelnetHandlerInterface */
+G_DEFINE_TYPE_WITH_CODE(MudTelnetNaws, mud_telnet_naws, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (MUD_TELNET_HANDLER_TYPE,
+                                               mud_telnet_naws_interface_init));
+/* MudTelnetNaws class functions */
+static void
+mud_telnet_naws_class_init (MudTelnetNawsClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    /* Override base object constructor */
+    object_class->constructor = mud_telnet_naws_constructor;
+
+    /* Override base object's finalize */
+    object_class->finalize = mud_telnet_naws_finalize;
+
+    /* Override base object property methods */
+    object_class->set_property = mud_telnet_naws_set_property;
+    object_class->get_property = mud_telnet_naws_get_property;
+
+    /* Add private data to class */
+    g_type_class_add_private(klass, sizeof(MudTelnetNawsPrivate));
+
+    /* Override Implementation Properties */
+    g_object_class_override_property(object_class,
+                                     PROP_ENABLED,
+                                     "enabled");
+
+    g_object_class_override_property(object_class,
+                                     PROP_HANDLES_OPTION,
+                                     "handles-option");
+
+    g_object_class_override_property(object_class,
+                                     PROP_TELNET,
+                                     "telnet");
+}
+
+static void
+mud_telnet_naws_interface_init(MudTelnetHandlerInterface *iface)
+{
+    iface->Enable = mud_telnet_naws_enable;
+    iface->Disable = mud_telnet_naws_disable;
+    iface->HandleSubNeg = mud_telnet_naws_handle_sub_neg;
+}
+
+static void
+mud_telnet_naws_init (MudTelnetNaws *self)
+{
+    /* Get our private data */
+    self->priv = MUD_TELNET_NAWS_GET_PRIVATE(self);
+
+    /* Set the defaults */
+    self->priv->telnet = NULL;
+    self->priv->option = TELOPT_NAWS;
+    self->priv->enabled = FALSE;
+
+    self->priv->resized_signal = 0;
+}
+
+static GObject *
+mud_telnet_naws_constructor (GType gtype,
+                              guint n_properties,
+                              GObjectConstructParam *properties)
+{
+    MudTelnetNaws *self;
+    GObject *obj;
+    MudTelnetNawsClass *klass;
+    GObjectClass *parent_class;
+
+    /* Chain up to parent constructor */
+    klass = MUD_TELNET_NAWS_CLASS( g_type_class_peek(MUD_TYPE_TELNET_NAWS) );
+    parent_class = G_OBJECT_CLASS( g_type_class_peek_parent(klass) );
+    obj = parent_class->constructor(gtype, n_properties, properties);
+
+    self = MUD_TELNET_NAWS(obj);
+
+    if(!self->priv->telnet)
+    {
+        g_printf("ERROR: Tried to instantiate MudTelnetNaws without passing parent MudTelnet\n");
+        g_error("Tried to instantiate MudTelnetNaws without passing parent MudTelnet");
+    }
+
+    return obj;
+}
+
+static void
+mud_telnet_naws_finalize (GObject *object)
+{
+    MudTelnetNaws *self;
+    MudConnectionView *view;
+    MudWindow *window;
+    GObjectClass *parent_class;
+
+    self = MUD_TELNET_NAWS(object);
+
+    g_object_get(self->priv->telnet, "parent-view", &view, NULL);
+    g_object_get(view, "window", &window, NULL);
+
+    if(self->priv->resized_signal != 0)
+        g_signal_handler_disconnect(window, self->priv->resized_signal);
+
+    parent_class = g_type_class_peek_parent(G_OBJECT_GET_CLASS(object));
+    parent_class->finalize(object);
+}
+
+static void
+mud_telnet_naws_set_property(GObject *object,
+                              guint prop_id,
+                              const GValue *value,
+                              GParamSpec *pspec)
+{
+    MudTelnetNaws *self;
+
+    self = MUD_TELNET_NAWS(object);
+
+    switch(prop_id)
+    {
+        case PROP_TELNET:
+            self->priv->telnet = MUD_TELNET(g_value_get_object(value));
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+static void
+mud_telnet_naws_get_property(GObject *object,
+                              guint prop_id,
+                              GValue *value,
+                              GParamSpec *pspec)
+{
+    MudTelnetNaws *self;
+
+    self = MUD_TELNET_NAWS(object);
+
+    switch(prop_id)
+    {
+        case PROP_ENABLED:
+            g_value_set_boolean(value, self->priv->enabled);
+            break;
+
+        case PROP_HANDLES_OPTION:
+            g_value_set_int(value, self->priv->option);
+            break;
+
+        case PROP_TELNET:
+            g_value_take_object(value, self->priv->telnet);
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+/* Interface Implementation */
+void 
+mud_telnet_naws_enable(MudTelnetHandler *handler)
+{
+    MudTelnetNaws *self;
+    MudWindow *window;
+    MudConnectionView *view;
+    VteTerminal *terminal;
+
+    self = MUD_TELNET_NAWS(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_NAWS(self));
+
+    self->priv->enabled = TRUE;
+
+    g_object_get(self->priv->telnet, "parent-view", &view, NULL);
+
+    g_object_get(view,
+                 "terminal", &terminal, 
+                 "window", &window,
+                 NULL);
+
+    self->priv->resized_signal = 
+        g_signal_connect(window,
+                         "resized",
+                         G_CALLBACK(mud_telnet_naws_resized_cb),
+                         self);
+    
+    mud_telnet_naws_send(self,
+                         terminal->column_count,
+                         terminal->row_count);
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "NAWS Enabled");
+}
+
+void
+mud_telnet_naws_disable(MudTelnetHandler *handler)
+{
+    MudTelnetNaws *self;
+    MudWindow *window;
+    MudConnectionView *view;
+
+    self = MUD_TELNET_NAWS(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_NAWS(self));
+
+    self->priv->enabled = FALSE;
+
+    g_object_get(self->priv->telnet, "parent-view", &view, NULL);
+    g_object_get(view,
+                 "window", &window,
+                 NULL);
+
+    g_signal_handler_disconnect(window, self->priv->resized_signal);
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "NAWS Disabled");
+}
+
+void
+mud_telnet_naws_handle_sub_neg(MudTelnetHandler *handler,
+                               guchar *buf,
+                               guint len)
+{
+    MudTelnetNaws *self;
+
+    self = MUD_TELNET_NAWS(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_NAWS(self));
+
+    /* We never receive a NAWS subreq, we just send them */
+    return;
+}
+
+/* Callbacks */
+static void
+mud_telnet_naws_resized_cb(MudWindow *window,
+                           gint width,
+                           gint height,
+                           MudTelnetNaws *self)
+{
+    MudConnectionView *view;
+
+    g_object_get(self->priv->telnet,
+                 "parent-view", &view,
+                 NULL);
+
+    if(view->connection &&
+       gnet_conn_is_connected(view->connection) &&
+       self->priv->enabled)
+        mud_telnet_naws_send(self,
+                             view->terminal->column_count,
+                             view->terminal->row_count);
+}
+
+/* Private Methods */
+static void
+mud_telnet_naws_send(MudTelnetNaws *self, gint width, gint height)
+{
+    guchar w1, h1, w0, h0;
+    
+    g_return_if_fail(MUD_IS_TELNET_NAWS(self));
+
+    w1 = (width >> 8) & 0xff;
+    w0 = width & 0xff;
+
+    h1 = (height >> 8) & 0xff;
+    h0 = height & 0xff;
+
+    mud_telnet_send_sub_req(self->priv->telnet, 5,
+                            (guchar)self->priv->option,
+                            w1, w0, h1, h0);
+}
+

Added: trunk/src/handlers/mud-telnet-naws.h
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-naws.h	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,59 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-naws.h
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MUD_TELNET_NAWS_H
+#define MUD_TELNET_NAWS_H
+
+G_BEGIN_DECLS
+
+#include <glib.h>
+
+#define MUD_TYPE_TELNET_NAWS              (mud_telnet_naws_get_type ())
+#define MUD_TELNET_NAWS(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), MUD_TYPE_TELNET_NAWS, MudTelnetNaws))
+#define MUD_TELNET_NAWS_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), MUD_TYPE_TELNET_NAWS, MudTelnetNawsClass))
+#define MUD_IS_TELNET_NAWS(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), MUD_TYPE_TELNET_NAWS))
+#define MUD_IS_TELNET_NAWS_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), MUD_TYPE_TELNET_NAWS))
+#define MUD_TELNET_NAWS_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), MUD_TYPE_TELNET_NAWS, MudTelnetNawsClass))
+#define MUD_TELNET_NAWS_GET_PRIVATE(obj)  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUD_TYPE_TELNET_NAWS, MudTelnetNawsPrivate))
+
+typedef struct _MudTelnetNaws            MudTelnetNaws;
+typedef struct _MudTelnetNawsClass       MudTelnetNawsClass;
+typedef struct _MudTelnetNawsPrivate     MudTelnetNawsPrivate;
+
+struct _MudTelnetNawsClass
+{
+    GObjectClass parent_class;
+};
+
+struct _MudTelnetNaws
+{
+    GObject parent_instance;
+
+    /*< private >*/
+    MudTelnetNawsPrivate *priv;
+};
+
+GType mud_telnet_naws_get_type (void);
+
+
+
+G_END_DECLS
+
+#endif // MUD_TELNET_NAWS_H
+

Added: trunk/src/handlers/mud-telnet-new-environ.c
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-new-environ.c	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,435 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-new-environ.c
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+
+#include "gnome-mud.h"
+#include "mud-telnet.h"
+#include "mud-telnet-handler-interface.h"
+#include "mud-telnet-new-environ.h"
+
+struct _MudTelnetNewEnvironPrivate
+{
+    /* Interface Properties */
+    MudTelnet *telnet;
+    gboolean enabled;
+    gint option;
+
+    /* Private Instance Members */
+    GHashTable *new_environ_data;
+};
+
+/* Property Identifiers */
+enum
+{
+    PROP_MUD_TELNET_NEWENVIRON_0,
+    PROP_ENABLED,
+    PROP_HANDLES_OPTION,
+    PROP_TELNET,
+    PROP_ENVIRON
+};
+
+enum
+{
+    PARSE_STATE_VAR,
+    PARSE_STATE_VAR_STRING,
+    PARSE_STATE_VAL,
+    PARSE_STATE_VAL_STRING
+};
+
+/* Class Functions */
+static void mud_telnet_newenviron_init (MudTelnetNewEnviron *self);
+static void mud_telnet_newenviron_class_init (MudTelnetNewEnvironClass *klass);
+static void mud_telnet_newenviron_interface_init(MudTelnetHandlerInterface *iface);
+static void mud_telnet_newenviron_finalize (GObject *object);
+static GObject *mud_telnet_newenviron_constructor (GType gtype,
+                                             guint n_properties,
+                                             GObjectConstructParam *properties);
+static void mud_telnet_newenviron_set_property(GObject *object,
+                                         guint prop_id,
+                                         const GValue *value,
+                                         GParamSpec *pspec);
+static void mud_telnet_newenviron_get_property(GObject *object,
+                                         guint prop_id,
+                                         GValue *value,
+                                         GParamSpec *pspec);
+
+/*Interface Implementation */
+void mud_telnet_newenviron_enable(MudTelnetHandler *self);
+void mud_telnet_newenviron_disable(MudTelnetHandler *self);
+void mud_telnet_newenviron_handle_sub_neg(MudTelnetHandler *self,
+                                    guchar *buf,
+                                    guint len);
+
+/* Private Methods */
+static void mud_telnet_newenviron_destroy_key(gpointer k);
+static void mud_telnet_newenviron_destroy_value(gpointer c);
+
+/* Create the Type. We implement MudTelnetHandlerInterface */
+G_DEFINE_TYPE_WITH_CODE(MudTelnetNewEnviron, mud_telnet_newenviron, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (MUD_TELNET_HANDLER_TYPE,
+                                               mud_telnet_newenviron_interface_init));
+/* MudTelnetNewEnviron class functions */
+static void
+mud_telnet_newenviron_class_init (MudTelnetNewEnvironClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    /* Override base object constructor */
+    object_class->constructor = mud_telnet_newenviron_constructor;
+
+    /* Override base object's finalize */
+    object_class->finalize = mud_telnet_newenviron_finalize;
+
+    /* Override base object property methods */
+    object_class->set_property = mud_telnet_newenviron_set_property;
+    object_class->get_property = mud_telnet_newenviron_get_property;
+
+    /* Add private data to class */
+    g_type_class_add_private(klass, sizeof(MudTelnetNewEnvironPrivate));
+
+    /* Override Implementation Properties */
+    g_object_class_override_property(object_class,
+                                     PROP_ENABLED,
+                                     "enabled");
+
+    g_object_class_override_property(object_class,
+                                     PROP_HANDLES_OPTION,
+                                     "handles-option");
+
+    g_object_class_override_property(object_class,
+                                     PROP_TELNET,
+                                     "telnet");
+    /* Custom Class Properties */
+    g_object_class_install_property(object_class,
+                            PROP_ENVIRON,
+                            g_param_spec_pointer("new-environ-data",
+                                                 "NEW-ENVIRON Data",
+                                                 "The Environ data provided by the mud.",
+                                                 G_PARAM_READABLE));
+}
+
+static void
+mud_telnet_newenviron_interface_init(MudTelnetHandlerInterface *iface)
+{
+    iface->Enable = mud_telnet_newenviron_enable;
+    iface->Disable = mud_telnet_newenviron_disable;
+    iface->HandleSubNeg = mud_telnet_newenviron_handle_sub_neg;
+}
+
+static void
+mud_telnet_newenviron_init (MudTelnetNewEnviron *self)
+{
+    /* Get our private data */
+    self->priv = MUD_TELNET_NEWENVIRON_GET_PRIVATE(self);
+
+    /* Set the defaults */
+    self->priv->telnet = NULL;
+    self->priv->option = TELOPT_NEWENVIRON;
+    self->priv->enabled = FALSE;
+
+    self->priv->new_environ_data = NULL;
+}
+
+static GObject *
+mud_telnet_newenviron_constructor (GType gtype,
+                             guint n_properties,
+                             GObjectConstructParam *properties)
+{
+    MudTelnetNewEnviron *self;
+    GObject *obj;
+    MudTelnetNewEnvironClass *klass;
+    GObjectClass *parent_class;
+
+    /* Chain up to parent constructor */
+    klass = MUD_TELNET_NEWENVIRON_CLASS( g_type_class_peek(MUD_TYPE_TELNET_NEWENVIRON) );
+    parent_class = G_OBJECT_CLASS( g_type_class_peek_parent(klass) );
+    obj = parent_class->constructor(gtype, n_properties, properties);
+
+    self = MUD_TELNET_NEWENVIRON(obj);
+
+    if(!self->priv->telnet)
+    {
+        g_printf("ERROR: Tried to instantiate MudTelnetNewEnviron without passing parent MudTelnet\n");
+        g_error("Tried to instantiate MudTelnetNewEnviron without passing parent MudTelnet");
+    }
+
+    self->priv->new_environ_data =
+        g_hash_table_new_full(g_str_hash,
+                              g_str_equal,
+                              mud_telnet_newenviron_destroy_key,
+                              mud_telnet_newenviron_destroy_value);
+
+    return obj;
+}
+
+static void
+mud_telnet_newenviron_finalize (GObject *object)
+{
+    MudTelnetNewEnviron *self;
+    GObjectClass *parent_class;
+
+    self = MUD_TELNET_NEWENVIRON(object);
+
+    if(self->priv->new_environ_data)
+        g_hash_table_destroy(self->priv->new_environ_data);
+
+    parent_class = g_type_class_peek_parent(G_OBJECT_GET_CLASS(object));
+    parent_class->finalize(object);
+}
+
+static void
+mud_telnet_newenviron_set_property(GObject *object,
+                             guint prop_id,
+                             const GValue *value,
+                             GParamSpec *pspec)
+{
+    MudTelnetNewEnviron *self;
+
+    self = MUD_TELNET_NEWENVIRON(object);
+
+    switch(prop_id)
+    {
+        case PROP_TELNET:
+            self->priv->telnet = MUD_TELNET(g_value_get_object(value));
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+static void
+mud_telnet_newenviron_get_property(GObject *object,
+                             guint prop_id,
+                             GValue *value,
+                             GParamSpec *pspec)
+{
+    MudTelnetNewEnviron *self;
+
+    self = MUD_TELNET_NEWENVIRON(object);
+
+    switch(prop_id)
+    {
+        case PROP_ENABLED:
+            g_value_set_boolean(value, self->priv->enabled);
+            break;
+
+        case PROP_HANDLES_OPTION:
+            g_value_set_int(value, self->priv->option);
+            break;
+
+        case PROP_TELNET:
+            g_value_take_object(value, self->priv->telnet);
+            break;
+
+        case PROP_ENVIRON:
+            g_value_set_pointer(value, self->priv->new_environ_data);
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+/* Interface Implementation */
+void 
+mud_telnet_newenviron_enable(MudTelnetHandler *handler)
+{
+    MudTelnetNewEnviron *self;
+
+    self = MUD_TELNET_NEWENVIRON(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_NEWENVIRON(self));
+
+    self->priv->enabled = TRUE;
+
+    /* We are only interested in USERVAR */
+    mud_telnet_send_sub_req(self->priv->telnet,
+                            2,
+                            TEL_NEWENVIRON_SEND,
+                            TEL_NEWENVIRON_USERVAR);
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "NEWENVIRON Enabled");
+}
+
+void
+mud_telnet_newenviron_disable(MudTelnetHandler *handler)
+{
+    MudTelnetNewEnviron *self;
+
+    self = MUD_TELNET_NEWENVIRON(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_NEWENVIRON(self));
+
+    self->priv->enabled = FALSE;
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "NEWENVIRON Disabled");
+}
+
+void
+mud_telnet_newenviron_handle_sub_neg(MudTelnetHandler *handler,
+                               guchar *buf,
+                               guint len)
+{
+    MudTelnetNewEnviron *self;
+    guint i, state;
+    GString *key, *value;
+
+    self = MUD_TELNET_NEWENVIRON(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_NEWENVIRON(self));
+
+    /* IAC SB NEW-ENVIRON IS IAC SE is a valid response
+     * when there are no USERVARs. Nothing to parse,
+     * bail out. */
+    if(len == 1)
+        return;
+
+    state = PARSE_STATE_VAR;
+
+    /* The first byte will be either IS or INFO. Since INFO
+     * simply updates variables we do not need to make a
+     * distinction between the two in our case.*/
+    for(i = 1; i < len - 1; ++i)
+    {
+        switch(state)
+        {
+            case PARSE_STATE_VAR:
+                key = g_string_new(NULL);
+
+                state = PARSE_STATE_VAR_STRING;
+                break;
+
+            case PARSE_STATE_VAR_STRING:
+                if( buf[i] != TEL_NEWENVIRON_VALUE )
+                    key = g_string_append_c(key, buf[i]);
+                else
+                {
+                    if( i + 1 != len)
+                    {
+                        if( buf[ i + 1] != TEL_NEWENVIRON_VALUE )
+                        {
+                            /* No VALUE follows USERVAR/VAR. So it
+                             * is undefined. */
+                            g_string_free(key, TRUE);
+
+                            state == PARSE_STATE_VAR;
+                        }
+                        else
+                        {
+                            state = PARSE_STATE_VAL;
+                            i--;
+                        }
+                    }
+                }
+                break;
+
+            case PARSE_STATE_VAL:
+                value = g_string_new(NULL);
+
+                state = PARSE_STATE_VAL_STRING;
+                break;
+
+            case PARSE_STATE_VAL_STRING:
+                if( buf[i] != TEL_NEWENVIRON_VAR &&
+                    buf[i] != TEL_NEWENVIRON_USERVAR )
+                    value = g_string_append_c(value, buf[i]);
+                else
+                {
+                    switch( buf[i] )
+                    {
+                        /* We treat USERVARs and VARs the same. There
+                         * shouldn't be any VARs since we don't ask for
+                         * them but we'll check anyway. */
+                        case TEL_NEWENVIRON_USERVAR:
+                        case TEL_NEWENVIRON_VAR:
+                            g_hash_table_replace(self->priv->new_environ_data,
+                                    g_string_free(key, FALSE),
+                                    g_string_free(value, FALSE));
+
+                            state = PARSE_STATE_VAR;
+                            i--;
+                            break;
+                    }
+                }
+
+                if( i + 1 == len - 1) // Last value in subnegotiation.
+                    g_hash_table_replace(self->priv->new_environ_data,
+                                         g_string_free(key, FALSE),
+                                         g_string_free(value, FALSE));
+
+                break;
+        }
+    }
+
+    /* Log the results */
+    {
+        GList *key_list, *entry;
+
+        g_log("Telnet", G_LOG_LEVEL_MESSAGE, "%s", "NEW-ENVIRON Data:");
+
+        key_list = g_hash_table_get_keys(self->priv->new_environ_data);
+
+        entry = key_list;
+
+        while(entry)
+        {
+            const gchar *keyv = entry->data;
+            const gchar *valv = g_hash_table_lookup(self->priv->new_environ_data, keyv);
+
+            g_log("Telnet",
+                  G_LOG_LEVEL_MESSAGE,
+                  "\t%s = %s",
+                  keyv, (valv) ? valv : "<null>");
+
+            entry = g_list_next(entry);
+        }
+
+        g_list_free(key_list);
+    }
+}
+
+/* Private Methods */
+static void
+mud_telnet_newenviron_destroy_key(gpointer k)
+{
+    gchar *key = (gchar *)k;
+
+    if(key)
+        g_free(key);
+}
+
+static void
+mud_telnet_newenviron_destroy_value(gpointer v)
+{
+    gchar *value = (gchar *)v;
+
+    if(value)
+        g_free(value);
+}
+

Added: trunk/src/handlers/mud-telnet-new-environ.h
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-new-environ.h	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,57 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-new-environ.h
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MUD_TELNET_NEWENVIRON_H
+#define MUD_TELNET_NEWENVIRON_H
+
+G_BEGIN_DECLS
+
+#include <glib.h>
+
+#define MUD_TYPE_TELNET_NEWENVIRON              (mud_telnet_newenviron_get_type ())
+#define MUD_TELNET_NEWENVIRON(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), MUD_TYPE_TELNET_NEWENVIRON, MudTelnetNewEnviron))
+#define MUD_TELNET_NEWENVIRON_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), MUD_TYPE_TELNET_NEWENVIRON, MudTelnetNewEnvironClass))
+#define MUD_IS_TELNET_NEWENVIRON(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), MUD_TYPE_TELNET_NEWENVIRON))
+#define MUD_IS_TELNET_NEWENVIRON_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), MUD_TYPE_TELNET_NEWENVIRON))
+#define MUD_TELNET_NEWENVIRON_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), MUD_TYPE_TELNET_NEWENVIRON, MudTelnetNewEnvironClass))
+#define MUD_TELNET_NEWENVIRON_GET_PRIVATE(obj)  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUD_TYPE_TELNET_NEWENVIRON, MudTelnetNewEnvironPrivate))
+
+typedef struct _MudTelnetNewEnviron            MudTelnetNewEnviron;
+typedef struct _MudTelnetNewEnvironClass       MudTelnetNewEnvironClass;
+typedef struct _MudTelnetNewEnvironPrivate     MudTelnetNewEnvironPrivate;
+
+struct _MudTelnetNewEnvironClass
+{
+    GObjectClass parent_class;
+};
+
+struct _MudTelnetNewEnviron
+{
+    GObject parent_instance;
+
+    /*< private >*/
+    MudTelnetNewEnvironPrivate *priv;
+};
+
+GType mud_telnet_newenviron_get_type (void);
+
+G_END_DECLS
+
+#endif // MUD_TELNET_NEWENVIRON_H
+

Added: trunk/src/handlers/mud-telnet-ttype.c
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-ttype.c	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,317 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-ttype.c
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+
+#include "gnome-mud.h"
+#include "mud-telnet.h"
+#include "mud-telnet-handler-interface.h"
+#include "mud-telnet-ttype.h"
+
+struct _MudTelnetTTypePrivate
+{
+    /* Interface Properties */
+    MudTelnet *telnet;
+    gboolean enabled;
+    gint option;
+
+    /* Private Instance Members */
+    gint ttype_iteration;
+};
+
+/* Property Identifiers */
+enum
+{
+    PROP_MUD_TELNET_TTYPE_0,
+    PROP_ENABLED,
+    PROP_HANDLES_OPTION,
+    PROP_TELNET
+};
+
+/* Class Functions */
+static void mud_telnet_ttype_init (MudTelnetTType *self);
+static void mud_telnet_ttype_class_init (MudTelnetTTypeClass *klass);
+static void mud_telnet_ttype_interface_init(MudTelnetHandlerInterface *iface);
+static void mud_telnet_ttype_finalize (GObject *object);
+static GObject *mud_telnet_ttype_constructor (GType gtype,
+                                              guint n_properties,
+                                              GObjectConstructParam *properties);
+static void mud_telnet_ttype_set_property(GObject *object,
+                                          guint prop_id,
+                                          const GValue *value,
+                                          GParamSpec *pspec);
+static void mud_telnet_ttype_get_property(GObject *object,
+                                          guint prop_id,
+                                          GValue *value,
+                                          GParamSpec *pspec);
+
+/*Interface Implementation */
+void mud_telnet_ttype_enable(MudTelnetHandler *self);
+void mud_telnet_ttype_disable(MudTelnetHandler *self);
+void mud_telnet_ttype_handle_sub_neg(MudTelnetHandler *self,
+                                     guchar *buf,
+                                     guint len);
+
+/* Create the Type. We implement MudTelnetHandlerInterface */
+G_DEFINE_TYPE_WITH_CODE(MudTelnetTType, mud_telnet_ttype, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (MUD_TELNET_HANDLER_TYPE,
+                                               mud_telnet_ttype_interface_init));
+/* MudTelnetTType class functions */
+static void
+mud_telnet_ttype_class_init (MudTelnetTTypeClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    /* Override base object constructor */
+    object_class->constructor = mud_telnet_ttype_constructor;
+
+    /* Override base object's finalize */
+    object_class->finalize = mud_telnet_ttype_finalize;
+
+    /* Override base object property methods */
+    object_class->set_property = mud_telnet_ttype_set_property;
+    object_class->get_property = mud_telnet_ttype_get_property;
+
+    /* Add private data to class */
+    g_type_class_add_private(klass, sizeof(MudTelnetTTypePrivate));
+
+    /* Override Implementation Properties */
+    g_object_class_override_property(object_class,
+                                     PROP_ENABLED,
+                                     "enabled");
+
+    g_object_class_override_property(object_class,
+                                     PROP_HANDLES_OPTION,
+                                     "handles-option");
+
+    g_object_class_override_property(object_class,
+                                     PROP_TELNET,
+                                     "telnet");
+}
+
+static void
+mud_telnet_ttype_interface_init(MudTelnetHandlerInterface *iface)
+{
+    iface->Enable = mud_telnet_ttype_enable;
+    iface->Disable = mud_telnet_ttype_disable;
+    iface->HandleSubNeg = mud_telnet_ttype_handle_sub_neg;
+}
+
+static void
+mud_telnet_ttype_init (MudTelnetTType *self)
+{
+    /* Get our private data */
+    self->priv = MUD_TELNET_TTYPE_GET_PRIVATE(self);
+
+    /* Set the defaults */
+    self->priv->telnet = NULL;
+    self->priv->option = TELOPT_TTYPE;
+    self->priv->enabled = FALSE;
+}
+
+static GObject *
+mud_telnet_ttype_constructor (GType gtype,
+                              guint n_properties,
+                              GObjectConstructParam *properties)
+{
+    MudTelnetTType *self;
+    GObject *obj;
+    MudTelnetTTypeClass *klass;
+    GObjectClass *parent_class;
+
+    /* Chain up to parent constructor */
+    klass = MUD_TELNET_TTYPE_CLASS( g_type_class_peek(MUD_TYPE_TELNET_TTYPE) );
+    parent_class = G_OBJECT_CLASS( g_type_class_peek_parent(klass) );
+    obj = parent_class->constructor(gtype, n_properties, properties);
+
+    self = MUD_TELNET_TTYPE(obj);
+
+    if(!self->priv->telnet)
+    {
+        g_printf("ERROR: Tried to instantiate MudTelnetTType without passing parent MudTelnet\n");
+        g_error("Tried to instantiate MudTelnetTType without passing parent MudTelnet");
+    }
+
+    self->priv->ttype_iteration = 0;
+
+    return obj;
+}
+
+static void
+mud_telnet_ttype_finalize (GObject *object)
+{
+    MudTelnetTType *self;
+    GObjectClass *parent_class;
+
+    self = MUD_TELNET_TTYPE(object);
+
+    parent_class = g_type_class_peek_parent(G_OBJECT_GET_CLASS(object));
+    parent_class->finalize(object);
+}
+
+static void
+mud_telnet_ttype_set_property(GObject *object,
+                              guint prop_id,
+                              const GValue *value,
+                              GParamSpec *pspec)
+{
+    MudTelnetTType *self;
+
+    self = MUD_TELNET_TTYPE(object);
+
+    switch(prop_id)
+    {
+        case PROP_TELNET:
+            self->priv->telnet = MUD_TELNET(g_value_get_object(value));
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+static void
+mud_telnet_ttype_get_property(GObject *object,
+                              guint prop_id,
+                              GValue *value,
+                              GParamSpec *pspec)
+{
+    MudTelnetTType *self;
+
+    self = MUD_TELNET_TTYPE(object);
+
+    switch(prop_id)
+    {
+        case PROP_ENABLED:
+            g_value_set_boolean(value, self->priv->enabled);
+            break;
+
+        case PROP_HANDLES_OPTION:
+            g_value_set_int(value, self->priv->option);
+            break;
+
+        case PROP_TELNET:
+            g_value_take_object(value, self->priv->telnet);
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+/* Interface Implementation */
+void 
+mud_telnet_ttype_enable(MudTelnetHandler *handler)
+{
+    MudTelnetTType *self;
+
+    self = MUD_TELNET_TTYPE(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_TTYPE(self));
+
+    self->priv->enabled = TRUE;
+    self->priv->ttype_iteration = 0;
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "Terminal Type Enabled");
+}
+
+void
+mud_telnet_ttype_disable(MudTelnetHandler *handler)
+{
+    MudTelnetTType *self;
+
+    self = MUD_TELNET_TTYPE(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_TTYPE(self));
+
+    self->priv->enabled = FALSE;
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "Terminal Type Disabled");
+}
+
+void
+mud_telnet_ttype_handle_sub_neg(MudTelnetHandler *handler,
+                                guchar *buf,
+                                guint len)
+{
+    MudTelnetTType *self;
+
+    self = MUD_TELNET_TTYPE(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_TTYPE(self));
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "Sending Terminal Type");
+
+    if(self->priv->enabled)
+    {
+        switch(self->priv->ttype_iteration)
+        {
+            case 0:
+                mud_telnet_send_sub_req(self->priv->telnet, 11,
+                        (guchar)self->priv->option,
+                        (guchar)TEL_TTYPE_IS,
+                        'g','n','o','m','e','-','m','u','d');
+                self->priv->ttype_iteration++;
+                break;
+
+            case 1:
+                mud_telnet_send_sub_req(self->priv->telnet, 7,
+                        (guchar)TELOPT_TTYPE,
+                        (guchar)TEL_TTYPE_IS,
+                        'x','t','e','r','m');
+                self->priv->ttype_iteration++;
+                break;
+
+            case 2:
+                mud_telnet_send_sub_req(self->priv->telnet, 6,
+                        (guchar)TELOPT_TTYPE,
+                        (guchar)TEL_TTYPE_IS,
+                        'a','n','s','i');
+                self->priv->ttype_iteration++;
+                break;
+
+            case 3:
+                mud_telnet_send_sub_req(self->priv->telnet, 9,
+                        (guchar)TELOPT_TTYPE,
+                        (guchar)TEL_TTYPE_IS,
+                        'U','N','K','N','O','W','N');
+                self->priv->ttype_iteration++;
+                break;
+
+            /* RFC 1091 says we need to repeat the last type */
+            case 4:
+                mud_telnet_send_sub_req(self->priv->telnet, 9,
+                        (guchar)TELOPT_TTYPE,
+                        (gchar)TEL_TTYPE_IS,
+                        'U','N','K','N','O','W','N');
+                self->priv->ttype_iteration = 0;
+                break;
+
+        }
+    }
+}
+

Added: trunk/src/handlers/mud-telnet-ttype.h
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-ttype.h	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,57 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-ttype.h
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MUD_TELNET_TTYPE_H
+#define MUD_TELNET_TTYPE_H
+
+G_BEGIN_DECLS
+
+#include <glib.h>
+
+#define MUD_TYPE_TELNET_TTYPE              (mud_telnet_ttype_get_type ())
+#define MUD_TELNET_TTYPE(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), MUD_TYPE_TELNET_TTYPE, MudTelnetTType))
+#define MUD_TELNET_TTYPE_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), MUD_TYPE_TELNET_TTYPE, MudTelnetTTypeClass))
+#define MUD_IS_TELNET_TTYPE(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), MUD_TYPE_TELNET_TTYPE))
+#define MUD_IS_TELNET_TTYPE_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), MUD_TYPE_TELNET_TTYPE))
+#define MUD_TELNET_TTYPE_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), MUD_TYPE_TELNET_TTYPE, MudTelnetTTypeClass))
+#define MUD_TELNET_TTYPE_GET_PRIVATE(obj)  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUD_TYPE_TELNET_TTYPE, MudTelnetTTypePrivate))
+
+typedef struct _MudTelnetTType            MudTelnetTType;
+typedef struct _MudTelnetTTypeClass       MudTelnetTTypeClass;
+typedef struct _MudTelnetTTypePrivate     MudTelnetTTypePrivate;
+
+struct _MudTelnetTTypeClass
+{
+    GObjectClass parent_class;
+};
+
+struct _MudTelnetTType
+{
+    GObject parent_instance;
+
+    /*< private >*/
+    MudTelnetTTypePrivate *priv;
+};
+
+GType mud_telnet_ttype_get_type (void);
+
+G_END_DECLS
+
+#endif // MUD_TELNET_TTYPE_H
+

Added: trunk/src/handlers/mud-telnet-zmp.c
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-zmp.c	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,584 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-zmp.c
+ * Copyright (C) 2008-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <glib.h>
+#include <gnet.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "gnome-mud.h"
+#include "mud-telnet.h"
+#include "mud-telnet-handler-interface.h"
+#include "mud-telnet-zmp.h"
+
+struct _MudTelnetZmpPrivate
+{
+    /* Interface Properties */
+    MudTelnet *telnet;
+    gboolean enabled;
+    gint option;
+
+    /* Private Instance Members */
+    GHashTable *commands;
+};
+
+/* Property Identifiers */
+enum
+{
+    PROP_MUD_TELNET_ZMP_0,
+    PROP_ENABLED,
+    PROP_HANDLES_OPTION,
+    PROP_TELNET
+};
+
+/* Class Functions */
+static void mud_telnet_zmp_init (MudTelnetZmp *self);
+static void mud_telnet_zmp_class_init (MudTelnetZmpClass *klass);
+static void mud_telnet_zmp_interface_init(MudTelnetHandlerInterface *iface);
+static void mud_telnet_zmp_finalize (GObject *object);
+static GObject *mud_telnet_zmp_constructor (GType gtype,
+                                             guint n_properties,
+                                             GObjectConstructParam *properties);
+static void mud_telnet_zmp_set_property(GObject *object,
+                                         guint prop_id,
+                                         const GValue *value,
+                                         GParamSpec *pspec);
+static void mud_telnet_zmp_get_property(GObject *object,
+                                         guint prop_id,
+                                         GValue *value,
+                                         GParamSpec *pspec);
+
+/*Interface Implementation */
+void mud_telnet_zmp_enable(MudTelnetHandler *self);
+void mud_telnet_zmp_disable(MudTelnetHandler *self);
+void mud_telnet_zmp_handle_sub_neg(MudTelnetHandler *self,
+                                    guchar *buf,
+                                    guint len);
+
+/* Create the Type. We implement MudTelnetHandlerInterface */
+G_DEFINE_TYPE_WITH_CODE(MudTelnetZmp, mud_telnet_zmp, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (MUD_TELNET_HANDLER_TYPE,
+                                               mud_telnet_zmp_interface_init));
+
+/* Private Methods */
+static void mud_zmp_register_core_functions(MudTelnetZmp *self);
+static void mud_zmp_send_command(MudTelnetZmp *self, guint32 count, ...);
+static void mud_zmp_destroy_key(gpointer k);
+static void mud_zmp_destroy_command(gpointer c);
+static gboolean mud_zmp_has_command(MudTelnetZmp *self, gchar *name);
+static gboolean mud_zmp_has_package(MudTelnetZmp *self, gchar *package);
+static MudZMPFunction mud_zmp_get_function(MudTelnetZmp *self, gchar *name);
+
+/* Core ZMP Functions */
+static void ZMP_ident(MudTelnetZmp *self, gint argc, gchar **argv);
+static void ZMP_ping_and_time(MudTelnetZmp *self, gint argc, gchar **argv);
+static void ZMP_check(MudTelnetZmp *self, gint argc, gchar **argv);
+
+/* MudTelnetZmp class functions */
+static void
+mud_telnet_zmp_class_init (MudTelnetZmpClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    /* Override base object constructor */
+    object_class->constructor = mud_telnet_zmp_constructor;
+
+    /* Override base object's finalize */
+    object_class->finalize = mud_telnet_zmp_finalize;
+
+    /* Override base object property methods */
+    object_class->set_property = mud_telnet_zmp_set_property;
+    object_class->get_property = mud_telnet_zmp_get_property;
+
+    /* Add private data to class */
+    g_type_class_add_private(klass, sizeof(MudTelnetZmpPrivate));
+
+    /* Override Implementation Properties */
+    g_object_class_override_property(object_class,
+                                     PROP_ENABLED,
+                                     "enabled");
+
+    g_object_class_override_property(object_class,
+                                     PROP_HANDLES_OPTION,
+                                     "handles-option");
+
+    g_object_class_override_property(object_class,
+                                     PROP_TELNET,
+                                     "telnet");
+}
+
+static void
+mud_telnet_zmp_interface_init(MudTelnetHandlerInterface *iface)
+{
+    iface->Enable = mud_telnet_zmp_enable;
+    iface->Disable = mud_telnet_zmp_disable;
+    iface->HandleSubNeg = mud_telnet_zmp_handle_sub_neg;
+}
+
+static void
+mud_telnet_zmp_init (MudTelnetZmp *self)
+{
+    /* Get our private data */
+    self->priv = MUD_TELNET_ZMP_GET_PRIVATE(self);
+
+    /* Set the defaults */
+    self->priv->telnet = NULL;
+    self->priv->option = TELOPT_ZMP;
+    self->priv->enabled = FALSE;
+}
+
+static GObject *
+mud_telnet_zmp_constructor (GType gtype,
+                            guint n_properties,
+                            GObjectConstructParam *properties)
+{
+    MudTelnetZmp *self;
+    GObject *obj;
+    MudTelnetZmpClass *klass;
+    GObjectClass *parent_class;
+
+    /* Chain up to parent constructor */
+    klass = MUD_TELNET_ZMP_CLASS( g_type_class_peek(MUD_TYPE_TELNET_ZMP) );
+    parent_class = G_OBJECT_CLASS( g_type_class_peek_parent(klass) );
+    obj = parent_class->constructor(gtype, n_properties, properties);
+
+    self = MUD_TELNET_ZMP(obj);
+
+    if(!self->priv->telnet)
+    {
+        g_printf("ERROR: Tried to instantiate MudTelnetZmp without passing parent MudTelnet\n");
+        g_error("Tried to instantiate MudTelnetZmp without passing parent MudTelnet");
+    }
+
+    self->priv->commands = g_hash_table_new_full(g_str_hash,
+                                                 g_str_equal,
+                                                 mud_zmp_destroy_key,
+                                                 mud_zmp_destroy_command);
+
+    mud_zmp_register_core_functions(self);
+
+    return obj;
+}
+
+static void
+mud_telnet_zmp_finalize (GObject *object)
+{
+    MudTelnetZmp *self;
+    GObjectClass *parent_class;
+
+    self = MUD_TELNET_ZMP(object);
+
+    if(self->priv->commands)
+        g_hash_table_destroy(self->priv->commands);
+
+    parent_class = g_type_class_peek_parent(G_OBJECT_GET_CLASS(object));
+    parent_class->finalize(object);
+}
+
+static void
+mud_telnet_zmp_set_property(GObject *object,
+                              guint prop_id,
+                              const GValue *value,
+                              GParamSpec *pspec)
+{
+    MudTelnetZmp *self;
+
+    self = MUD_TELNET_ZMP(object);
+
+    switch(prop_id)
+    {
+        case PROP_TELNET:
+            self->priv->telnet = MUD_TELNET(g_value_get_object(value));
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+static void
+mud_telnet_zmp_get_property(GObject *object,
+                              guint prop_id,
+                              GValue *value,
+                              GParamSpec *pspec)
+{
+    MudTelnetZmp *self;
+
+    self = MUD_TELNET_ZMP(object);
+
+    switch(prop_id)
+    {
+        case PROP_ENABLED:
+            g_value_set_boolean(value, self->priv->enabled);
+            break;
+
+        case PROP_HANDLES_OPTION:
+            g_value_set_int(value, self->priv->option);
+            break;
+
+        case PROP_TELNET:
+            g_value_take_object(value, self->priv->telnet);
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+            break;
+    }
+}
+
+/* Interface Implementation */
+void 
+mud_telnet_zmp_enable(MudTelnetHandler *handler)
+{
+    MudTelnetZmp *self;
+
+    self = MUD_TELNET_ZMP(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_ZMP(self));
+
+    self->priv->enabled = TRUE;
+
+    g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "ZMP Enabled");
+}
+
+void
+mud_telnet_zmp_disable(MudTelnetHandler *handler)
+{
+    MudTelnetZmp *self;
+
+    self = MUD_TELNET_ZMP(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_ZMP(self));
+
+    /* Cannot disable ZMP once enabled per specification */
+    return;
+
+}
+
+void
+mud_telnet_zmp_handle_sub_neg(MudTelnetHandler *handler,
+                              guchar *buf,
+                              guint len)
+{
+    guint i;
+    gint argc;
+    gchar **argv;
+    GString *args;
+    MudZMPFunction zmp_handler = NULL;
+    MudTelnetZmp *self = MUD_TELNET_ZMP(handler);
+
+    g_return_if_fail(MUD_IS_TELNET_ZMP(self));
+
+    /* Count Strings */
+    for(i = 0; i < len; ++i)
+        if(buf[i] == '\0')
+            ++argc;
+
+    argv = g_new0(gchar *, argc);
+    argc = 0;
+    args = g_string_new(NULL);
+
+    for(i = 0; i < len; ++i)
+    {
+        if(buf[i] == '\0')
+        {
+            argv[argc++] = g_string_free(args, FALSE);
+            args = g_string_new(NULL);
+            continue;
+        }
+
+        args = g_string_append_c(args, buf[i]);
+    }
+
+    g_string_free(args, TRUE);
+
+    g_log("Telnet", G_LOG_LEVEL_MESSAGE, "Received: ZMP Command: %s", argv[0]);
+    for(i = 1; i < argc; ++i)
+        g_log("Telnet", G_LOG_LEVEL_MESSAGE, "\t%s", argv[i]);
+
+    if(mud_zmp_has_command(self, argv[0]))
+    {
+        zmp_handler = mud_zmp_get_function(self, argv[0]);
+
+        if(zmp_handler)
+            zmp_handler(self, argc, argv);
+        else
+            g_warning("NULL ZMP functioned returned.");
+    }
+    else
+        g_warning("Server sent unsupported ZMP command. Bad server, bad.");
+
+    for(i = 0; i < argc; ++i)
+        g_free(argv[i]);
+
+    g_free(argv);
+}
+
+/* Private Methods */
+static void
+mud_zmp_send_command(MudTelnetZmp *self, guint32 count, ...)
+{
+    guchar byte;
+    guint32 i;
+    guint32 j;
+    guchar null = '\0';
+    va_list va;
+    gchar *arg;
+    GConn *conn;
+
+    g_return_if_fail(MUD_IS_TELNET_ZMP(self));
+
+    g_object_get(self->priv->telnet, "connection", &conn, NULL);
+
+    va_start(va, count);
+
+    g_log("Telnet", G_LOG_LEVEL_DEBUG, "Sending ZMP Command:");
+
+    byte = (guchar)TEL_IAC;
+    gnet_conn_write(conn, (gchar *)&byte, 1);
+    byte = (guchar)TEL_SB;
+    gnet_conn_write(conn, (gchar *)&byte, 1);
+    byte = (guchar)TELOPT_ZMP;
+    gnet_conn_write(conn, (gchar *)&byte, 1);
+
+    for (i = 0; i < count; ++i)
+    {
+        arg = (gchar *)va_arg(va, gchar *);
+
+        g_log("Telnet", G_LOG_LEVEL_DEBUG, "\t%s", arg);
+
+        for(j = 0; j < strlen(arg); ++j)
+        {
+            byte = (guchar)arg[j];
+
+            gnet_conn_write(conn, (gchar *)&byte, 1);
+
+            if (byte == (guchar)TEL_IAC)
+                gnet_conn_write(conn, (gchar *)&byte, 1);
+        }
+
+        gnet_conn_write(conn, (gchar *)&null, 1);
+    }
+
+    va_end(va);
+
+    byte = (guchar)TEL_IAC;
+    gnet_conn_write(conn, (gchar *)&byte, 1);
+    byte = (guchar)TEL_SE;
+    gnet_conn_write(conn, (gchar *)&byte, 1);
+}
+
+static void
+mud_zmp_register_core_functions(MudTelnetZmp *self)
+{
+    g_return_if_fail(MUD_IS_TELNET_ZMP(self));
+
+    mud_zmp_register(self, mud_zmp_new_command("zmp.",
+                                               "zmp.ident",
+                                               ZMP_ident));
+    mud_zmp_register(self, mud_zmp_new_command("zmp.",
+                                               "zmp.ping",
+                                               ZMP_ping_and_time));
+    mud_zmp_register(self, mud_zmp_new_command("zmp.",
+                                               "zmp.time",
+                                               ZMP_ping_and_time));
+    mud_zmp_register(self, mud_zmp_new_command("zmp.",
+                                               "zmp.check",
+                                               ZMP_check));
+}
+
+static void
+mud_zmp_destroy_key(gpointer k)
+{
+    gchar *key = (gchar *)k;
+
+    if(key)
+        g_free(key);
+}
+
+static void
+mud_zmp_destroy_command(gpointer c)
+{
+    MudZMPCommand *command = (MudZMPCommand *)c;
+
+    if(command)
+    {
+        if(command->name)
+            g_free(command->name);
+
+        if(command->package)
+            g_free(command->package);
+
+        g_free(command);
+    }
+}
+
+static gboolean
+mud_zmp_has_command(MudTelnetZmp *self, gchar *name)
+{
+    if(!MUD_IS_TELNET_ZMP(self))
+        return FALSE;
+
+    return !(g_hash_table_lookup(self->priv->commands, name) == NULL);
+}
+
+static gboolean
+mud_zmp_has_package(MudTelnetZmp *self, gchar *package)
+{
+    GList *keys;
+    GList *iter;
+
+    g_return_if_fail(MUD_IS_TELNET_ZMP(self));
+
+    keys = g_hash_table_get_keys(self->priv->commands);
+
+    for(iter = g_list_first(keys); iter != NULL; iter = g_list_next(iter))
+    {
+        MudZMPCommand *command =
+            (MudZMPCommand *)g_hash_table_lookup(self->priv->commands,
+                    (gchar *)iter->data);
+
+        if(g_str_equal(command->package, package))
+        {
+            g_list_free(keys);
+            return TRUE;
+        }
+    }
+
+    g_list_free(keys);
+
+    return FALSE;
+}
+
+static MudZMPFunction
+mud_zmp_get_function(MudTelnetZmp *self, gchar *name)
+{
+    MudZMPFunction ret = NULL;
+    MudZMPCommand *val;
+
+    g_return_if_fail(MUD_IS_TELNET_ZMP(self));
+
+    if(!mud_zmp_has_command(self, name))
+        return NULL;
+
+    val = (MudZMPCommand *)g_hash_table_lookup(self->priv->commands, name);
+
+    if(val)
+        ret = (MudZMPFunction)val->execute;
+
+    return ret;
+}
+
+
+/* Core ZMP Functions */
+static void
+ZMP_ident(MudTelnetZmp *self, gint argc, gchar **argv)
+{
+    g_return_if_fail(MUD_IS_TELNET_ZMP(self));
+
+    mud_zmp_send_command(self, 4,
+            "zmp.ident", "gnome-mud", VERSION,
+            "A mud client written for the GNOME environment.");
+}
+
+static void
+ZMP_ping_and_time(MudTelnetZmp *self, gint argc, gchar **argv)
+{
+    time_t t;
+    gchar time_buffer[128];
+
+    g_return_if_fail(MUD_IS_TELNET_ZMP(self));
+
+    time(&t);
+
+    strftime(time_buffer, sizeof(time_buffer),
+            "%Y-%m-%d %H:%M:%S", gmtime(&t));
+
+    mud_zmp_send_command(self, 2, "zmp.time", time_buffer);
+}
+
+static void
+ZMP_check(MudTelnetZmp *self, gint argc, gchar **argv)
+{
+    gchar *item;
+
+    g_return_if_fail(MUD_IS_TELNET_ZMP(self));
+
+    if(argc < 2)
+        return; // Malformed ZMP_Check
+
+    item = argv[1];
+
+    if(item[strlen(item) - 1] == '.') // Check for package.
+    {
+        if(mud_zmp_has_package(self, item))
+            mud_zmp_send_command(self, 2, "zmp.support", item);
+        else
+            mud_zmp_send_command(self, 2, "zmp.no-support", item);
+    }
+    else // otherwise command
+    {
+        if(mud_zmp_has_command(self, item))
+            mud_zmp_send_command(self, 2, "zmp.support", item);
+        else
+            mud_zmp_send_command(self, 2, "zmp.no-support", item);
+    }
+}
+
+/* Public Methods */
+void
+mud_zmp_register(MudTelnetZmp *self, MudZMPCommand *command)
+{
+    g_return_if_fail(MUD_IS_TELNET_ZMP(self));
+
+    if(!command)
+        return;
+
+    if(mud_zmp_has_command(self, command->name))
+        return; // Function already registered.
+
+    g_hash_table_replace(self->priv->commands,
+                         g_strdup(command->name),
+                         command);
+}
+
+MudZMPCommand *
+mud_zmp_new_command(const gchar *package,
+                    const gchar *name,
+                    MudZMPFunction execute)
+{
+    MudZMPCommand *new_command = g_new0(MudZMPCommand, 1);
+
+    if(!new_command)
+        return NULL;
+
+    new_command->name = g_strdup(name);
+    new_command->package = g_strdup(package);
+    new_command->execute = execute;
+
+    return new_command;
+}
+

Added: trunk/src/handlers/mud-telnet-zmp.h
==============================================================================
--- (empty file)
+++ trunk/src/handlers/mud-telnet-zmp.h	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,70 @@
+/* GNOME-Mud - A simple Mud Client
+ * mud-telnet-zmp.h
+ * Copyright (C) 2005-2009 Les Harris <lharris gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MUD_TELNET_ZMP_H
+#define MUD_TELNET_ZMP_H
+
+G_BEGIN_DECLS
+
+#include <glib.h>
+
+#define MUD_TYPE_TELNET_ZMP              (mud_telnet_zmp_get_type ())
+#define MUD_TELNET_ZMP(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), MUD_TYPE_TELNET_ZMP, MudTelnetZmp))
+#define MUD_TELNET_ZMP_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), MUD_TYPE_TELNET_ZMP, MudTelnetZmpClass))
+#define MUD_IS_TELNET_ZMP(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), MUD_TYPE_TELNET_ZMP))
+#define MUD_IS_TELNET_ZMP_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), MUD_TYPE_TELNET_ZMP))
+#define MUD_TELNET_ZMP_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), MUD_TYPE_TELNET_ZMP, MudTelnetZmpClass))
+#define MUD_TELNET_ZMP_GET_PRIVATE(obj)  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUD_TYPE_TELNET_ZMP, MudTelnetZmpPrivate))
+
+typedef struct _MudTelnetZmp            MudTelnetZmp;
+typedef struct _MudTelnetZmpClass       MudTelnetZmpClass;
+typedef struct _MudTelnetZmpPrivate     MudTelnetZmpPrivate;
+
+struct _MudTelnetZmpClass
+{
+    GObjectClass parent_class;
+};
+
+struct _MudTelnetZmp
+{
+    GObject parent_instance;
+
+    /*< private >*/
+    MudTelnetZmpPrivate *priv;
+};
+
+typedef void(*MudZMPFunction)(MudTelnetZmp *self, gint argc, gchar **argv);
+
+typedef struct MudZMPCommand
+{
+    gchar *package;
+    gchar *name;
+    MudZMPFunction execute;
+} MudZMPCommand;
+
+GType mud_telnet_zmp_get_type (void);
+
+MudZMPCommand* mud_zmp_new_command(const gchar *package,
+                                   const gchar *name,
+                                   MudZMPFunction execute);
+
+void mud_zmp_register(MudTelnetZmp *self, MudZMPCommand *command);
+
+#endif // MUD_TELNET_ZMP_H
+

Modified: trunk/src/mud-connection-view.c
==============================================================================
--- trunk/src/mud-connection-view.c	(original)
+++ trunk/src/mud-connection-view.c	Tue Mar 17 18:08:13 2009
@@ -39,9 +39,7 @@
 #include "mud-parse-base.h"
 #include "mud-telnet.h"
 
-#ifdef ENABLE_GST
-#include "mud-telnet-msp.h"
-#endif
+#include "handlers/mud-telnet-handlers.h"
 
 struct _MudConnectionViewPrivate
 {

Modified: trunk/src/mud-telnet.c
==============================================================================
--- trunk/src/mud-telnet.c	(original)
+++ trunk/src/mud-telnet.c	Tue Mar 17 18:08:13 2009
@@ -33,23 +33,7 @@
 #include "mud-telnet.h"
 
 /* Handlers */
-#include "mud-telnet-handler-interface.h"
-#include "mud-telnet-ttype.h"
-#include "mud-telnet-naws.h"
-#include "mud-telnet-echo.h"
-#include "mud-telnet-eor.h"
-#include "mud-telnet-charset.h"
-#include "mud-telnet-zmp.h"
-#include "mud-telnet-mssp.h"
-#include "mud-telnet-new-environ.h"
-
-#ifdef ENABLE_GST
-#include "mud-telnet-msp.h"
-#endif
-
-#ifdef ENABLE_MCCP
-#include "mud-telnet-mccp.h"
-#endif
+#include "handlers/mud-telnet-handlers.h"
 
 struct _MudTelnetPrivate
 {

Modified: trunk/src/mud-telnet.h
==============================================================================
--- trunk/src/mud-telnet.h	(original)
+++ trunk/src/mud-telnet.h	Tue Mar 17 18:08:13 2009
@@ -108,7 +108,7 @@
 
 #include <gnet.h>
 #include "mud-connection-view.h"
-#include "mud-telnet-handler-interface.h"
+#include "handlers/mud-telnet-handlers.h"
 
 enum TelnetState
 {

Added: trunk/src/zmp/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/src/zmp/Makefile.am	Tue Mar 17 18:08:13 2009
@@ -0,0 +1,24 @@
+NULL =
+
+noinst_LTLIBRARIES = libzmpcommands.la
+
+libzmpcommands_la_SOURCES = \
+	zmp-subwindow.c \
+	zmp-subwindow.h \
+	$(NULL)
+
+libzmpcommands_la_CPPFLAGS = \
+	-I$(srcdir)/.. \
+	$(AM_CPPFLAGS)
+
+libzmpcommands_la_CFLAGS = \
+	$(GMUD_CFLAGS) \
+	$(MSP_CFLAGS)
+
+libzmpcommands_la_LDFLAGS =
+
+libzmpcommands_la_LIBADD = \
+	$(GMUD_LIBS) \
+	$(MSP_LIBS) \
+	$(Z_LIBS)
+

Added: trunk/src/zmp/zmp-subwindow.c
==============================================================================

Added: trunk/src/zmp/zmp-subwindow.h
==============================================================================



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]