[gnome-mud] Git now current with svn.



commit 9b6c50e60df782ed9f7309451b78a9d83d6f5042
Author: Les Harris <lharris gnome org>
Date:   Sun Apr 19 17:17:50 2009 -0700

    Git now current with svn.
---
 src/gnome-mud-marshallers.list     |    1 +
 src/gnome-mud.c                    |   18 ++-
 src/handlers/mud-telnet-handlers.h |    1 +
 src/handlers/mud-telnet-msp.c      |  114 ++++---------
 src/handlers/mud-telnet-msp.h      |    4 +-
 src/handlers/mud-telnet-naws.c     |   18 ++-
 src/handlers/mud-telnet-naws.h     |    2 +-
 src/mud-connection-view.c          |  282 +++++++++++++++++++++----------
 src/mud-connection-view.h          |    4 +
 src/mud-line-buffer.c              |  141 +++++++++++++---
 src/mud-line-buffer.h              |   43 ++++--
 src/mud-log.c                      |   11 +-
 src/mud-log.h                      |    2 +-
 src/mud-subwindow.c                |   54 +++++-
 src/mud-subwindow.h                |    1 +
 src/mud-telnet.c                   |   19 ++-
 src/mud-telnet.h                   |   31 ++++
 src/mud-trigger.c                  |  330 ++++++++++++++++++++++++++----------
 src/mud-trigger.h                  |    7 +-
 src/mud-window.c                   |   27 +++-
 src/zmp/zmp-subwindow.c            |   27 +++
 21 files changed, 809 insertions(+), 328 deletions(-)

diff --git a/src/gnome-mud-marshallers.list b/src/gnome-mud-marshallers.list
index d023d1a..0c8d9c3 100644
--- a/src/gnome-mud-marshallers.list
+++ b/src/gnome-mud-marshallers.list
@@ -1,3 +1,4 @@
 VOID:INT,INT
 VOID:UINT,UINT
 VOID:STRING,UINT
+VOID:POINTER,UINT
diff --git a/src/gnome-mud.c b/src/gnome-mud.c
index 8bf20da..bf88bdb 100644
--- a/src/gnome-mud.c
+++ b/src/gnome-mud.c
@@ -121,22 +121,30 @@ main (gint argc, char *argv[])
     window = g_object_new(MUD_TYPE_WINDOW, NULL);
 
     {
+        MudLineBufferLine *line = g_new0(MudLineBufferLine, 1);
         MudTrigger *trigger = g_object_new(MUD_TYPE_TRIGGER,
                                            "trigger-key", "test",
                                            "profile-key", "test",
-                                           "lines", 3,
+                                           "lines", 1,
                                            "action-type", MUD_TRIGGER_ACTION_TEXT,
-                                           "action", "\n=== %0 ===\n=== %1 ===\n",
+                                           "action", "=== %0 ===\n\t%1\n\t%2",
                                            NULL);
 
-        gchar *test_line = g_strdup("Foo says, \"Bar\"\n");
+        line->line = g_strdup("Foo says, \"foobazbar\"");
 
-        mud_trigger_add_data(trigger, test_line, strlen(test_line));
+        mud_trigger_execute(trigger, line, strlen(line->line));
 
-        g_free(test_line);
+        g_free(line->line);
+        g_free(line);
         g_object_unref(trigger);
     }
 
+    {
+        g_printf("%c%c%d%c%d%c%d%c", '\x1B', '[', 1 , ';', 36, ';', 40, 'm');
+        g_printf("%s", "test");
+        g_printf("%c%c%d%c\n", '\x1B', '[', 0, 'm');
+    }
+
     gtk_main();
 
     gconf_client_suggest_sync(client, &err);
diff --git a/src/handlers/mud-telnet-handlers.h b/src/handlers/mud-telnet-handlers.h
index 6e0f916..7dc87d8 100644
--- a/src/handlers/mud-telnet-handlers.h
+++ b/src/handlers/mud-telnet-handlers.h
@@ -44,6 +44,7 @@ G_BEGIN_DECLS
 #include "mud-telnet-new-environ.h"
 #include "mud-telnet-ttype.h"
 #include "mud-telnet-zmp.h"
+#include "mud-telnet-aardwolf.h"
 
 G_END_DECLS
 
diff --git a/src/handlers/mud-telnet-msp.c b/src/handlers/mud-telnet-msp.c
index ce2862e..80971d3 100644
--- a/src/handlers/mud-telnet-msp.c
+++ b/src/handlers/mud-telnet-msp.c
@@ -34,6 +34,7 @@
 #include "mud-telnet.h"
 #include "mud-telnet-handler-interface.h"
 #include "mud-telnet-msp.h"
+#include "mud-line-buffer.h"
 
 struct _MudTelnetMspPrivate
 {
@@ -365,93 +366,51 @@ mud_telnet_msp_parser_clear(MudTelnetMsp *self)
     self->priv->msp_parser.output = g_string_new(NULL);
 }
 
-GString *
-mud_telnet_msp_parse(MudTelnetMsp *self, GString *buf, gint *len)
+void
+mud_telnet_msp_parse(MudTelnetMsp *self, MudLineBufferLine *line)
 {
-    gint count;
-    GString *ret = NULL;
+    guint len = strlen(line->line);
+    gchar *buf = line->line;
 
-    if(!MUD_IS_TELNET_MSP(self))
-        return NULL;
+    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)
+    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] == '!')
+                if(buf[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++]);
-                }
+                    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;
-                }
+                if(buf[self->priv->msp_parser.lex_pos_start + 1] != '!')
+                    return;
 
                 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')
+                if(buf[self->priv->msp_parser.lex_pos_start + 2] == 'S' &&
+                        buf[self->priv->msp_parser.lex_pos_start + 3] == 'O' &&
+                        buf[self->priv->msp_parser.lex_pos_start + 4] == 'U' &&
+                        buf[self->priv->msp_parser.lex_pos_start + 5] == 'N' &&
+                        buf[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')
+                else if(buf[self->priv->msp_parser.lex_pos_start + 2] == 'M' &&
+                        buf[self->priv->msp_parser.lex_pos_start + 3] == 'U' &&
+                        buf[self->priv->msp_parser.lex_pos_start + 4] == 'S' &&
+                        buf[self->priv->msp_parser.lex_pos_start + 5] == 'I' &&
+                        buf[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;
+                    return;
                 }
 
                 // Skip leading (
@@ -461,19 +420,20 @@ mud_telnet_msp_parse(MudTelnetMsp *self, GString *buf, gint *len)
                 break;
 
             case MSP_STATE_GET_ARGS:
-                self->priv->msp_parser.lex_pos_end = self->priv->msp_parser.lex_pos_start;
+                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] != ')')
+                while(self->priv->msp_parser.lex_pos_end < len &&
+                        buf[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++]);
+                                buf[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] != ')')
+                if(self->priv->msp_parser.lex_pos_end >= len &&
+                        buf[self->priv->msp_parser.lex_pos_end - 1] != ')')
                 {
                     self->priv->msp_parser.lex_pos_start =
                         self->priv->msp_parser.lex_pos_end;
@@ -492,20 +452,12 @@ mud_telnet_msp_parse(MudTelnetMsp *self, GString *buf, gint *len)
                 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;
-    }
+                line->gag = TRUE;
 
-    g_string_free(buf, TRUE);
-    *(&buf) = NULL;
-
-    return ret;
+                return;
+        }
+    }
 }
 
 void
diff --git a/src/handlers/mud-telnet-msp.h b/src/handlers/mud-telnet-msp.h
index b8dbf1c..c47225b 100644
--- a/src/handlers/mud-telnet-msp.h
+++ b/src/handlers/mud-telnet-msp.h
@@ -41,6 +41,8 @@ typedef struct _MudTelnetMsp            MudTelnetMsp;
 typedef struct _MudTelnetMspClass       MudTelnetMspClass;
 typedef struct _MudTelnetMspPrivate     MudTelnetMspPrivate;
 
+#include "mud-line-buffer.h"
+
 struct _MudTelnetMspClass
 {
     GObjectClass parent_class;
@@ -139,7 +141,7 @@ typedef struct 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_parse(MudTelnetMsp *self, MudLineBufferLine *line);
 void mud_telnet_msp_stop_playing(MudTelnetMsp *self, MudMSPTypes type);
 void mud_telnet_msp_parser_clear(MudTelnetMsp *self);
 
diff --git a/src/handlers/mud-telnet-naws.c b/src/handlers/mud-telnet-naws.c
index 36d3504..4b5ccf5 100644
--- a/src/handlers/mud-telnet-naws.c
+++ b/src/handlers/mud-telnet-naws.c
@@ -187,10 +187,10 @@ mud_telnet_naws_finalize (GObject *object)
 
     self = MUD_TELNET_NAWS(object);
 
-    if(self->priv->resized_signal != 0)
+    if(self->priv->resized_signal != 0 && IS_MUD_WINDOW(self->priv->window))
         g_signal_handler_disconnect(self->priv->window, self->priv->resized_signal);
 
-    if(self->priv->delete_signal != 0)
+    if(self->priv->delete_signal != 0 && GTK_IS_WIDGET(self->priv->main_window))
         g_signal_handler_disconnect(self->priv->main_window, self->priv->delete_signal);
 
     parent_class = g_type_class_peek_parent(G_OBJECT_GET_CLASS(object));
@@ -389,3 +389,17 @@ mud_telnet_naws_delete_event_cb(GtkWidget *widget,
     return FALSE;
 }
 
+void
+mud_telnet_naws_disconnect_signals(MudTelnetNaws *self)
+{
+
+    if(self->priv->resized_signal != 0)
+        g_signal_handler_disconnect(self->priv->window, self->priv->resized_signal);
+
+    if(self->priv->delete_signal != 0)
+        g_signal_handler_disconnect(self->priv->main_window, self->priv->delete_signal);
+
+    self->priv->resized_signal = 0;
+    self->priv->delete_signal = 0;
+}
+
diff --git a/src/handlers/mud-telnet-naws.h b/src/handlers/mud-telnet-naws.h
index c125b99..1dc8426 100644
--- a/src/handlers/mud-telnet-naws.h
+++ b/src/handlers/mud-telnet-naws.h
@@ -51,7 +51,7 @@ struct _MudTelnetNaws
 
 GType mud_telnet_naws_get_type (void);
 
-
+void mud_telnet_naws_disconnect_signals(MudTelnetNaws *self);
 
 G_END_DECLS
 
diff --git a/src/mud-connection-view.c b/src/mud-connection-view.c
index 044b6d2..1e72b93 100644
--- a/src/mud-connection-view.c
+++ b/src/mud-connection-view.c
@@ -39,6 +39,7 @@
 #include "mud-log.h"
 #include "mud-parse-base.h"
 #include "mud-telnet.h"
+#include "mud-line-buffer.h"
 #include "mud-subwindow.h"
 #include "utils.h"
 
@@ -63,6 +64,8 @@ struct _MudConnectionViewPrivate
     gchar *current_output;
     GList *subwindows;
 
+    MudLineBuffer *line_buffer;
+
 #ifdef ENABLE_GST
     GQueue *download_queue;
     GConnHttp *dl_conn;
@@ -134,6 +137,14 @@ static void mud_connection_view_close_current_cb(GtkWidget *menu_item,
 static void mud_connection_view_profile_changed_cb(MudProfile *profile,
                                                    MudProfileMask *mask,
                                                    MudConnectionView *view);
+static void mud_connection_view_line_added_cb(MudLineBuffer *buffer,
+                                              MudLineBufferLine *line,
+                                              guint length,
+                                              MudConnectionView *view);
+static void mud_connection_view_partial_line_cb(MudLineBuffer *buffer,
+                                                const gchar *line,
+                                                guint length,
+                                                MudConnectionView *view);
 
 
 /* Private Methods */
@@ -388,6 +399,9 @@ mud_connection_view_init (MudConnectionView *self)
 
     self->priv->subwindows = NULL;
     self->priv->current_output = g_strdup("main");
+
+    self->priv->line_buffer = g_object_new(MUD_TYPE_LINE_BUFFER,
+                                           NULL);
 }
 
 static GObject *
@@ -521,6 +535,11 @@ mud_connection_view_constructor (GType gtype,
     /* Setup VTE */
     vte_terminal_set_encoding(self->terminal, "ISO-8859-1");
     vte_terminal_set_emulation(self->terminal, "xterm");
+    vte_terminal_set_cursor_shape(self->terminal,
+                                  VTE_CURSOR_SHAPE_UNDERLINE);
+
+    vte_terminal_set_cursor_blink_mode(self->terminal,
+                                       VTE_CURSOR_BLINK_OFF);
 
     g_object_get(self->window,
                  "window", &main_window,
@@ -606,6 +625,16 @@ mud_connection_view_constructor (GType gtype,
     gtk_widget_hide(self->priv->dl_button);
 #endif
 
+    g_signal_connect(self->priv->line_buffer,
+                     "line-added",
+                     G_CALLBACK(mud_connection_view_line_added_cb),
+                     self);
+
+    g_signal_connect(self->priv->line_buffer,
+                     "partial-line-received",
+                     G_CALLBACK(mud_connection_view_partial_line_cb),
+                     self);
+
     gnet_conn_connect(self->connection);
 
     return obj;
@@ -666,8 +695,13 @@ mud_connection_view_finalize (GObject *object)
         g_object_unref(connection_view->telnet);
   
     g_object_unref(connection_view->log);
+
     g_object_unref(connection_view->parse);
-    g_object_unref(connection_view->profile);
+
+    if(connection_view->profile)
+        g_object_unref(connection_view->profile);
+
+    g_object_unref(connection_view->priv->line_buffer);
 
     entry = g_list_first(connection_view->priv->subwindows);
 
@@ -1093,16 +1127,11 @@ mud_connection_view_popup(MudConnectionView *view, GdkEventButton *event)
 static void
 mud_connection_view_network_event_cb(GConn *conn, GConnEvent *event, gpointer pview)
 {
-    gint gag;
-    gchar *buf;
-    gboolean temp;
-    MudConnectionView *view = MUD_CONNECTION_VIEW(pview);
     gint length;
+    MudConnectionView *view = MUD_CONNECTION_VIEW(pview);
 
 #ifdef ENABLE_GST
     MudMSPDownloadItem *item;
-    MudTelnetMsp *msp_handler;
-    gboolean msp_parser_enabled;
 #endif
 
     g_assert(view != NULL);
@@ -1159,88 +1188,21 @@ mud_connection_view_network_event_cb(GConn *conn, GConnEvent *event, gpointer pv
             }
 
             view->priv->processed =
-                mud_telnet_process(view->telnet, (guchar *)event->buffer,
-                        event->length, &length);
+                mud_telnet_process(view->telnet, 
+                                   (guchar *)event->buffer,
+                                   event->length,
+                                   &length);
 
-            if(view->priv->processed != NULL)
+            if(view->priv->processed)
             {
-#ifdef ENABLE_GST
-                msp_handler =
-                    MUD_TELNET_MSP(mud_telnet_get_handler(view->telnet,
-                                                          TELOPT_MSP));
-
-                g_object_get(msp_handler,
-                             "enabled", &msp_parser_enabled,
-                             NULL);
+                mud_line_buffer_add_data(view->priv->line_buffer,
+                                         view->priv->processed->str,
+                                         view->priv->processed->len);
 
-                if(msp_parser_enabled)
-                {
-                    view->priv->processed =
-                        mud_telnet_msp_parse(msp_handler,
-                                             view->priv->processed,
-                                             &length);
-                }
-#endif
-                if(view->priv->processed != NULL)
-                {
-#ifdef ENABLE_GST
-                    if(msp_parser_enabled)
-                        mud_telnet_msp_parser_clear(msp_handler);
-#endif 
-                    buf = view->priv->processed->str;
-
-                    temp = view->local_echo;
-                    view->local_echo = FALSE;
-                    gag = mud_parse_base_do_triggers(view->parse,
-                            buf);
-                    view->local_echo = temp;
-
-                    if(!gag)
-                    {
-                        if(g_str_equal(view->priv->current_output, "main"))
-                        {
-                            vte_terminal_feed(view->terminal,
-                                              buf,
-                                              length);
-
-                            mud_window_toggle_tab_icon(view->window, view);
-                        }
-                        else
-                        {
-                            MudSubwindow *sub =
-                                mud_connection_view_get_subwindow(view,
-                                        view->priv->current_output);
-
-                            if(sub)
-                                mud_subwindow_feed(sub, buf, length);
-                            else
-                            {
-                                vte_terminal_feed(view->terminal,
-                                        buf,
-                                        length);
-
-                                mud_window_toggle_tab_icon(view->window, view);
-                            }
-
-                        }
-
-                        if(view->logging)
-                            mud_log_write_hook(view->log, buf, length);
-                    }
-
-                    if (view->connect_hook) {
-                        mud_connection_view_send (view, view->connect_string);
-                        view->connect_hook = FALSE;
-                    }
+                g_string_free(view->priv->processed, TRUE);
+                view->priv->processed = NULL;
 
-                    if(view->priv->processed != NULL)
-                    {
-                        g_string_free(view->priv->processed, TRUE);
-                        view->priv->processed = NULL;
-                    }
-
-                    buf = NULL;
-                }
+                mud_line_buffer_flush(view->priv->line_buffer);
             }
 
             gnet_conn_read(view->connection);
@@ -1257,6 +1219,121 @@ mud_connection_view_network_event_cb(GConn *conn, GConnEvent *event, gpointer pv
     }
 }
 
+static void
+mud_connection_view_line_added_cb(MudLineBuffer *buffer,
+                                  MudLineBufferLine *line,
+                                  guint length,
+                                  MudConnectionView *view)
+{
+#ifdef ENABLE_GST
+    MudTelnetMsp *msp_handler;
+    gboolean msp_parser_enabled;
+
+    msp_handler =
+        MUD_TELNET_MSP(mud_telnet_get_handler(view->telnet,
+                    TELOPT_MSP));
+
+    g_object_get(msp_handler,
+            "enabled", &msp_parser_enabled,
+            NULL);
+
+    if(msp_parser_enabled)
+    {
+        mud_telnet_msp_parse(msp_handler,
+                             line);
+
+        mud_telnet_msp_parser_clear(msp_handler);
+
+        if(line->gag)
+            return;
+    }
+#endif
+
+    // TODO: Trigger & script code.
+
+    if(!line->gag)
+    {
+        if(g_str_equal(view->priv->current_output, "main"))
+        {
+            vte_terminal_feed(view->terminal,
+                              line->line,
+                              length);
+
+            mud_window_toggle_tab_icon(view->window, view);
+        }
+        else
+        {
+            MudSubwindow *sub =
+                mud_connection_view_get_subwindow(view,
+                        view->priv->current_output);
+
+            if(sub)
+                mud_subwindow_feed(sub, line->line, length);
+            else
+            {
+                vte_terminal_feed(view->terminal,
+                                  line->line,
+                                  length);
+
+                mud_window_toggle_tab_icon(view->window, view);
+            }
+        }
+
+        if (view->connect_hook)
+        {
+            mud_connection_view_send (view, view->connect_string);
+            view->connect_hook = FALSE;
+        }
+    }
+
+    if(view->logging)
+        mud_log_write_hook(view->log, line->line, length);
+}
+
+static void
+mud_connection_view_partial_line_cb(MudLineBuffer *buffer,
+                                    const gchar *line,
+                                    guint length,
+                                    MudConnectionView *view)
+{
+    //TODO:  Pass through trigger and script code.
+    
+    if(!mud_line_buffer_partial_clear(buffer))
+    {
+        mud_line_buffer_clear_partial_line(buffer);
+
+        if(g_str_equal(view->priv->current_output, "main"))
+        {
+            vte_terminal_feed(view->terminal,
+                    line,
+                    length);
+
+            mud_window_toggle_tab_icon(view->window, view);
+        }
+        else
+        {
+            MudSubwindow *sub =
+                mud_connection_view_get_subwindow(view,
+                        view->priv->current_output);
+
+            if(sub)
+                mud_subwindow_feed(sub, line, length);
+            else
+            {
+                vte_terminal_feed(view->terminal,
+                        line,
+                        length);
+
+                mud_window_toggle_tab_icon(view->window, view);
+            }
+
+        }
+
+    }
+
+    if(view->logging)
+        mud_log_write_hook(view->log, line, length);
+}
 
 static void
 popup_menu_detach(GtkWidget *widget, GtkMenu *menu)
@@ -1399,6 +1476,9 @@ mud_connection_view_set_terminal_colors(MudConnectionView *view)
             &view->profile->preferences->Foreground,
             &view->profile->preferences->Background,
             view->profile->preferences->Colors, C_MAX);
+
+    vte_terminal_set_color_cursor(view->terminal,
+                                  &view->profile->preferences->Background);
 }
 
 static void
@@ -1531,6 +1611,22 @@ mud_connection_view_enable_subwindow_input(MudConnectionView *view,
     }
 }
 
+void
+mud_connection_view_enable_subwindow_scroll(MudConnectionView *view,
+                                            const gchar *identifier,
+                                            gboolean enable)
+{
+    g_return_if_fail(IS_MUD_CONNECTION_VIEW(view));
+
+    if(mud_connection_view_has_subwindow(view, identifier))
+    {
+        MudSubwindow *sub =
+            mud_connection_view_get_subwindow(view, identifier);
+
+        mud_subwindow_enable_scroll(sub, enable);
+    }
+}
+
 
 void
 mud_connection_view_show_subwindow(MudConnectionView *view,
@@ -2049,10 +2145,13 @@ mud_connection_view_start_logging(MudConnectionView *view)
 {
     g_return_if_fail(IS_MUD_CONNECTION_VIEW(view));
 
-    mud_log_open(view->log);
+    if(!view->logging)
+    {
+        mud_log_open(view->log);
 
-    if(mud_log_islogging(view->log))
-        view->logging = TRUE;
+        if(mud_log_islogging(view->log))
+            view->logging = TRUE;
+    }
 }
 
 void
@@ -2060,8 +2159,11 @@ mud_connection_view_stop_logging(MudConnectionView *view)
 {
     g_return_if_fail(IS_MUD_CONNECTION_VIEW(view));
 
-    view->logging = FALSE;
-    mud_log_close(view->log);
+    if(view->logging)
+    {
+        view->logging = FALSE;
+        mud_log_close(view->log);
+    }
 }
 
 void
diff --git a/src/mud-connection-view.h b/src/mud-connection-view.h
index 052bfa6..2ccb733 100644
--- a/src/mud-connection-view.h
+++ b/src/mud-connection-view.h
@@ -122,6 +122,10 @@ void mud_connection_view_enable_subwindow_input(MudConnectionView *view,
                                                 const gchar *identifier,
                                                 gboolean enable);
 
+void mud_connection_view_enable_subwindow_scroll(MudConnectionView *view,
+                                                 const gchar *identifier,
+                                                 gboolean enable);
+
 void mud_connection_view_show_subwindow(MudConnectionView *view,
                                         const gchar *identifier);
 
diff --git a/src/mud-line-buffer.c b/src/mud-line-buffer.c
index 832ea28..4dc9419 100644
--- a/src/mud-line-buffer.c
+++ b/src/mud-line-buffer.c
@@ -116,7 +116,7 @@ mud_line_buffer_class_init (MudLineBufferClass *klass)
                                            "Total possible number of lines in buffer.",
                                            0,
                                            G_MAXULONG,
-                                           20,
+                                           G_MAXULONG,
                                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
     /* Register Signals */
@@ -127,10 +127,10 @@ mud_line_buffer_class_init (MudLineBufferClass *klass)
                      0,
                      NULL,
                      NULL,
-                     gnome_mud_cclosure_VOID__STRING_UINT,
+                     gnome_mud_cclosure_VOID__POINTER_UINT,
                      G_TYPE_NONE,
                      2,
-                     G_TYPE_STRING,
+                     G_TYPE_POINTER,
                      G_TYPE_UINT);
 
     mud_line_buffer_signal[LINE_REMOVED] =
@@ -273,11 +273,15 @@ mud_line_buffer_add_data(MudLineBuffer *self,
     g_return_if_fail(MUD_IS_LINE_BUFFER(self));
 
     data_buffer = g_string_new_len(data, length);
-    data_buffer = g_string_prepend(data_buffer,
-                                   self->priv->incoming_buffer->str);
 
-    g_string_free(self->priv->incoming_buffer, TRUE);
-    self->priv->incoming_buffer = g_string_new(NULL);
+    if(self->priv->incoming_buffer)
+    {
+        data_buffer = g_string_prepend(data_buffer,
+                                       self->priv->incoming_buffer->str);
+
+        g_string_free(self->priv->incoming_buffer, TRUE);
+        self->priv->incoming_buffer = g_string_new(NULL);
+    }
 
     line = g_string_new(NULL);
 
@@ -287,21 +291,29 @@ mud_line_buffer_add_data(MudLineBuffer *self,
 
         if(data_buffer->str[i] == '\n')
         {
+            MudLineBufferLine *new_line = g_new0(MudLineBufferLine, 1);
+
             ++self->priv->length;
 
+            new_line->gag = FALSE;
+            new_line->line = g_strdup(line->str);
+
             self->priv->line_buffer =
                 g_list_append(self->priv->line_buffer,
-                              g_strdup(line->str));
+                              new_line);
 
             if(self->priv->length == self->priv->maximum_line_count + 1)
             {
-                gchar *kill_line =
+                MudLineBufferLine *kill_line =
                     (g_list_first(self->priv->line_buffer))->data;
 
                 self->priv->line_buffer = g_list_remove(self->priv->line_buffer,
                                                         kill_line);
                 if(kill_line)
+                {
+                    g_free(kill_line->line);
                     g_free(kill_line);
+                }
 
                 --self->priv->length;
 
@@ -313,7 +325,7 @@ mud_line_buffer_add_data(MudLineBuffer *self,
             g_signal_emit(self,
                           mud_line_buffer_signal[LINE_ADDED],
                           0,
-                          line->str,
+                          new_line,
                           line->len);
 
             g_string_free(line, TRUE);
@@ -346,7 +358,9 @@ mud_line_buffer_flush(MudLineBuffer *self)
 
     g_list_foreach(self->priv->line_buffer, mud_line_buffer_free_line, NULL);
     g_list_free(self->priv->line_buffer);
-    g_string_free(self->priv->incoming_buffer, TRUE);
+
+    if(self->priv->incoming_buffer)
+        g_string_free(self->priv->incoming_buffer, TRUE);
 
     self->priv->length = 0;
     self->priv->line_buffer = NULL;
@@ -370,9 +384,10 @@ mud_line_buffer_get_lines(MudLineBuffer *self)
 
     while(entry)
     {
-        const gchar *line = (gchar *)entry->data;
+        const MudLineBufferLine *line =
+            (MudLineBufferLine *)entry->data;
 
-        lines = g_string_append(lines, line);
+        lines = g_string_append(lines, line->line);
 
         entry = g_list_next(entry);
     }
@@ -380,10 +395,67 @@ mud_line_buffer_get_lines(MudLineBuffer *self)
     return g_string_free(lines, (lines->len == 0) );
 }
 
+const GList *
+mud_line_buffer_get_lines_with_attributes(MudLineBuffer *self)
+{
+    return self->priv->line_buffer;
+}
+
+gchar *
+mud_line_buffer_get_lines_and_partial(MudLineBuffer *self)
+{
+    GList *entry;
+    GString *lines;
+
+    if(!MUD_IS_LINE_BUFFER(self))
+    {
+        g_critical("Invalid MudLineBuffer passed to mud_line_buffer_get_lines");
+        return NULL;
+    }
+
+    entry = g_list_first(self->priv->line_buffer);
+    lines = g_string_new(NULL);
+
+    while(entry)
+    {
+        const MudLineBufferLine *line =
+            (MudLineBufferLine *)entry->data;
+
+        lines = g_string_append(lines, line->line);
+
+        entry = g_list_next(entry);
+    }
+
+    if(self->priv->incoming_buffer)
+    {
+        lines = g_string_append(lines,
+                                g_string_free(self->priv->incoming_buffer,
+                                              FALSE));
+
+        self->priv->incoming_buffer = NULL;
+    }
+
+    return g_string_free(lines, (lines->len == 0) );
+}
+
+void
+mud_line_buffer_clear_partial_line(MudLineBuffer *self)
+{
+    g_return_if_fail(MUD_IS_LINE_BUFFER(self));
+
+    if(self->priv->incoming_buffer)
+    {
+        g_string_free(self->priv->incoming_buffer, TRUE);
+        self->priv->incoming_buffer = g_string_new(NULL);
+    }
+}
+
 const gchar *
 mud_line_buffer_get_line(MudLineBuffer *self,
                          guint line)
 {
+    MudLineBufferLine *buffer_line;
+
     if(!MUD_IS_LINE_BUFFER(self))
     {
         g_critical("Invalid MudLineBuffer passed to mud_line_buffer_get_line");
@@ -393,7 +465,10 @@ mud_line_buffer_get_line(MudLineBuffer *self,
     if(line >= self->priv->length)
         return NULL;
 
-    return g_list_nth_data(self->priv->line_buffer, line);
+    buffer_line = g_list_nth_data(self->priv->line_buffer,
+                                  line);
+
+    return buffer_line->line;
 }
 
 gchar *
@@ -426,7 +501,10 @@ mud_line_buffer_get_range(MudLineBuffer *self,
 
     for(i = start; i < end; ++i)
     {
-        range = g_string_append(range, entry->data);
+        MudLineBufferLine *buffer_line =
+            (MudLineBufferLine *)entry->data;
+
+        range = g_string_append(range, buffer_line->line);
 
         entry = g_list_next(entry);
     }
@@ -438,19 +516,35 @@ void
 mud_line_buffer_remove_line(MudLineBuffer *self,
                             guint line)
 {
-    const gchar *remove_data;
+    MudLineBufferLine *buffer_line;
 
     g_return_if_fail(MUD_IS_LINE_BUFFER(self));
 
-    remove_data = mud_line_buffer_get_line(self, line);
-
-    if(!remove_data)
+    if(line >= self->priv->length)
         return;
 
+    buffer_line = g_list_nth_data(self->priv->line_buffer,
+                                  line);
+
     self->priv->line_buffer = g_list_remove(self->priv->line_buffer,
-                                            remove_data);
+                                            buffer_line);
 
-    g_free((gchar *)remove_data); // Somewhat naughty. But the line is removed.
+    g_free(buffer_line->line);
+    g_free(buffer_line);
+}
+
+gboolean
+mud_line_buffer_partial_clear(MudLineBuffer *self)
+{
+    if(!MUD_IS_LINE_BUFFER(self))
+        return TRUE;
+
+    if(!self->priv->incoming_buffer)
+        return TRUE;
+    else if(self->priv->incoming_buffer->len == 0)
+        return TRUE;
+
+    return FALSE;
 }
 
 /* Private Methods */
@@ -458,9 +552,12 @@ static void
 mud_line_buffer_free_line(gpointer value,
                           gpointer user_data)
 {
-    gchar *line = (gchar *)value;
+    MudLineBufferLine *line = (MudLineBufferLine *)value;
 
     if(line)
+    {
+        g_free(line->line);
         g_free(line);
+    }
 }
 
diff --git a/src/mud-line-buffer.h b/src/mud-line-buffer.h
index 14ba8c4..060d268 100644
--- a/src/mud-line-buffer.h
+++ b/src/mud-line-buffer.h
@@ -49,25 +49,42 @@ struct _MudLineBuffer
     MudLineBufferPrivate *priv;
 };
 
-GType         mud_line_buffer_get_type (void);
+typedef struct MudLineBufferLine
+{
+    // Attributes
+    gboolean gag;
+
+    // Line Data
+    gchar *line;
+} MudLineBufferLine;
+
+GType           mud_line_buffer_get_type (void);
+
+void            mud_line_buffer_add_data(MudLineBuffer *self,
+                                         const gchar *data,
+                                         guint length);
+
+void            mud_line_buffer_flush(MudLineBuffer *self);
+
+gchar *         mud_line_buffer_get_lines(MudLineBuffer *self);
+
+const GList *   mud_line_buffer_get_lines_with_attributes(MudLineBuffer *self);
 
-void          mud_line_buffer_add_data(MudLineBuffer *self,
-                                       const gchar *data,
-                                       guint length);
+gchar *         mud_line_buffer_get_lines_and_partial(MudLineBuffer *self);
 
-void          mud_line_buffer_flush(MudLineBuffer *self);
+const gchar *   mud_line_buffer_get_line(MudLineBuffer *self,
+                                         guint line);
 
-gchar *       mud_line_buffer_get_lines(MudLineBuffer *self);
+gchar *         mud_line_buffer_get_range(MudLineBuffer *self,
+                                          guint start,
+                                          guint end);
 
-const gchar * mud_line_buffer_get_line(MudLineBuffer *self,
-                                       guint line);
+void            mud_line_buffer_remove_line(MudLineBuffer *self,
+                                            guint line);
 
-gchar *       mud_line_buffer_get_range(MudLineBuffer *self,
-                                        guint start,
-                                        guint end);
+void            mud_line_buffer_clear_partial_line(MudLineBuffer *self);
 
-void          mud_line_buffer_remove_line(MudLineBuffer *self,
-                                          guint line);
+gboolean        mud_line_buffer_partial_clear(MudLineBuffer *self);
 
 G_END_DECLS
 
diff --git a/src/mud-log.c b/src/mud-log.c
index 9714344..f78f263 100644
--- a/src/mud-log.c
+++ b/src/mud-log.c
@@ -128,7 +128,7 @@ static gboolean mud_log_keypress_cb(GtkWidget *widget,
                                     GdkEventKey *event,
                                     MudLog *self);
 static void mud_log_line_added_cb(MudLineBuffer *buffer,
-                                  const gchar *line,
+                                  MudLineBufferLine *line,
                                   guint length,
                                   MudLog *self);
 
@@ -583,14 +583,14 @@ mud_log_prev_spin_changed_cb(GtkSpinButton *button,
 
 static void
 mud_log_line_added_cb(MudLineBuffer *buffer,
-                      const gchar *line,
+                      MudLineBufferLine *line,
                       guint length,
                       MudLog *self)
 {
     if(!self->priv->done)
     {
         if(line && length != 0) 
-            mud_log_write(self, line, length);
+            mud_log_write(self, line->line, length);
 
         if(self->priv->include_next)
         {
@@ -829,7 +829,7 @@ mud_log_close(MudLog *log)
     {
         while(!g_queue_is_empty(log->priv->span_queue))
         {
-            mud_log_write(log, "</span>", strlen("</span>"));
+            fwrite("</span>", 1, strlen("</span>"), log->priv->logfile);
             g_queue_pop_head(log->priv->span_queue);
         }
     }
@@ -875,7 +875,7 @@ mud_log_islogging(MudLog *log)
 }
 
 void
-mud_log_write_hook(MudLog *log, gchar *data, gint length)
+mud_log_write_hook(MudLog *log, const gchar *data, gint length)
 {
     g_return_if_fail(MUD_IS_LOG(log));
 
@@ -988,6 +988,7 @@ mud_log_parse_ecma_color(MudLog *self,
     gchar **argv;
     gboolean xterm_forecolor, xterm_color;
 
+    g_printf("%s\n", data);
     argv = g_strsplit(data, ";", -1);
     argc = g_strv_length(argv);
 
diff --git a/src/mud-log.h b/src/mud-log.h
index cac6eb0..5df74d4 100644
--- a/src/mud-log.h
+++ b/src/mud-log.h
@@ -55,7 +55,7 @@ struct _MudLog
 GType mud_log_get_type (void);
 
 /*< Public Methods >*/
-void mud_log_write_hook(MudLog *log, gchar *data, gint length);
+void mud_log_write_hook(MudLog *log, const gchar *data, gint length);
 void mud_log_open(MudLog *log);
 void mud_log_close(MudLog *log);
 gboolean mud_log_islogging(MudLog *log);
diff --git a/src/mud-subwindow.c b/src/mud-subwindow.c
index 303f6f3..4c050e5 100644
--- a/src/mud-subwindow.c
+++ b/src/mud-subwindow.c
@@ -50,6 +50,7 @@ struct _MudSubwindowPrivate
     gboolean visible;
     gboolean view_hidden;
     gboolean input_enabled;
+    gboolean scroll;
 
     GQueue *history;
     gint current_history_index;
@@ -60,7 +61,7 @@ struct _MudSubwindowPrivate
     GtkWidget *window;
     GtkWidget *entry;
     GtkWidget *terminal;
-    GtkWidget *scroll;
+    GtkWidget *scrollbar;
     GtkWidget *vbox;
 
     gint x, y;
@@ -87,7 +88,8 @@ enum
     PROP_VIEW_HIDDEN,
     PROP_INPUT,
     PROP_OLD_WIDTH,
-    PROP_OLD_HEIGHT
+    PROP_OLD_HEIGHT,
+    PROP_SCROLL
 };
 
 /* Signal Indices */
@@ -268,6 +270,14 @@ mud_subwindow_class_init (MudSubwindowClass *klass)
                 FALSE,
                 G_PARAM_READWRITE));
 
+    g_object_class_install_property(object_class,
+            PROP_SCROLL,
+            g_param_spec_boolean("scroll-enabled",
+                "Scroll Enabled",
+                "True if subwindow scrolls.",
+                TRUE,
+                G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
     /* Register Signals */
     mud_subwindow_signal[RESIZED] =
         g_signal_new("resized",
@@ -322,7 +332,7 @@ mud_subwindow_init (MudSubwindow *self)
 
     self->priv->window = NULL;
     self->priv->entry = NULL;
-    self->priv->scroll = NULL;
+    self->priv->scrollbar = NULL;
     self->priv->terminal = NULL;
     self->priv->vbox = NULL;
 }
@@ -403,7 +413,7 @@ mud_subwindow_constructor (GType gtype,
     gtk_widget_hide(self->priv->entry);
 
     self->priv->terminal = vte_terminal_new();
-    self->priv->scroll = gtk_vscrollbar_new(NULL);
+    self->priv->scrollbar = gtk_vscrollbar_new(NULL);
     term_box = gtk_hbox_new(FALSE, 0);
 
     vte_terminal_set_encoding(VTE_TERMINAL(self->priv->terminal),
@@ -429,7 +439,7 @@ mud_subwindow_constructor (GType gtype,
                        0);
 
     gtk_box_pack_end(GTK_BOX(term_box),
-                     self->priv->scroll,
+                     self->priv->scrollbar,
                      FALSE,
                      FALSE,
                      0);
@@ -439,14 +449,17 @@ mud_subwindow_constructor (GType gtype,
     gtk_container_add(GTK_CONTAINER(self->priv->window), self->priv->vbox);
 
     gtk_range_set_adjustment(
-            GTK_RANGE(self->priv->scroll),
+            GTK_RANGE(self->priv->scrollbar),
             VTE_TERMINAL(self->priv->terminal)->adjustment);
 
     gtk_window_set_title(GTK_WINDOW(self->priv->window), self->priv->title);
 
     gtk_widget_show(term_box);
     gtk_widget_show(self->priv->vbox);
-    gtk_widget_show(self->priv->scroll);
+
+    if(self->priv->scroll)
+        gtk_widget_show(self->priv->scrollbar);
+
     gtk_widget_show(self->priv->terminal);
     gtk_widget_show(self->priv->window);
 
@@ -545,6 +558,13 @@ mud_subwindow_set_property(GObject *object,
                 self->priv->input_enabled = new_boolean;
             break;
 
+        case PROP_SCROLL:
+            new_boolean = g_value_get_boolean(value);
+
+            if(new_boolean != self->priv->scroll)
+                self->priv->scroll = new_boolean;
+            break;
+
         case PROP_VISIBLE:
             new_boolean = g_value_get_boolean(value);
 
@@ -647,6 +667,10 @@ mud_subwindow_get_property(GObject *object,
             g_value_set_string(value, self->priv->identifier);
             break;
 
+        case PROP_SCROLL:
+            g_value_set_boolean(value, self->priv->scroll);
+            break;
+
         case PROP_WIDTH:
             g_value_set_uint(value, self->priv->width);
             break;
@@ -1119,3 +1143,19 @@ mud_subwindow_enable_input(MudSubwindow *self,
     mud_subwindow_set_size(self, self->priv->width, self->priv->height);
 }
 
+void
+mud_subwindow_enable_scroll(MudSubwindow *self,
+                           gboolean enable)
+{
+    g_return_if_fail(MUD_IS_SUBWINDOW(self));
+
+    self->priv->input_enabled = enable;
+
+    if(enable)
+        gtk_widget_show(self->priv->scrollbar);
+    else
+        gtk_widget_hide(self->priv->scrollbar);
+
+    mud_subwindow_set_size(self, self->priv->width, self->priv->height);
+}
+
diff --git a/src/mud-subwindow.h b/src/mud-subwindow.h
index 97eae87..f31e166 100644
--- a/src/mud-subwindow.h
+++ b/src/mud-subwindow.h
@@ -54,6 +54,7 @@ GType mud_subwindow_get_type (void);
 void mud_subwindow_show(MudSubwindow *self);
 void mud_subwindow_hide(MudSubwindow *self);
 void mud_subwindow_enable_input(MudSubwindow *self, gboolean enable);
+void mud_subwindow_enable_scroll(MudSubwindow *self, gboolean scroll);
 void mud_subwindow_set_title(MudSubwindow *self, const gchar *title);
 void mud_subwindow_set_size(MudSubwindow *self, guint width, guint height);
 void mud_subwindow_reread_profile(MudSubwindow *self);
diff --git a/src/mud-telnet.c b/src/mud-telnet.c
index f4d2f5e..7110097 100644
--- a/src/mud-telnet.c
+++ b/src/mud-telnet.c
@@ -162,7 +162,7 @@ mud_telnet_class_init (MudTelnetClass *klass)
                 "ga received",
                 "set if GA has been received",
                 FALSE,
-                G_PARAM_READABLE));
+                G_PARAM_READWRITE));
 
     g_object_class_install_property(object_class,
             PROP_EOR_RECEIVED,
@@ -170,7 +170,7 @@ mud_telnet_class_init (MudTelnetClass *klass)
                 "eor received",
                 "set if EOR has been received",
                 FALSE,
-                G_PARAM_READABLE));
+                G_PARAM_READWRITE));
 
     g_object_class_install_property(object_class,
             PROP_CONNECTION,
@@ -279,6 +279,14 @@ mud_telnet_set_property(GObject *object,
             self->parent_view = MUD_CONNECTION_VIEW(g_value_get_object(value));
             break;
 
+        case PROP_GA_RECEIVED:
+            self->ga_received = g_value_get_boolean(value);
+            break;
+
+        case PROP_EOR_RECEIVED:
+            self->eor_received = g_value_get_boolean(value);
+            break;
+
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
             break;
@@ -504,13 +512,13 @@ mud_telnet_process(MudTelnet *telnet, guchar * buf, guint32 c, gint *len)
 
                     case (guchar)TEL_GA:
                         telnet->ga_received = TRUE;
-                        g_log("Telnet", G_LOG_LEVEL_INFO, "%s", "GA Received.");
                         // TODO: Hook up to triggers.
                         telnet->priv->tel_state = TEL_STATE_TEXT;
                         break;
 
                     case (guchar)TEL_EOR_BYTE:
                         // TODO: Hook up to triggers.
+                        telnet->eor_received = TRUE;
                         telnet->priv->tel_state = TEL_STATE_TEXT;
                         break;
 
@@ -772,6 +780,7 @@ mud_telnet_register_handlers(MudTelnet *telnet)
                          g_object_new(MUD_TYPE_TELNET_NEWENVIRON,
                                       "telnet", telnet,
                                       NULL));
+
 #ifdef ENABLE_GST
     /* MSP */
     g_hash_table_replace(telnet->priv->handlers,
@@ -869,6 +878,10 @@ mud_telnet_get_telopt_string(guchar ch)
             string = g_string_append(string, "ZMP");
             break;
 
+        case TELOPT_AARDWOLF:
+            string = g_string_append(string, "AARDWOLF");
+            break;
+
         default:
             g_string_printf(string, "Dec: %d Hex: %x Ascii: %c", ch, ch, ch);
             break;
diff --git a/src/mud-telnet.h b/src/mud-telnet.h
index e844187..1911026 100644
--- a/src/mud-telnet.h
+++ b/src/mud-telnet.h
@@ -98,6 +98,37 @@ G_BEGIN_DECLS
 #define     TEL_NEWENVIRON_ESC          2
 #define     TEL_NEWENVIRON_USERVAR      3
 
+/* Aardwolf
+ * http://www.aardwolf.com/blog/2008/07/10/telnet-negotiation-control-mud-client-interaction */
+#define TELOPT_AARDWOLF                 102
+#define TEL_AARDWOLF_STATMON            1
+#define TEL_AARDWOLF_BIGMAP             2
+#define TEL_AARDWOLF_HELP               3
+#define TEL_AARDWOLF_MAP_TAGS           4
+#define TEL_AARDWOLF_CHANNEL_TAGS       5
+#define TEL_AARDWOLF_TELL_TAGS          6
+#define TEL_AARDWOLF_SPELLUP_TAGS       7
+#define TEL_AARDWOLF_SKILLGAINS_TAGS    8
+#define TEL_AARDWOLF_SAY_TAGS           9
+#define TEL_AARDWOLF_SCORE_TAGS         11
+#define TEL_AARDWOLF_MAPPER_ROOM_NAMES  12
+#define TEL_AARDWOLF_MAPPER_EXITS       14
+#define TEL_AARDWOLF_EDITOR_TAGS        15
+#define TEL_AARDWOLF_EQUIP_TAGS         16
+#define TEL_AARDWOLF_INVENTORY_TAGS     17
+#define TEL_AARDWOLF_QUIET_ALL          50
+#define TEL_AARDWOLF_AUTOTICK           51
+#define TEL_AARDWOLF_PROMPTS            52
+#define TEL_AARDWOLF_PAGING             53
+#define TEL_AARDWOLF_SERVER             100
+#define TEL_AARDWOLF_SERVER_LOGIN       1
+#define TEL_AARDWOLF_SERVER_MOTD        2
+#define TEL_AARDWOLF_SERVER_ACTIVE      3
+#define TEL_AARDWOLF_SERVER_AFK         4
+#define TEL_AARDWOLF_SERVER_NOTE        5
+#define TEL_AARDWOLF_SERVER_EDIT        6
+#define TEL_AARDWOLF_SERVER_PAGED       7
+
 #define TEL_SUBREQ_BUFFER_SIZE 16318 
 #define TELOPT_STATE_QUEUE_EMPTY	FALSE
 #define TELOPT_STATE_QUEUE_OPPOSITE	TRUE
diff --git a/src/mud-trigger.c b/src/mud-trigger.c
index db27fa6..3df1ad8 100644
--- a/src/mud-trigger.c
+++ b/src/mud-trigger.c
@@ -29,6 +29,7 @@
 
 #include "mud-line-buffer.h"
 #include "mud-trigger.h"
+#include "mud-subwindow.h"
 #include "gnome-mud-builtins.h"
 #include "utils.h"
 
@@ -40,9 +41,11 @@ struct _MudTriggerPrivate
     gulong lines;
 
     gboolean enabled;
-    gboolean gag_output;
+    gboolean gag;
     
-    gboolean multiline;
+    /* Simple Text Triggers */
+    GRegex *simple_regex;
+    gchar *match_string;
 
     /* Glob Triggers */
     GPatternSpec *glob;
@@ -56,8 +59,11 @@ struct _MudTriggerPrivate
     /* Condition Triggers */
     GList *condition_items;
 
-    /* Filter Child */
-    MudTrigger *child;
+    /* Filter */
+    gboolean filter;
+    GList *filter_set;
+    guint filter_line;
+    gboolean filter_active_step;
 
     /* Key names */
     gchar *profile_key;
@@ -69,6 +75,14 @@ struct _MudTriggerPrivate
 
     /* Variables */
     GList *variables;
+
+    /* Subwindow */
+    GList *windows;
+    gchar *title;
+    guint width;
+    guint height;
+    gboolean input;
+    gboolean scroll;
 };
 
 enum
@@ -109,7 +123,7 @@ static void mud_trigger_get_property(GObject *object,
 
 // Callbacks
 static void mud_trigger_line_added_cb(MudLineBuffer *buffer,
-                                      const gchar *line,
+                                      MudLineBufferLine *line,
                                       guint length,
                                       MudTrigger *self);
 
@@ -192,8 +206,7 @@ mud_trigger_init (MudTrigger *self)
 
     self->priv->line_buffer = NULL;
 
-    self->priv->gag_output = FALSE;
-    self->priv->multiline = FALSE;
+    self->priv->gag = FALSE;
 
     self->priv->glob = NULL;
     self->priv->glob_string = NULL;
@@ -203,10 +216,12 @@ mud_trigger_init (MudTrigger *self)
 
     self->priv->condition_items = NULL;
 
-    self->priv->child = NULL;
-
     self->priv->trigger_key = NULL;
     self->priv->profile_key = NULL;
+
+    self->priv->windows = NULL;
+
+    self->priv->filter_set = NULL;
 }
 
 static GObject *
@@ -244,12 +259,23 @@ mud_trigger_constructor (GType gtype,
     g_printf("Action: %s\n", self->priv->action);
     g_printf("Action Type: %d\n", self->priv->action_type);
 
+    self->priv->type = MUD_TRIGGER_TYPE_SINGLE;
+    /*self->priv->regex = g_regex_new("^(.*) says, \n\"(.*)\"",
+                                    G_REGEX_OPTIMIZE|G_REGEX_MULTILINE|G_REGEX_DOTALL,
+                                    0,
+                                    NULL);*/
+
+    //self->priv->glob = g_pattern_spec_new("foo?*bar*");
+   
+    /*self->priv->simple_regex = g_regex_new("hello world",
+                                           G_REGEX_OPTIMIZE,
+                                           0,
+                                           NULL);*/
+
     self->priv->regex = g_regex_new("^(.*) says, \"(.*)\"",
                                     G_REGEX_OPTIMIZE,
-                                    G_REGEX_MATCH_NOTEMPTY,
+                                    0,
                                     NULL);
-                                     
-
     return obj;
 }
 
@@ -266,6 +292,9 @@ mud_trigger_finalize (GObject *object)
     if(self->priv->regex)
         g_regex_unref(self->priv->regex);
 
+    if(self->priv->glob)
+        g_pattern_spec_free(self->priv->glob);
+
     g_free(self->priv->trigger_key);
     g_free(self->priv->profile_key);
 
@@ -407,21 +436,22 @@ mud_trigger_add_data(MudTrigger *self,
     g_free(stripped);
 }
 
-// Callbacks
-static void
-mud_trigger_line_added_cb(MudLineBuffer *buffer,
-                          const gchar *line,
-                          guint length,
-                          MudTrigger *self)
+void
+mud_trigger_execute(MudTrigger *self,
+                    MudLineBufferLine *line,
+                    guint length)
 {
+    gchar *stripped = utils_strip_ansi(line->line);
+    guint len = strlen(stripped);
+
     switch(self->priv->type)
     {
         case MUD_TRIGGER_TYPE_SINGLE:
-            if(self->priv->regex)
+            if(self->priv->regex) // Regex match
             {
                 if(g_regex_match_full(self->priv->regex,
-                                      line,
-                                      length,
+                                      stripped,
+                                      len,
                                       0,
                                       0,
                                       &self->priv->info,
@@ -429,19 +459,149 @@ mud_trigger_line_added_cb(MudLineBuffer *buffer,
                 {
                     mud_trigger_do_action(self);
 
+                    if(self->priv->gag)
+                        line->gag = TRUE;
+
                     g_match_info_free(self->priv->info);
                 }
+            }
+            else if(self->priv->glob) // Glob match
+            {
+                if(g_pattern_match_string(self->priv->glob,
+                                          stripped))
+                {
+                    mud_trigger_do_action(self);
 
+                    if(self->priv->gag)
+                        line->gag = TRUE;
+                }
             }
+            else if(self->priv->simple_regex) // Simple text match.
+            {
+                if(g_regex_match_full(self->priv->simple_regex,
+                                      stripped,
+                                      len,
+                                      0,
+                                      0,
+                                      &self->priv->info,
+                                      NULL))
+                {
+                    mud_trigger_do_action(self);
+
+                    if(self->priv->gag)
+                        line->gag = TRUE;
+
+                    g_match_info_free(self->priv->info);
+                } 
+            }
+            else
+                g_return_if_reached();
+
             break;
 
-        case MUD_TRIGGER_TYPE_MULTI:
+        case MUD_TRIGGER_TYPE_CONDITION:
             break;
 
-        case MUD_TRIGGER_TYPE_FILTER:
+        default:
+            g_warn_if_reached();
             break;
+    }
 
-        case MUD_TRIGGER_TYPE_CONDITION:
+    g_free(stripped);
+}
+
+void
+mud_trigger_add_filter_child(MudTrigger *self,
+                             MudTrigger *child)
+{
+    g_return_if_fail(MUD_IS_TRIGGER(self));
+    g_return_if_fail(MUD_IS_TRIGGER(child));
+
+    self->priv->filter_set = g_list_append(self->priv->filter_set,
+                                           child);
+}
+
+void
+mud_trigger_add_window(MudTrigger *self,
+                       const gchar *title,
+                       guint width,
+                       guint height,
+                       gboolean input,
+                       gboolean scroll)
+{
+
+}
+
+// Callbacks
+static void
+mud_trigger_line_added_cb(MudLineBuffer *buffer,
+                          MudLineBufferLine *line,
+                          guint length,
+                          MudTrigger *self)
+{
+    gulong len, max;
+    
+    switch(self->priv->type)
+    {
+        case MUD_TRIGGER_TYPE_MULTI:
+            g_object_get(self->priv->line_buffer,
+                         "length", &len,
+                         "maximum-line-count", &max,
+                         NULL);
+
+            if(len == max)
+            {
+                gchar *lines = mud_line_buffer_get_lines(self->priv->line_buffer);
+                guint lines_length = strlen(lines);
+
+                if(self->priv->regex) // Regex match
+                {
+                    if(g_regex_match_full(self->priv->regex,
+                                lines,
+                                lines_length,
+                                0,
+                                0,
+                                &self->priv->info,
+                                NULL))
+                    {
+                        mud_trigger_do_action(self);
+
+                        g_match_info_free(self->priv->info);
+                    }
+
+                }
+                else if(self->priv->glob) // Glob match
+                {
+                    if(g_pattern_match_string(self->priv->glob,
+                                lines))
+                    {
+                        mud_trigger_do_action(self);
+                    }
+                }
+                else if(self->priv->simple_regex) // Simple text match.
+                {
+                   if(g_regex_match_full(self->priv->simple_regex,
+                                         lines,
+                                         lines_length,
+                                         0,
+                                         0,
+                                         &self->priv->info,
+                                         NULL))
+                   {
+                       mud_trigger_do_action(self);
+
+                       g_match_info_free(self->priv->info);
+                   } 
+                }
+                else
+                    g_return_if_reached();
+
+                g_free(lines);
+            }
+            break;
+
+        default:
+            g_warn_if_reached();
             break;
     }
 }
@@ -462,10 +622,16 @@ mud_trigger_do_action(MudTrigger *self)
                    data = mud_trigger_parse(self,
                                             self->priv->action);
 
+                   // send to mud here
                    g_printf("Parsed: %s\n", data);
 
                    g_free(data);
-               } 
+               }
+               else
+               {
+                   // send to mud here
+                   g_printf("Action Fired: %s\n", self->priv->action);
+               }
             }
             break;
 
@@ -473,6 +639,7 @@ mud_trigger_do_action(MudTrigger *self)
             break;
 
         case MUD_TRIGGER_ACTION_LUA:
+            // coming in 0.13
             break;
     }
 }
@@ -480,10 +647,10 @@ mud_trigger_do_action(MudTrigger *self)
 static gchar * 
 mud_trigger_parse(MudTrigger *self, const gchar *data)
 {
-    guint length, matches_length, i;
     gint state;
-    GString *ret, *reg_num;
     gchar **matches;
+    GString *ret, *reg_num;
+    guint length, matches_length, i, j, num;
 
     length = strlen(data);
 
@@ -503,87 +670,62 @@ mud_trigger_parse(MudTrigger *self, const gchar *data)
         switch(state)
         {
             case PARSE_STATE_TEXT:
-                if(data[i] == '%')
-                {
-                    reg_num = g_string_new(NULL);
+                if(data[i] == '%' && i + 1 < length)
                     state = PARSE_STATE_REGISTER;
-                }
                 else
                     ret = g_string_append_c(ret, data[i]);
                 break;
 
             case PARSE_STATE_REGISTER:
-                if(!g_ascii_isdigit(data[i]) &&
-                   i + 1 < length &&
-                   !g_ascii_isdigit(data[i + 1]))
+                reg_num = g_string_new(NULL);
+
+                j = i;
+
+                while(TRUE)
                 {
-                    if(reg_num->len == 0)
-                    {
-                        ret = g_string_append_c(ret, data[i]);
+                    if(j == length || data[j] != '%')
+                        break;
 
-                        if(i != 0 && data[ i - 1 ] == '%')
-                            ret = g_string_append_c(ret, data[ i - 1 ]);
+                    ret = g_string_append_c(ret, data[j++]);
+                }
 
-                        g_string_free(reg_num, TRUE);
-                        reg_num = NULL;
+                if(j == length)
+                {
+                    if(data[j - 1] == '%')
+                        ret = g_string_append_c(ret, data[j - 1]);
 
-                        state = PARSE_STATE_TEXT;
-                    }
-                    else
-                    {
-                        guint num = atol(reg_num->str);
-                        gint check = i - reg_num->len - 2;
-
-                        if(num >= matches_length - 1)
-                        {
-                            if(i != 0 && check > -1 && data[check] == '%')
-                                ret = g_string_append_c(ret, '%');
-
-                            ret = g_string_append(ret, _("#Submatch Out of Range#"));
-                            ret = g_string_append_c(ret, data[i]);
-
-                            state = PARSE_STATE_TEXT; 
-                        }
-                        else
-                        {
-                            if(i != 0 && check > -1 && data[check] == '%')
-                                ret = g_string_append_c(ret, '%');
-                            ret = g_string_append(ret, matches[num + 1]);
-                            ret = g_string_append_c(ret, data[i]);
-
-                            state = PARSE_STATE_TEXT;
-                        }
-
-                        g_string_free(reg_num, TRUE);
-                        reg_num = NULL;
-                    }
+                    i = j;
+                    break;
+                }
+
+                for(; g_ascii_isdigit(data[j]) && j < length; j++)
+                    reg_num = g_string_append_c(reg_num, data[j]);
+
+                if(reg_num->len == 0) // No number, not a register.
+                {
+                    /* Append the % that got us here. */
+                    ret = g_string_append_c(ret, '%');
+
+                    i = j - 1;
+
+                    g_string_free(reg_num, TRUE);
+
+                    state = PARSE_STATE_TEXT;
                 }
                 else
                 {
-                    if(g_ascii_isdigit(data[i]))
-                        reg_num = g_string_append_c(reg_num, data[i]);
+                    i = j - 1;
 
-                    if(i + 1 == length)
-                    {
-                        if(reg_num->len != 0)
-                        {
-                            guint num  = atol(reg_num->str);
-
-                            if(num >= matches_length - 1)
-                            {
-                                ret = g_string_append(ret, _("#Submatch Out of Range#"));
-                                state = PARSE_STATE_TEXT; 
-                            }
-                            else
-                                ret = g_string_append(ret, matches[num + 1]);
-                        }
-
-                        if(!g_ascii_isdigit(data[i]))
-                            ret = g_string_append_c(ret, data[i]);
-
-                        g_string_free(reg_num, TRUE);
-                        reg_num = NULL;
-                    }
+                    num = atol(reg_num->str);
+
+                    g_string_free(reg_num, TRUE);
+
+                    if(num >= matches_length)
+                        ret = g_string_append(ret, _("#Submatch Out of Range#"));
+                    else
+                        ret = g_string_append(ret, matches[num]);
+
+                    state = PARSE_STATE_TEXT;
                 }
                 break;
         }
diff --git a/src/mud-trigger.h b/src/mud-trigger.h
index f70153e..214c04d 100644
--- a/src/mud-trigger.h
+++ b/src/mud-trigger.h
@@ -36,6 +36,8 @@ typedef struct _MudTrigger            MudTrigger;
 typedef struct _MudTriggerClass       MudTriggerClass;
 typedef struct _MudTriggerPrivate     MudTriggerPrivate;
 
+#include "mud-line-buffer.h"
+
 struct _MudTriggerClass
 {
     GObjectClass parent_class;
@@ -53,7 +55,6 @@ typedef enum
 {
     MUD_TRIGGER_TYPE_SINGLE,
     MUD_TRIGGER_TYPE_MULTI,
-    MUD_TRIGGER_TYPE_FILTER,
     MUD_TRIGGER_TYPE_CONDITION
 } MudTriggerType;
 
@@ -89,6 +90,10 @@ void mud_trigger_add_data(MudTrigger *self,
                           const gchar *data,
                           guint length);
 
+void mud_trigger_execute(MudTrigger *self,
+                         MudLineBufferLine *line,
+                         guint length);
+
 G_END_DECLS
 
 #endif // MUD_TRIGGER_H
diff --git a/src/mud-window.c b/src/mud-window.c
index 521750d..8ae4ce1 100644
--- a/src/mud-window.c
+++ b/src/mud-window.c
@@ -44,6 +44,8 @@
 #include "mud-parse-base.h"
 #include "mud-connections.h"
 #include "gnome-mud-marshallers.h"
+#include "mud-telnet.h"
+#include "handlers/mud-telnet-handlers.h"
 #include "utils.h"
 
 struct _MudWindowPrivate
@@ -424,6 +426,7 @@ mud_window_constructor (GType gtype,
     self->profile_manager = g_object_new(MUD_TYPE_PROFILE_MANAGER,
                                          "parent-window", self,
                                         NULL);
+
     mud_window_populate_profiles_menu(self);
 
     return obj;
@@ -448,12 +451,12 @@ mud_window_finalize (GObject *object)
         entry = g_slist_next(entry);
     }
 
-    g_object_unref(self->profile_manager);
-
     g_slist_free(self->priv->mud_views_list);
     
     g_object_unref(self->tray);
 
+    g_object_unref(self->profile_manager);
+
     parent_class = g_type_class_peek_parent(G_OBJECT_GET_CLASS(object));
     parent_class->finalize(object);
 
@@ -518,6 +521,26 @@ mud_window_get_property(GObject *object,
 static int
 mud_window_close(GtkWidget *widget, MudWindow *self)
 {
+    GSList *entry = self->priv->mud_views_list;
+
+    while(entry != NULL)
+    {
+        MudTelnetNaws *naws;
+        gboolean enabled;
+        MudConnectionView *view =
+            MUD_CONNECTION_VIEW(entry->data);
+
+        naws = MUD_TELNET_NAWS(mud_telnet_get_handler(view->telnet,
+                    TELOPT_NAWS));
+
+        g_object_get(naws, "enabled", &enabled, NULL);
+
+        if(enabled)
+            mud_telnet_naws_disconnect_signals(naws);
+
+        entry = g_slist_next(entry);
+    }
+
     g_object_unref(self);
 
     return TRUE;
diff --git a/src/zmp/zmp-subwindow.c b/src/zmp/zmp-subwindow.c
index 7c4c5ca..22cd665 100644
--- a/src/zmp/zmp-subwindow.c
+++ b/src/zmp/zmp-subwindow.c
@@ -78,6 +78,7 @@ static void zmp_subwindow_open(MudTelnetZmp *self, gint argc, gchar **argv);
 static void zmp_subwindow_close(MudTelnetZmp *self, gint argc, gchar **argv);
 static void zmp_subwindow_select(MudTelnetZmp *self, gint argc, gchar **argv);
 static void zmp_subwindow_set_input(MudTelnetZmp *self, gint argc, gchar **argv);
+static void zmp_subwindow_set_scroll(MudTelnetZmp *self, gint argc, gchar **argv);
 static void zmp_subwindow_do_input(MudSubwindow *sub,
                                    const gchar *input,
                                    ZmpSubwindow *self);
@@ -244,6 +245,9 @@ zmp_subwindow_register_commands(MudTelnetZmp *zmp)
     mud_zmp_register(zmp, mud_zmp_new_command("subwindow.",
                                               "subwindow.set-input",
                                               zmp_subwindow_set_input));
+    mud_zmp_register(zmp, mud_zmp_new_command("subwindow.",
+                                              "subwindow.set-scroll",
+                                              zmp_subwindow_set_scroll));
 
 
     /* If the server sends us these, its a broken server.
@@ -392,6 +396,29 @@ zmp_subwindow_set_input(MudTelnetZmp *self,
 }
 
 static void
+zmp_subwindow_set_scroll(MudTelnetZmp *self,
+                         gint argc,
+                         gchar **argv)
+{
+    MudConnectionView *view;
+    MudTelnet *telnet;
+    guint enable;
+
+    if(argc != 3)
+        return;
+
+    g_object_get(self, "telnet", &telnet, NULL);
+    g_object_get(telnet, "parent-view", &view, NULL);
+
+    enable = (guint)atol(argv[2]);
+
+    mud_connection_view_enable_subwindow_scroll(view,
+                                                argv[1],
+                                                enable);
+
+}
+
+static void
 zmp_subwindow_do_input(MudSubwindow *sub,
                        const gchar *input,
                        ZmpSubwindow *self)



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