gnome-mud r675 - in trunk: . src ui



Author: lharris
Date: Mon Jun 30 09:54:58 2008
New Revision: 675
URL: http://svn.gnome.org/viewvc/gnome-mud?rev=675&view=rev

Log:
Merged msp into the master branch to implement MSP


Added:
   trunk/src/mud-telnet-msp.c
   trunk/src/mud-telnet-msp.h
Modified:
   trunk/ChangeLog
   trunk/configure.ac
   trunk/gnome-mud.schemas.in
   trunk/src/Makefile.am
   trunk/src/gconf-helper.c
   trunk/src/gnome-mud.c
   trunk/src/mud-connection-view.c
   trunk/src/mud-connection-view.h
   trunk/src/mud-preferences-window.c
   trunk/src/mud-profile.c
   trunk/src/mud-profile.h
   trunk/src/mud-telnet-handlers.c
   trunk/src/mud-telnet-handlers.h
   trunk/src/mud-telnet.c
   trunk/src/mud-telnet.h
   trunk/src/mud-window.c
   trunk/src/utils.c
   trunk/ui/main.glade
   trunk/ui/prefs.glade

Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac	(original)
+++ trunk/configure.ac	Mon Jun 30 09:54:58 2008
@@ -57,8 +57,9 @@
 VTE_REQUIRED=0.11.00
 PCRE_REQUIRED=6.0.0
 GCONF_REQUIRED=0.20
+GSTREAMER_REQUIRED=0.10
 
-PKG_CHECK_MODULES(GMUD, gtk+-2.0 >= $GTK_REQUIRED vte >= $VTE_REQUIRED libglade-2.0 >= $LIBGLADE_REQUIRED libpcre >= $PCRE_REQUIRED gmodule-2.0 >= $GMODULE_REQUIRED gnet-2.0 >= $LIBGNET_REQUIRED gconf-2.0 >= $GCONF_REQUIRED)
+PKG_CHECK_MODULES(GMUD, gtk+-2.0 >= $GTK_REQUIRED vte >= $VTE_REQUIRED libglade-2.0 >= $LIBGLADE_REQUIRED libpcre >= $PCRE_REQUIRED gmodule-2.0 >= $GMODULE_REQUIRED gnet-2.0 >= $LIBGNET_REQUIRED gconf-2.0 >= $GCONF_REQUIRED gstreamer-0.10 >= $GSTREAMER_REQUIRED)
 AC_SUBST(GMUD_CFLAGS)
 AC_SUBST(GMUD_LIBS)
 

Modified: trunk/gnome-mud.schemas.in
==============================================================================
--- trunk/gnome-mud.schemas.in	(original)
+++ trunk/gnome-mud.schemas.in	Mon Jun 30 09:54:58 2008
@@ -185,6 +185,20 @@
 		</schema>
 
 		<schema>
+			<key>/schemas/apps/gnome-mud/functionality/remote_download</key>
+			<applyto>/apps/gnome-mud/functionality/remote_download</applyto>
+			<owner>gnome-mud</owner>
+			<type>bool</type>
+			<default>true</default>
+			<locale name="C">
+				<short>Remote Download</short>
+				<long>
+				Enable sound file downloading on MSP enabled MUDs
+				</long>
+			</locale>
+		</schema>
+
+		<schema>
 			<key>/schemas/apps/gnome-mud/functionality/commdev</key>
 			<applyto>/apps/gnome-mud/functionality/commdev</applyto>
 			<owner>gnome-mud</owner>

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Mon Jun 30 09:54:58 2008
@@ -49,6 +49,8 @@
 	mud-telnet.h                \
 	mud-telnet-handlers.c		\
 	mud-telnet-handlers.h		\
+	mud-telnet-msp.c			\
+	mud-telnet-msp.h			\
 	mud-telnet-zmp.c			\
 	mud-telnet-zmp.h			\
 	mud-tray.c					\

Modified: trunk/src/gconf-helper.c
==============================================================================
--- trunk/src/gconf-helper.c	(original)
+++ trunk/src/gconf-helper.c	Mon Jun 30 09:54:58 2008
@@ -126,6 +126,7 @@
 	GCONF_GET_BOOLEAN(use_proxy,        functionality,  UseProxy);
 	GCONF_GET_BOOLEAN(remote_encoding,  functionality,  UseRemoteEncoding);
 	GCONF_GET_STRING(proxy_hostname,    functionality,  ProxyHostname);
+	GCONF_GET_BOOLEAN(remote_download,  functionality,  UseRemoteDownload);
 
 	/* palette */
 	g_snprintf(keyname, 2048, "/apps/gnome-mud/%sui/palette", extra_path);

Modified: trunk/src/gnome-mud.c
==============================================================================
--- trunk/src/gnome-mud.c	(original)
+++ trunk/src/gnome-mud.c	Mon Jun 30 09:54:58 2008
@@ -28,6 +28,7 @@
 #include <stdio.h>
 #include <sys/stat.h>
 #include <gnet.h>
+#include <gst/gst.h>
 
 #ifdef USE_PYTHON
 //#include <Python.h>
@@ -102,6 +103,9 @@
     /* Initialize the Gnet library */
     gnet_init();
 
+	/* Initialize GStreamer */
+	gst_init(&argc, &argv);
+
 	gtk_init(&argc, &argv);
 
 	/* Start a GConf client */
@@ -135,6 +139,10 @@
 	if(!g_file_test(buf, G_FILE_TEST_IS_DIR))
 		mkdir(buf, 0777 );
 
+	g_snprintf(buf, 500, "%s/.gnome-mud/audio/", g_get_home_dir());
+	if(!g_file_test(buf, G_FILE_TEST_IS_DIR))
+		mkdir(buf, 0777 );
+
 	gtk_about_dialog_set_url_hook(utils_activate_url, NULL, NULL);
 	gtk_main();
 	gconf_client_suggest_sync(gconf_client, &err);

Modified: trunk/src/mud-connection-view.c
==============================================================================
--- trunk/src/mud-connection-view.c	(original)
+++ trunk/src/mud-connection-view.c	Mon Jun 30 09:54:58 2008
@@ -39,6 +39,7 @@
 #include "mud-parse-base.h"
 #include "mud-telnet.h"
 #include "mud-telnet-zmp.h"
+#include "mud-telnet-msp.h"
 
 /* Hack, will refactor with plugin rewrite -lh */
 extern gboolean PluginGag;
@@ -54,6 +55,9 @@
 	GtkWidget *scrollbar;
 	GtkWidget *box;
 	GtkWidget *popup_menu;
+	GtkWidget *progressbar;
+	GtkWidget *dl_label;
+	GtkWidget *dl_button;
 
 	MudProfile *profile;
 	MudLog *log;
@@ -73,6 +77,14 @@
 	MudTelnet *telnet;
 	gchar *hostname;
 	guint port;
+
+	gchar *mud_name;
+
+	GQueue *download_queue;
+	GConnHttp *dl_conn;
+	gboolean downloading;
+
+	GString *processed;
 };
 
 static void mud_connection_view_init                     (MudConnectionView *connection_view);
@@ -88,6 +100,8 @@
 static void mud_connection_view_popup                    (MudConnectionView *view, GdkEventButton *event);
 static void mud_connection_view_reread_profile           (MudConnectionView *view);
 static void mud_connection_view_network_event_cb(GConn *conn, GConnEvent *event, gpointer data);
+static void mud_connection_view_http_cb(GConnHttp *conn, GConnHttpEvent *event, gpointer data);
+static void mud_connection_view_cancel_dl_cb(GtkWidget *widget, MudConnectionView *view);
 
 GType
 mud_connection_view_get_type (void)
@@ -305,22 +319,46 @@
 mud_connection_view_init (MudConnectionView *connection_view)
 {
 	GtkWidget *box;
+	GtkWidget *dl_vbox;
+	GtkWidget *dl_hbox;
+	GtkWidget *term_box;
 
   	connection_view->priv = g_new0(MudConnectionViewPrivate, 1);
 
     connection_view->priv->history = g_queue_new();
     connection_view->priv->current_history_index = 0;
 
+    connection_view->priv->download_queue = g_queue_new();
+    connection_view->priv->dl_conn = NULL;
+    connection_view->priv->processed = NULL;
+
 	connection_view->priv->parse = mud_parse_base_new(connection_view);
 
 	connection_view->priv->connect_hook = FALSE;
 
-	box = gtk_hbox_new(FALSE, 0);
+	box = gtk_vbox_new(FALSE, 0);
+	dl_vbox = gtk_vbox_new(FALSE, 0);
+	dl_hbox = gtk_hbox_new(FALSE, 0);
+	term_box = gtk_hbox_new(FALSE, 0);
+
+	connection_view->priv->dl_label = gtk_label_new("Downloading...");
+	connection_view->priv->progressbar = gtk_progress_bar_new();
+	gtk_progress_bar_set_pulse_step (GTK_PROGRESS_BAR(connection_view->priv->progressbar), 0.1);
+	connection_view->priv->dl_button = gtk_button_new_from_stock("gtk-cancel");
+	connection_view->priv->downloading = FALSE;
+
+	gtk_box_pack_start(GTK_BOX(dl_vbox), connection_view->priv->dl_label, FALSE, FALSE, 0);
+
+	gtk_box_pack_start(GTK_BOX(dl_hbox), connection_view->priv->progressbar, TRUE, TRUE, 0);
+
+	gtk_box_pack_end(GTK_BOX(dl_hbox), connection_view->priv->dl_button, FALSE, FALSE, 0);
+
+	gtk_box_pack_end(GTK_BOX(dl_vbox), dl_hbox, TRUE, TRUE, 0);
 
 	connection_view->priv->terminal = vte_terminal_new();
 	vte_terminal_set_encoding(VTE_TERMINAL(connection_view->priv->terminal), "ISO-8859-1");
 
-	gtk_box_pack_start(GTK_BOX(box), connection_view->priv->terminal, TRUE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(term_box), connection_view->priv->terminal, TRUE, TRUE, 0);
 	g_signal_connect(G_OBJECT(connection_view->priv->terminal),
 					 "button_press_event",
 					 G_CALLBACK(mud_connection_view_button_press_event),
@@ -328,11 +366,22 @@
 	g_object_set_data(G_OBJECT(connection_view->priv->terminal),
 					  "connection-view", connection_view);
 
+	g_signal_connect(connection_view->priv->dl_button, "clicked",
+		G_CALLBACK(mud_connection_view_cancel_dl_cb), connection_view);
+
 	connection_view->priv->scrollbar = gtk_vscrollbar_new(NULL);
 	gtk_range_set_adjustment(GTK_RANGE(connection_view->priv->scrollbar), VTE_TERMINAL(connection_view->priv->terminal)->adjustment);
-	gtk_box_pack_start(GTK_BOX(box), connection_view->priv->scrollbar, FALSE, FALSE, 0);
+	gtk_box_pack_end(GTK_BOX(term_box), connection_view->priv->scrollbar, FALSE, FALSE, 0);
+
+	gtk_box_pack_start(GTK_BOX(box), dl_vbox, FALSE, FALSE, 0);
+	gtk_box_pack_end(GTK_BOX(box), term_box, TRUE, TRUE, 0);
 
 	gtk_widget_show_all(box);
+
+	gtk_widget_hide(connection_view->priv->progressbar);
+	gtk_widget_hide(connection_view->priv->dl_label);
+	gtk_widget_hide(connection_view->priv->dl_button);
+
 	g_object_set_data(G_OBJECT(box), "connection-view", connection_view);
 
 	connection_view->priv->box = box;
@@ -364,16 +413,22 @@
 	MudConnectionView *connection_view;
 	GObjectClass *parent_class;
 	gchar *history_item;
+	MudMSPDownloadItem *item;
 
 	connection_view = MUD_CONNECTION_VIEW(object);
 
     while((history_item = (gchar *)g_queue_pop_head(connection_view->priv->history)) != NULL)
-        if(history_item != NULL)
-            g_free(history_item);
+		g_free(history_item);
 
     if(connection_view->priv->history)
         g_queue_free(connection_view->priv->history);
 
+	while((item = (MudMSPDownloadItem *)g_queue_pop_head(connection_view->priv->download_queue)) != NULL)
+		mud_telnet_msp_download_item_free(item);
+
+	if(connection_view->priv->download_queue)
+        g_queue_free(connection_view->priv->download_queue);
+
     mud_zmp_finalize(connection_view->priv->telnet);
 
     gnet_conn_disconnect(connection_view->connection);
@@ -396,9 +451,29 @@
 void
 mud_connection_view_disconnect(MudConnectionView *view)
 {
+	MudMSPDownloadItem *item;
+
 	g_assert(view != NULL);
 
+	while((item = (MudMSPDownloadItem *)g_queue_pop_head(view->priv->download_queue)) != NULL)
+		mud_telnet_msp_download_item_free(item);
+
+	if(view->priv->download_queue)
+        g_queue_free(view->priv->download_queue);
+
+	view->priv->download_queue = NULL;
+
+	if(view->priv->processed)
+		g_string_free(view->priv->processed, TRUE);
+
+	view->priv->processed = NULL;
+
+    mud_zmp_finalize(view->priv->telnet);
+
 	gnet_conn_disconnect(view->connection);
+
+	g_object_unref(view->priv->telnet);
+
 	mud_connection_view_add_text(view, _("*** Connection closed.\n"), System);
 }
 
@@ -406,11 +481,42 @@
 mud_connection_view_reconnect(MudConnectionView *view)
 {
     gchar *buf;
+    MudMSPDownloadItem *item;
 
 	g_assert(view != NULL);
 
-	gnet_conn_disconnect(view->connection);
-	mud_connection_view_add_text(view, _("*** Connection closed.\n"), System);
+
+	if(gnet_conn_is_connected(view->connection))
+	{
+		while((item = (MudMSPDownloadItem *)g_queue_pop_head(view->priv->download_queue)) != NULL)
+			mud_telnet_msp_download_item_free(item);
+
+		if(view->priv->download_queue)
+	        g_queue_free(view->priv->download_queue);
+
+		view->priv->download_queue = NULL;
+
+		if(view->priv->processed)
+			g_string_free(view->priv->processed, TRUE);
+
+		view->priv->processed = NULL;
+
+	    mud_zmp_finalize(view->priv->telnet);
+
+		gnet_conn_disconnect(view->connection);
+
+		g_object_unref(view->priv->telnet);
+
+		mud_connection_view_add_text(view, _("*** Connection closed.\n"), System);
+
+		view->priv->download_queue = g_queue_new();
+
+		view->naws_enabled = FALSE;
+
+		view->priv->telnet = mud_telnet_new(view, view->connection, view->priv->mud_name);
+
+		view->local_echo = TRUE;
+	}
 
 	buf = g_strdup_printf(_("*** Making connection to %s, port %d.\n"),
 	    view->priv->hostname, view->priv->port);
@@ -687,7 +793,7 @@
 
 	view->naws_enabled = FALSE;
 
-	view->priv->telnet = mud_telnet_new(view, view->connection);
+	view->priv->telnet = mud_telnet_new(view, view->connection, name);
 
 	view->local_echo = TRUE;
 
@@ -824,23 +930,21 @@
 }
 
 static void
-mud_connection_view_network_event_cb(GConn *conn, GConnEvent *event, gpointer pview)
+ mud_connection_view_network_event_cb(GConn *conn, GConnEvent *event, gpointer pview)
 {
     gint gag;
 	gint pluggag;
-	gint i;
-	MudTelnetBuffer buffer;
-	GString *string;
 	gchar *buf;
 	gboolean temp;
     MudConnectionView *view = MUD_CONNECTION_VIEW(pview);
+    gint length;
 
     g_assert(view != NULL);
 
     switch(event->type)
     {
         case GNET_CONN_ERROR:
-            mud_connection_view_add_text(view, _("*** Could not connect."), Error);
+            mud_connection_view_add_text(view, _("*** Could not connect.\n"), Error);
         break;
 
         case GNET_CONN_CONNECT:
@@ -862,43 +966,48 @@
 		      mud_tray_update_icon(view->priv->tray, online);
 	       }
 
-	       buffer = mud_telnet_process(view->priv->telnet, (guchar *)event->buffer, event->length);
+	       view->priv->processed = mud_telnet_process(view->priv->telnet,
+	       				(guchar *)event->buffer, event->length, &length);
 
-	       if(buffer.len != 0)
+	       if(view->priv->processed != NULL)
 	       {
-	           string = g_string_new(NULL);
-	           for(i = 0; i < buffer.len; i++)
-	                g_string_append_c(string, buffer.buffer[i]);
-
-	           buf = string->str;
-
-	           temp = view->local_echo;
-	           view->local_echo = FALSE;
-	           gag = mud_parse_base_do_triggers(view->priv->parse,
-	                    buf);
-	           view->local_echo = temp;
-
-	           mud_window_handle_plugins(view->priv->window, view->priv->id,
-	                    buf, buffer.len, 1);
-
-	           pluggag = PluginGag;
-	           PluginGag = FALSE;
-
-	            if(!gag && !pluggag)
-	            {
-
-	    	        vte_terminal_feed(VTE_TERMINAL(view->priv->terminal),
-	    	            buf, buffer.len);
-	    	        mud_log_write_hook(view->priv->log, buf, buffer.len);
-	            }
+	       	   if(view->priv->telnet->msp_parser.enabled)
+	       	   {
+					view->priv->processed = mud_telnet_msp_parse(
+						view->priv->telnet, view->priv->processed, &length);
+			   }
+
+			   if(view->priv->processed != NULL)
+			   {
+			   	   mud_telnet_msp_parser_clear(view->priv->telnet);
+		           buf = view->priv->processed->str;
+
+		           temp = view->local_echo;
+		           view->local_echo = FALSE;
+		           gag = mud_parse_base_do_triggers(view->priv->parse,
+		                    buf);
+		           view->local_echo = temp;
+
+		           mud_window_handle_plugins(view->priv->window, view->priv->id,
+		                    buf, length, 1);
+
+		           pluggag = PluginGag;
+		           PluginGag = FALSE;
+
+		            if(!gag && !pluggag)
+		            {
+		    	        vte_terminal_feed(VTE_TERMINAL(view->priv->terminal),
+		    	            buf, length);
+		    	        mud_log_write_hook(view->priv->log, buf, length);
+		            }
+
+	                if (view->priv->connect_hook) {
+	                    mud_connection_view_send (view, view->priv->connect_string);
+	                    view->priv->connect_hook = FALSE;
+	               }
 
-                if (view->priv->connect_hook) {
-                    mud_connection_view_send (view, view->priv->connect_string);
-                    view->priv->connect_hook = FALSE;
-               }
-
-                g_string_free(string, TRUE);
-                buf = NULL;
+	               buf = NULL;
+	            }
             }
 
             gnet_conn_read(view->connection);
@@ -939,3 +1048,201 @@
                 VTE_TERMINAL(view->priv->terminal)->row_count);
     }
 }
+
+static void
+mud_connection_view_start_download(MudConnectionView *view)
+{
+	MudMSPDownloadItem *item;
+
+	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(view->priv->progressbar), 0.0);
+	gtk_label_set_text(GTK_LABEL(view->priv->dl_label), _("Connecting..."));
+	gtk_widget_show(view->priv->progressbar);
+	gtk_widget_show(view->priv->dl_label);
+	gtk_widget_show(view->priv->dl_button);
+
+	if(!view->priv->downloading && view->priv->dl_conn)
+		gnet_conn_http_delete(view->priv->dl_conn);
+
+	item = g_queue_peek_head(view->priv->download_queue);
+	view->priv->dl_conn = gnet_conn_http_new();
+	gnet_conn_http_set_uri(view->priv->dl_conn, item->url);
+	gnet_conn_http_set_user_agent (view->priv->dl_conn, "gnome-mud");
+
+	view->priv->downloading = TRUE;
+
+	gnet_conn_http_run_async(view->priv->dl_conn,
+		mud_connection_view_http_cb, view);
+}
+
+void
+mud_connection_view_queue_download(MudConnectionView *view, gchar *url, gchar *file)
+{
+	MudMSPDownloadItem *item;
+	guint i, size;
+	GConfClient *client;
+	gboolean download;
+
+    gchar key[2048];
+	gchar extra_path[512] = "";
+
+    client = gconf_client_get_default();
+
+    g_snprintf(key, 2048, "/apps/gnome-mud/%s%s", extra_path, "functionality/remote_download");
+    download = gconf_client_get_bool(client, key, NULL);
+
+    if(download)
+    {
+		size = g_queue_get_length(view->priv->download_queue);
+
+		for(i = 0; i < size; ++i) // Don't add items twice.
+		{
+			item = (MudMSPDownloadItem *)g_queue_peek_nth(view->priv->download_queue, i);
+
+			if(strcmp(item->url, url) == 0)
+				return;
+		}
+
+		item = NULL;
+		item = g_malloc(sizeof(MudMSPDownloadItem));
+
+		item->url = g_strdup(url);
+		item->file = g_strdup(file);
+
+		g_queue_push_tail(view->priv->download_queue, item);
+
+		item = NULL;
+
+		if(view->priv->downloading == FALSE)
+			mud_connection_view_start_download(view);
+	}
+}
+
+static void
+mud_connection_view_http_cb(GConnHttp *conn, GConnHttpEvent *event, gpointer data)
+{
+	MudConnectionView *view = (MudConnectionView *)data;
+	MudMSPDownloadItem *item;
+	gchar **uri;
+	GString *file_name;
+	GConnHttpEventData *event_data;
+
+	switch(event->type)
+	{
+		case GNET_CONN_HTTP_CONNECTED:
+		break;
+
+		case GNET_CONN_HTTP_DATA_PARTIAL:
+			event_data = (GConnHttpEventData *)event;
+
+			if(event_data->content_length == 0)
+				gtk_progress_bar_pulse(GTK_PROGRESS_BAR(view->priv->progressbar));
+			else
+				gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(view->priv->progressbar),
+					(gdouble)((gdouble)event_data->data_received / (gdouble)event_data->content_length));
+		break;
+
+		case GNET_CONN_HTTP_DATA_COMPLETE:
+			event_data = (GConnHttpEventData *)event;
+
+			gtk_widget_hide(view->priv->progressbar);
+			gtk_widget_hide(view->priv->dl_label);
+			gtk_widget_hide(view->priv->dl_button);
+
+			item = g_queue_pop_head(view->priv->download_queue);
+
+			g_file_set_contents(item->file, event_data->buffer,
+				event_data->buffer_length, NULL);
+
+			mud_telnet_msp_download_item_free(item);
+
+			view->priv->downloading = FALSE;
+
+			if(!g_queue_is_empty(view->priv->download_queue))
+				mud_connection_view_start_download(view);
+		break;
+
+		case GNET_CONN_HTTP_TIMEOUT:
+			if(!view->priv->downloading)
+				break;
+
+			gtk_widget_hide(view->priv->progressbar);
+			gtk_widget_hide(view->priv->dl_label);
+			gtk_widget_hide(view->priv->dl_button);
+
+			g_warning(_("Connection timed out."));
+
+			item = g_queue_pop_head(view->priv->download_queue);
+			mud_telnet_msp_download_item_free(item);
+
+			view->priv->downloading = FALSE;
+
+			if(!g_queue_is_empty(view->priv->download_queue))
+				mud_connection_view_start_download(view);
+		break;
+
+		case GNET_CONN_HTTP_ERROR:
+			gtk_widget_hide(view->priv->progressbar);
+			gtk_widget_hide(view->priv->dl_label);
+			gtk_widget_hide(view->priv->dl_button);
+
+			g_warning(_("There was an internal http connection error."));
+
+			item = g_queue_pop_head(view->priv->download_queue);
+			mud_telnet_msp_download_item_free(item);
+
+			view->priv->downloading = FALSE;
+
+			if(!g_queue_is_empty(view->priv->download_queue))
+				mud_connection_view_start_download(view);
+
+		break;
+
+		case GNET_CONN_HTTP_RESOLVED:
+			break;
+
+		case GNET_CONN_HTTP_RESPONSE:
+			item = g_queue_peek_head(view->priv->download_queue);
+
+			uri = g_strsplit(item->url, "/", 0);
+
+			file_name = g_string_new(NULL);
+
+			g_string_append(file_name, _("Downloading"));
+			g_string_append_c(file_name, ' ');
+			g_string_append(file_name, uri[g_strv_length(uri) - 1]);
+			g_string_append(file_name, "...");
+
+			gtk_label_set_text(GTK_LABEL(view->priv->dl_label), file_name->str);
+
+			g_string_free(file_name, TRUE);
+			g_strfreev(uri);
+			break;
+
+		case GNET_CONN_HTTP_REDIRECT:
+			break;
+	}
+}
+
+static void
+mud_connection_view_cancel_dl_cb(GtkWidget *widget, MudConnectionView *view)
+{
+	MudMSPDownloadItem *item;
+
+	gtk_widget_hide(view->priv->progressbar);
+	gtk_widget_hide(view->priv->dl_label);
+	gtk_widget_hide(view->priv->dl_button);
+
+	if(view->priv->dl_conn)
+	{
+		gnet_conn_http_delete(view->priv->dl_conn);
+		view->priv->dl_conn = NULL;
+	}
+
+	item = g_queue_pop_head(view->priv->download_queue);
+	mud_telnet_msp_download_item_free(item);
+
+	view->priv->downloading = FALSE;
+
+	if(!g_queue_is_empty(view->priv->download_queue))
+		mud_connection_view_start_download(view);
+}

Modified: trunk/src/mud-connection-view.h
==============================================================================
--- trunk/src/mud-connection-view.h	(original)
+++ trunk/src/mud-connection-view.h	Mon Jun 30 09:54:58 2008
@@ -69,6 +69,7 @@
 void mud_connection_view_get_term_size(MudConnectionView *view, gint *w, gint *h);
 void mud_connection_view_set_naws(MudConnectionView *view, gint enabled);
 void mud_connection_view_send_naws(MudConnectionView *view);
+void mud_connection_view_queue_download(MudConnectionView *view, gchar *url, gchar *file);
 
 #include "mud-profile.h"
 void mud_connection_view_set_profile(MudConnectionView *view, MudProfile *profile);

Modified: trunk/src/mud-preferences-window.c
==============================================================================
--- trunk/src/mud-preferences-window.c	(original)
+++ trunk/src/mud-preferences-window.c	Mon Jun 30 09:54:58 2008
@@ -80,6 +80,8 @@
 	GtkWidget *proxy_combo;
 	GtkWidget *proxy_entry;
 
+	GtkWidget *msp_check;
+
 	GtkWidget *sb_lines;
 
 	GtkWidget *fp_font;
@@ -219,7 +221,7 @@
 static void mud_preferences_window_proxy_check_cb(GtkWidget *widget, MudPreferencesWindow *window);
 static void mud_preferences_window_proxy_combo_cb(GtkWidget *widget, MudPreferencesWindow *window);
 static void mud_preferences_window_proxy_entry_cb(GtkWidget *widget, MudPreferencesWindow *window);
-
+static void mud_preferences_window_msp_check_cb(GtkWidget *widget, MudPreferencesWindow *window);
 
 static void mud_preferences_window_update_echotext    (MudPreferencesWindow *window, MudPrefs *preferences);
 static void mud_preferences_window_update_keeptext    (MudPreferencesWindow *window, MudPrefs *preferences);
@@ -236,6 +238,7 @@
 static void mud_preferences_window_update_proxy_entry(MudPreferencesWindow *window, MudPrefs *preferences);
 static void mud_preferences_window_update_encoding_check(MudPreferencesWindow *window, MudPrefs *preferences);
 static void mud_preferences_window_update_encoding_combo(MudPreferencesWindow *window, MudPrefs *preferences);
+static void mud_preferences_window_update_msp_check(MudPreferencesWindow *window, MudPrefs *preferences);
 
 void mud_preferences_window_populate_trigger_treeview(MudPreferencesWindow *window);
 void mud_preferences_window_populate_alias_treeview(MudPreferencesWindow *window);
@@ -332,6 +335,7 @@
 	preferences->priv->proxy_check = glade_xml_get_widget(glade, "proxy_check");
 	preferences->priv->proxy_combo = glade_xml_get_widget(glade, "proxy_combo");
 	preferences->priv->proxy_entry = glade_xml_get_widget(glade, "proxy_entry");
+	preferences->priv->msp_check = glade_xml_get_widget(glade, "msp_check");
 
 	preferences->priv->fp_font = glade_xml_get_widget(glade, "fp_font");
 
@@ -942,6 +946,10 @@
 					 G_CALLBACK(mud_preferences_window_proxy_entry_cb),
 					 window);
 
+	g_signal_connect(G_OBJECT(window->priv->msp_check), "toggled",
+					 G_CALLBACK(mud_preferences_window_msp_check_cb),
+					 window);
+
 	g_signal_connect(G_OBJECT(window->priv->sb_lines), "changed",
 					 G_CALLBACK(mud_preferences_window_scrollback_cb),
 					 window);
@@ -992,6 +1000,7 @@
 	mud_preferences_window_update_proxy_entry(window, profile->preferences);
 	mud_preferences_window_update_encoding_check(window, profile->preferences);
 	mud_preferences_window_update_encoding_combo(window, profile->preferences);
+	mud_preferences_window_update_msp_check(window, profile->preferences);
 }
 
 static void
@@ -1068,6 +1077,15 @@
 }
 
 static void
+mud_preferences_window_msp_check_cb(GtkWidget *widget, MudPreferencesWindow *window)
+{
+	gboolean value = GTK_TOGGLE_BUTTON(widget)->active ? TRUE : FALSE;
+	RETURN_IF_CHANGING_PROFILES(window);
+
+	mud_profile_set_msp_check(window->priv->profile, value);
+}
+
+static void
 mud_preferences_window_proxy_combo_cb(GtkWidget *widget, MudPreferencesWindow *window)
 {
 	RETURN_IF_CHANGING_PROFILES(window);
@@ -1507,6 +1525,8 @@
 	    mud_preferences_window_update_proxy_combo(window, profile->preferences);
 	if (mask->Encoding)
 	    mud_preferences_window_update_encoding_combo(window, profile->preferences);
+	if (mask->UseRemoteDownload)
+	    mud_preferences_window_update_msp_check(window, profile->preferences);
 }
 
 static void
@@ -1535,6 +1555,13 @@
 }
 
 static void
+mud_preferences_window_update_msp_check(MudPreferencesWindow *window, MudPrefs *preferences)
+{
+	gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(window->priv->msp_check), preferences->UseRemoteDownload);
+
+}
+
+static void
 mud_preferences_window_update_proxy_combo(MudPreferencesWindow *window, MudPrefs *preferences)
 {
 	gchar *profile_name;

Modified: trunk/src/mud-profile.c
==============================================================================
--- trunk/src/mud-profile.c	(original)
+++ trunk/src/mud-profile.c	Mon Jun 30 09:54:58 2008
@@ -549,6 +549,7 @@
 	    UPDATE_STRING("encoding", Encoding, "ISO-8859-1");
 	    UPDATE_BOOLEAN("use_proxy", UseProxy, FALSE);
 	    UPDATE_BOOLEAN("remote_encoding", UseRemoteEncoding, FALSE);
+	    UPDATE_BOOLEAN("remote_download", UseRemoteDownload, FALSE);
 	}
 
 #undef UPDATE_BOOLEAN
@@ -639,6 +640,15 @@
 	gconf_client_set_bool(profile->priv->gconf_client, key, value, NULL);
 }
 
+void
+mud_profile_set_msp_check (MudProfile *profile, const gint value)
+{
+    const gchar *key = mud_profile_gconf_get_key(profile, "functionality/remote_download");
+	RETURN_IF_NOTIFYING(profile);
+
+	gconf_client_set_bool(profile->priv->gconf_client, key, value, NULL);
+}
+
 static void
 mud_profile_set_proxy_combo_full(MudProfile *profile, gchar *version)
 {
@@ -815,6 +825,7 @@
 	mud_profile_set_encoding_combo(to, from->preferences->Encoding);
 	mud_profile_set_encoding_check(to, from->preferences->UseRemoteEncoding);
 	mud_profile_set_proxy_check(to, from->preferences->UseProxy);
+	mud_profile_set_msp_check(to, from->preferences->UseRemoteDownload);
 	mud_profile_set_proxy_combo_full(to, from->preferences->ProxyVersion);
 	mud_profile_set_proxy_entry(to, from->preferences->ProxyHostname);
 }

Modified: trunk/src/mud-profile.h
==============================================================================
--- trunk/src/mud-profile.h	(original)
+++ trunk/src/mud-profile.h	Mon Jun 30 09:54:58 2008
@@ -43,6 +43,7 @@
 
 	gboolean UseRemoteEncoding;
 	gboolean UseProxy;
+	gboolean UseRemoteDownload;
 	gchar *Encoding;
 	gchar *ProxyVersion;
 	gchar *ProxyHostname;
@@ -78,6 +79,7 @@
 	unsigned int Encoding : 1;
 	unsigned int ProxyVersion : 1;
 	unsigned int ProxyHostname : 1;
+	unsigned int UseRemoteDownload : 1;
 } MudProfileMask;
 
 struct _MudProfileClass
@@ -116,6 +118,7 @@
 void mud_profile_set_proxy_check (MudProfile *profile, const gint value);
 void mud_profile_set_proxy_combo(MudProfile *profile, GtkComboBox *combo);
 void mud_profile_set_proxy_entry (MudProfile *profile, const gchar *value);
+void mud_profile_set_msp_check (MudProfile *profile, const gint value);
 
 gchar *mud_profile_from_number(gint num);
 gint mud_profile_num_from_name(gchar *name);

Modified: trunk/src/mud-telnet-handlers.c
==============================================================================
--- trunk/src/mud-telnet-handlers.c	(original)
+++ trunk/src/mud-telnet-handlers.c	Mon Jun 30 09:54:58 2008
@@ -296,3 +296,25 @@
 	g_string_free(args, TRUE);
 
 }
+
+/* MSP */
+void
+MudHandler_MSP_Enable(MudTelnet *telnet, MudTelnetHandler *handler)
+{
+	handler->enabled = TRUE;
+	mud_telnet_msp_init(telnet);
+	telnet->msp_parser.enabled = TRUE;
+}
+
+void
+MudHandler_MSP_Disable(MudTelnet *telnet, MudTelnetHandler *handler)
+{
+    handler->enabled = FALSE;
+}
+
+void
+MudHandler_MSP_HandleSubNeg(MudTelnet *telnet, guchar *buf,
+    guint len, MudTelnetHandler *handler)
+{
+    return;
+}

Modified: trunk/src/mud-telnet-handlers.h
==============================================================================
--- trunk/src/mud-telnet-handlers.h	(original)
+++ trunk/src/mud-telnet-handlers.h	Mon Jun 30 09:54:58 2008
@@ -62,4 +62,10 @@
 void MudHandler_ZMP_HandleSubNeg(MudTelnet *telnet, guchar *buf,
     guint len, MudTelnetHandler *handler);
 
+/* MSP */
+void MudHandler_MSP_Enable(MudTelnet *telnet, MudTelnetHandler *handler);
+void MudHandler_MSP_Disable(MudTelnet *telnet, MudTelnetHandler *handler);
+void MudHandler_MSP_HandleSubNeg(MudTelnet *telnet, guchar *buf,
+    guint len, MudTelnetHandler *handler);
+
 #endif // MUD_TELNET_HANDLERS_H

Added: trunk/src/mud-telnet-msp.c
==============================================================================
--- (empty file)
+++ trunk/src/mud-telnet-msp.c	Mon Jun 30 09:54:58 2008
@@ -0,0 +1,891 @@
+/* GNOME-Mud - A simple Mud CLient
+ * Copyright (C) 1998-2006 Robin Ericsson <lobbin localhost nu>
+ *
+ * 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 <gst/gst.h>
+#include <ctype.h>
+
+#include "gnome-mud.h"
+#include "mud-telnet.h"
+#include "mud-telnet-msp.h"
+
+static void mud_telnet_msp_parser_reset(MudTelnet *telnet);
+static void mud_telnet_msp_parser_args(MudTelnet *telnet);
+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(MudTelnet *telnet, MudMSPCommand *command);
+static void mud_telnet_msp_stop_playing(MudTelnet *telnet, MudMSPTypes type);
+static void mud_telnet_msp_start_playing(MudTelnet *telnet, MudMSPTypes type);
+static gboolean mud_telnet_msp_get_files(MudTelnet *telnet, 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);
+
+GString *
+mud_telnet_msp_parse(MudTelnet *telnet, GString *buf, gint *len)
+{
+	gint count;
+	GString *ret = NULL;
+	gchar *temp;
+
+	mud_telnet_msp_parser_reset(telnet);
+
+	if(telnet->prev_buffer)
+	{
+		g_string_prepend(buf, telnet->prev_buffer->str);
+		g_string_free(telnet->prev_buffer, TRUE);
+		telnet->prev_buffer = NULL;
+	}
+
+	while(telnet->msp_parser.lex_pos_start < *len)
+	{
+		switch(telnet->msp_parser.state)
+		{
+			case MSP_STATE_TEXT:
+				if(buf->str[telnet->msp_parser.lex_pos_start] == '!')
+					telnet->msp_parser.state = MSP_STATE_POSSIBLE_COMMAND;
+				else
+				{
+					g_string_append_c(telnet->msp_parser.output,
+						buf->str[telnet->msp_parser.lex_pos_start++]);
+				}
+			break;
+
+			case MSP_STATE_POSSIBLE_COMMAND:
+				if(telnet->msp_parser.lex_pos_start + 1 == *len)
+					continue;
+				else if(buf->str[telnet->msp_parser.lex_pos_start + 1] != '!')
+				{
+					g_string_append_c(telnet->msp_parser.output,
+						buf->str[telnet->msp_parser.lex_pos_start++]);
+					telnet->msp_parser.state = MSP_STATE_TEXT;
+					continue;
+				}
+
+				telnet->msp_parser.state = MSP_STATE_COMMAND;
+			break;
+
+			case MSP_STATE_COMMAND:
+				if(telnet->msp_parser.lex_pos_start + 8 >= *len)
+				{
+					telnet->prev_buffer = g_string_new(NULL);
+
+					count = telnet->msp_parser.lex_pos_start;
+
+					while(count != buf->len)
+						g_string_append_c(telnet->prev_buffer, buf->str[count++]);
+
+					telnet->msp_parser.lex_pos_start += count;
+					continue;
+				}
+
+				if(buf->str[telnet->msp_parser.lex_pos_start + 2] == 'S' &&
+				   buf->str[telnet->msp_parser.lex_pos_start + 3] == 'O' &&
+				   buf->str[telnet->msp_parser.lex_pos_start + 4] == 'U' &&
+				   buf->str[telnet->msp_parser.lex_pos_start + 5] == 'N' &&
+				   buf->str[telnet->msp_parser.lex_pos_start + 6] == 'D')
+				   	telnet->msp_type = MSP_TYPE_SOUND;
+				else if(buf->str[telnet->msp_parser.lex_pos_start + 2] == 'M' &&
+				   		buf->str[telnet->msp_parser.lex_pos_start + 3] == 'U' &&
+				   		buf->str[telnet->msp_parser.lex_pos_start + 4] == 'S' &&
+				   		buf->str[telnet->msp_parser.lex_pos_start + 5] == 'I' &&
+				   		buf->str[telnet->msp_parser.lex_pos_start + 6] == 'C')
+				   			telnet->msp_type = MSP_TYPE_MUSIC;
+				else
+				{
+					/* Not an msp command, bail out. */
+					g_string_append_c(telnet->msp_parser.output, buf->str[telnet->msp_parser.lex_pos_start++]);
+					g_string_append_c(telnet->msp_parser.output, buf->str[telnet->msp_parser.lex_pos_start++]);
+
+					telnet->msp_parser.state = MSP_STATE_TEXT;
+					continue;
+				}
+
+				// Skip leading (
+				telnet->msp_parser.lex_pos_start += 8;
+				telnet->msp_parser.state = MSP_STATE_GET_ARGS;
+				continue;
+			break;
+
+			case MSP_STATE_GET_ARGS:
+				telnet->msp_parser.lex_pos_end = telnet->msp_parser.lex_pos_start;
+
+				if(telnet->msp_parser.arg_buffer == NULL)
+					telnet->msp_parser.arg_buffer = g_string_new(NULL);
+				else
+				{
+					/* This stops some craziness where g_string_append_c
+					   doesn't actually update the gstring. Glib bug? */
+					temp = g_strdup(telnet->msp_parser.arg_buffer->str);
+					g_string_free(telnet->msp_parser.arg_buffer, TRUE);
+					telnet->msp_parser.arg_buffer = g_string_new(temp);
+					g_free(temp);
+				}
+
+				while(telnet->msp_parser.lex_pos_end < *len && buf->str[telnet->msp_parser.lex_pos_end] != ')')
+					g_string_append_c(telnet->msp_parser.arg_buffer, buf->str[telnet->msp_parser.lex_pos_end++]);
+
+				if(telnet->msp_parser.lex_pos_end >= *len && buf->str[telnet->msp_parser.lex_pos_end - 1] != ')')
+				{
+					telnet->msp_parser.lex_pos_start = telnet->msp_parser.lex_pos_end;
+					continue;
+				}
+
+				telnet->msp_parser.state = MSP_STATE_PARSE_ARGS;
+
+			break;
+
+			case MSP_STATE_PARSE_ARGS:
+				mud_telnet_msp_parser_args(telnet);
+
+				g_string_free(telnet->msp_parser.arg_buffer, TRUE);
+				telnet->msp_parser.arg_buffer = NULL;
+				telnet->msp_parser.lex_pos_start = telnet->msp_parser.lex_pos_end + 2;
+				telnet->msp_parser.state = MSP_STATE_TEXT;
+			break;
+		}
+	}
+
+	if(telnet->msp_parser.state == MSP_STATE_TEXT)
+	{
+		ret = g_string_new(g_strdup(telnet->msp_parser.output->str));
+		*len = telnet->msp_parser.output->len;
+	}
+
+	return ret;
+}
+
+void
+mud_telnet_msp_init(MudTelnet *telnet)
+{
+	telnet->msp_parser.enabled = TRUE;
+	telnet->msp_parser.state = MSP_STATE_TEXT;
+	telnet->msp_parser.lex_pos_start = 0;
+	telnet->msp_parser.lex_pos_end = 0;
+	telnet->msp_parser.output = g_string_new(NULL);
+	telnet->msp_parser.arg_buffer = NULL;
+}
+
+void
+mud_telnet_msp_parser_clear(MudTelnet *telnet)
+{
+	if(telnet->msp_parser.output)
+		g_string_free(telnet->msp_parser.output, TRUE);
+
+	telnet->msp_parser.lex_pos_start = 0;
+	telnet->msp_parser.lex_pos_end = 0;
+	telnet->msp_parser.output = g_string_new(NULL);
+}
+
+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);
+}
+
+static void
+mud_telnet_msp_parser_reset(MudTelnet *telnet)
+{
+	telnet->msp_parser.lex_pos_start = 0;
+	telnet->msp_parser.lex_pos_end = 0;
+}
+
+#define ARG_STATE_FILE 0
+#define ARG_STATE_V 1
+#define ARG_STATE_L 2
+#define ARG_STATE_C 3
+#define ARG_STATE_T 4
+#define ARG_STATE_U 5
+#define ARG_STATE_P 6
+
+static void
+mud_telnet_msp_parser_args(MudTelnet *telnet)
+{
+	gint state = ARG_STATE_FILE;
+	gint i;
+	GString *buffer = g_string_new(NULL);
+	gchar *args = g_strdup(telnet->msp_parser.arg_buffer->str);
+	gint len = strlen(args);
+	MudMSPCommand *command = g_new0(MudMSPCommand, 1);
+
+	command->type = telnet->msp_type;
+	command->fName = NULL;
+	command->V = NULL;
+	command->L = NULL;
+	command->C = NULL;
+	command->T = NULL;
+	command->U = NULL;
+	command->P = NULL;
+
+	command->mud_name = g_strdup(telnet->mud_name);
+	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 = (telnet->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
+					  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
+					  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
+					  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
+					  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
+					  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] != '/')
+				   			g_string_append_c(buffer, '/');
+
+				   		command->U = g_strdup(buffer->str);
+				   		g_string_free(buffer, TRUE);
+				   		buffer = g_string_new(NULL);
+				   }
+				   else
+					  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
+					  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] != '/')
+	   			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(telnet, 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(MudTelnet *telnet, MudMSPCommand *command)
+{
+	/*g_message("MSP Command Parse Results");
+	g_print("Type: %s\n", (command->type == MSP_TYPE_SOUND) ? "Sound" : "Music" );
+	g_print("Filename: %s\n", (command->fName != NULL) ? command->fName : "<null>");
+	g_print("V: %s\n", (command->V != NULL) ? command->V : "<null>");
+	g_print("L: %s\n", (command->L != NULL) ? command->L : "<null>");
+	g_print("C: %s\n", (command->C != NULL) ? command->C : "<null>");
+	g_print("T: %s\n", (command->T != NULL) ? command->T : "<null>");
+	g_print("U: %s\n", (command->U != NULL) ? command->U : "<null>");
+	g_print("P: %s\n", (command->P != NULL) ? command->P : "<null>");
+	g_print("Sfx Type: %s Volume: %d  Priority: %d  Repeat %d times. %s %s\n", (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(telnet->base_url)
+				g_free(telnet->base_url);
+
+
+			telnet->base_url = g_strdup(command->U);
+		}
+		else
+			mud_telnet_msp_stop_playing(telnet, command->type);
+
+		mud_telnet_msp_command_free(command);
+
+		return;
+	}
+
+	if(telnet->sound[command->type].current_command)
+	{
+		if(telnet->sound[command->type].playing)
+		{
+			if(command->priority > telnet->sound[command->type].current_command->priority)
+			{
+				mud_telnet_msp_stop_playing(telnet, command->type);
+				telnet->sound[command->type].current_command = command;
+				mud_telnet_msp_start_playing(telnet, command->type);
+			}
+			else
+				mud_telnet_msp_command_free(command);
+		}
+		else
+		{
+			mud_telnet_msp_stop_playing(telnet, command->type);
+			telnet->sound[command->type].current_command = command;
+			mud_telnet_msp_start_playing(telnet, command->type);
+		}
+	}
+	else
+	{
+		telnet->sound[command->type].current_command = command;
+		mud_telnet_msp_start_playing(telnet, command->type);
+	}
+}
+
+static void
+mud_telnet_msp_stop_playing(MudTelnet *telnet, MudMSPTypes type)
+{
+	telnet->sound[type].playing = FALSE;
+
+	if(GST_IS_ELEMENT(telnet->sound[type].play))
+	{
+		gst_element_set_state (telnet->sound[type].play, GST_STATE_NULL);
+		gst_object_unref (GST_OBJECT (telnet->sound[type].play));
+	}
+
+	if(telnet->sound[type].files)
+	{
+			g_strfreev(telnet->sound[type].files);
+			telnet->sound[type].files = NULL;
+	}
+
+	telnet->sound[type].files_len = 0;
+
+	mud_telnet_msp_command_free(telnet->sound[type].current_command);
+	telnet->sound[type].current_command = NULL;
+}
+
+static void
+mud_telnet_msp_start_playing(MudTelnet *telnet, MudMSPTypes type)
+{
+	if(!telnet->sound[type].current_command)
+		return;
+
+	if(mud_telnet_msp_get_files(telnet, type))
+	{
+		gint num = 0;
+
+		telnet->sound[type].playing = TRUE;
+
+		if(telnet->sound[type].files_len != 0)
+			num = rand() % telnet->sound[type].files_len;
+
+		telnet->sound[type].play = gst_element_factory_make ("playbin", "play");
+		g_object_set (G_OBJECT(telnet->sound[type].play),
+			"uri", telnet->sound[type].files[num], NULL);
+		g_object_set(G_OBJECT(telnet->sound[type].play),
+			"volume", (double)telnet->sound[type].current_command->volume/100, NULL);
+
+		telnet->sound[type].bus =
+			gst_pipeline_get_bus (GST_PIPELINE (telnet->sound[type].play));
+
+		if(type == MSP_TYPE_SOUND)
+			gst_bus_add_watch (telnet->sound[type].bus, mud_telnet_msp_sound_bus_call, telnet);
+		else
+			gst_bus_add_watch (telnet->sound[type].bus, mud_telnet_msp_music_bus_call, telnet);
+
+		gst_object_unref (telnet->sound[type].bus);
+
+		gst_element_set_state (telnet->sound[type].play, GST_STATE_PLAYING);
+	}
+}
+
+static gboolean
+mud_telnet_msp_get_files(MudTelnet *telnet, 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;
+	GDir *dir;
+	gint i, depth;
+	GPatternSpec *regex;
+
+	if(!telnet->sound[type].current_command)
+		return FALSE;
+
+	g_snprintf(sound_dir, 2048, "%s/.gnome-mud/audio/%s/",
+		g_get_home_dir(), telnet->sound[type].current_command->mud_name);
+	if(!g_file_test(sound_dir, G_FILE_TEST_IS_DIR))
+		mkdir(sound_dir, 0777 );
+
+	structure = g_strsplit(telnet->sound[type].current_command->fName, "/", 0);
+	depth = g_strv_length(structure);
+
+	subdir = g_string_new(NULL);
+
+	for(i = 0; i < depth - 1; ++i)
+	{
+		g_string_append(subdir, structure[i]);
+		g_string_append_c(subdir, '/');
+	}
+
+	file_name = g_string_new(structure[depth - 1]);
+
+	g_strfreev(structure);
+
+	full_dir = g_string_new(sound_dir);
+	g_string_append(full_dir, subdir->str);
+
+	if(telnet->sound[type].current_command->T)
+		g_string_append(full_dir, telnet->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))
+		{
+			g_string_append(file_output, "file://");
+			g_string_append(file_output, full_dir->str);
+			g_string_append_c(file_output, '/');
+			g_string_append(file_output, file);
+			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 && telnet->sound[type].current_command->T)
+	{
+		g_string_free(full_dir, TRUE);
+		full_dir = g_string_new(sound_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))
+			{
+				g_string_append(file_output, "file://");
+				g_string_append(file_output, full_dir->str);
+				g_string_append_c(file_output, '/');
+				g_string_append(file_output, file);
+				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(telnet->base_url || telnet->sound[type].current_command->U)
+		{
+			if(telnet->base_url)
+				g_string_append(url_output, telnet->base_url);
+			else
+				g_string_append(url_output, telnet->sound[type].current_command->U);
+
+			if(subdir->len != 0)
+				g_string_append(url_output, subdir->str);
+
+			if(telnet->sound[type].current_command->T)
+			{
+				g_string_append(url_output, telnet->sound[type].current_command->T);
+				g_string_append_c(url_output, '/');
+			}
+
+			g_string_append(url_output, file_name->str);
+
+			g_string_append(file_output, full_dir->str);
+			if(telnet->sound[type].current_command->T)
+				g_string_append_c(file_output, '/');
+			g_string_append(file_output, file_name->str);
+
+			telnet->sound[type].current_command->priority = 0;
+
+			mud_connection_view_queue_download(telnet->parent, 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(telnet->sound[type].files)
+		g_strfreev(telnet->sound[type].files);
+
+	telnet->sound[type].files = files;
+	telnet->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)
+{
+	MudTelnet *telnet = (MudTelnet *)data;
+
+	switch (GST_MESSAGE_TYPE (msg))
+	{
+		case GST_MESSAGE_EOS:
+			telnet->sound[MSP_TYPE_SOUND].playing = FALSE;
+
+			telnet->sound[MSP_TYPE_SOUND].current_command->current_repeat_count--;
+
+			gst_element_set_state (telnet->sound[MSP_TYPE_SOUND].play, GST_STATE_NULL);
+
+			if(telnet->sound[MSP_TYPE_SOUND].current_command->loop ||
+			   telnet->sound[MSP_TYPE_SOUND].current_command->current_repeat_count != 0)
+			{
+				gint num = 0;
+
+				if(telnet->sound[MSP_TYPE_SOUND].files_len != 0)
+					num = rand() % telnet->sound[MSP_TYPE_SOUND].files_len;
+
+				g_object_set (G_OBJECT(telnet->sound[MSP_TYPE_SOUND].play),
+					"uri", telnet->sound[MSP_TYPE_SOUND].files[num], NULL);
+				g_object_set(G_OBJECT(telnet->sound[MSP_TYPE_SOUND].play),
+					"volume", (double)telnet->sound[MSP_TYPE_SOUND].current_command->volume/100.0, NULL);
+
+				gst_element_set_state (telnet->sound[MSP_TYPE_SOUND].play, GST_STATE_PLAYING);
+			}
+			else
+				mud_telnet_msp_stop_playing(telnet, 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)
+{
+	MudTelnet *telnet = (MudTelnet *)data;
+
+	switch (GST_MESSAGE_TYPE (msg))
+	{
+		case GST_MESSAGE_EOS:
+			telnet->sound[MSP_TYPE_MUSIC].playing = FALSE;
+
+			telnet->sound[MSP_TYPE_MUSIC].current_command->current_repeat_count--;
+
+			gst_element_set_state (telnet->sound[MSP_TYPE_MUSIC].play, GST_STATE_NULL);
+
+			if(telnet->sound[MSP_TYPE_MUSIC].current_command->loop ||
+			   telnet->sound[MSP_TYPE_MUSIC].current_command->current_repeat_count != 0)
+			{
+				gint num = 0;
+
+				if(telnet->sound[MSP_TYPE_MUSIC].files_len != 0)
+					num = rand() % telnet->sound[MSP_TYPE_MUSIC].files_len;
+
+				g_object_set (G_OBJECT(telnet->sound[MSP_TYPE_MUSIC].play),
+					"uri", telnet->sound[MSP_TYPE_MUSIC].files[num], NULL);
+				g_object_set(G_OBJECT(telnet->sound[MSP_TYPE_MUSIC].play),
+					"volume", (double)telnet->sound[MSP_TYPE_MUSIC].current_command->volume/100.0, NULL);
+
+				gst_element_set_state (telnet->sound[MSP_TYPE_MUSIC].play, GST_STATE_PLAYING);
+			}
+			else
+				mud_telnet_msp_stop_playing(telnet, 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;
+}

Added: trunk/src/mud-telnet-msp.h
==============================================================================
--- (empty file)
+++ trunk/src/mud-telnet-msp.h	Mon Jun 30 09:54:58 2008
@@ -0,0 +1,102 @@
+/* GNOME-Mud - A simple Mud CLient
+ * Copyright (C) 1998-2006 Robin Ericsson <lobbin localhost nu>
+ *
+ * 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
+
+#include <glib.h>
+#include "mud-telnet.h"
+
+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 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;
+
+#include <gst/gst.h>
+typedef struct MudMSPSound
+{
+	gboolean playing;
+	gchar **files;
+	gint files_len;
+
+	GstElement *play;
+	GstBus *bus;
+
+	MudMSPCommand *current_command;
+} MudMSPSound;
+
+void mud_telnet_msp_init(MudTelnet *telnet);
+void mud_telnet_msp_parser_clear(MudTelnet *telnet);
+void mud_telnet_msp_download_item_free(MudMSPDownloadItem *item);
+GString *mud_telnet_msp_parse(MudTelnet *telnet, GString *buf, gint *len);
+
+#endif // MUD_TELNET_MSP_H

Modified: trunk/src/mud-telnet.c
==============================================================================
--- trunk/src/mud-telnet.c	(original)
+++ trunk/src/mud-telnet.c	Mon Jun 30 09:54:58 2008
@@ -39,7 +39,7 @@
 
 struct _MudTelnetPrivate
 {
-
+	GString *processed;
 };
 
 GType mud_telnet_get_type (void);
@@ -105,6 +105,9 @@
 mud_telnet_init (MudTelnet *telnet)
 {
 	telnet->priv = g_new0(MudTelnetPrivate, 1);
+	telnet->msp_parser.enabled = FALSE;
+	telnet->priv->processed = g_string_new(NULL);
+	telnet->prev_buffer = NULL;
 }
 
 static void
@@ -133,7 +136,7 @@
 
 // Instantiate MudTelnet
 MudTelnet*
-mud_telnet_new(MudConnectionView *parent, GConn *connection)
+mud_telnet_new(MudConnectionView *parent, GConn *connection, gchar *mud_name)
 {
 	MudTelnet *telnet;
 
@@ -151,6 +154,20 @@
 
 	telnet->eor_enabled = FALSE;
 
+	telnet->mud_name = g_strdup(mud_name);
+
+	telnet->sound[0].files = NULL;
+	telnet->sound[0].current_command = NULL;
+	telnet->sound[0].playing = FALSE;
+	telnet->sound[0].files_len = 0;
+
+	telnet->sound[1].files = NULL;
+	telnet->sound[1].current_command = NULL;
+	telnet->sound[1].playing = FALSE;
+	telnet->sound[1].files_len = 0;
+
+	telnet->base_url = NULL;
+
 	return telnet;
 }
 
@@ -217,6 +234,13 @@
     telnet->handlers[5].disable = MudHandler_ZMP_Disable;
     telnet->handlers[5].handle_sub_neg = MudHandler_ZMP_HandleSubNeg;
 
+    /* MSP */
+    telnet->handlers[6].type = HANDLER_MSP;
+    telnet->handlers[6].option_number = (guchar)TELOPT_MSP;
+    telnet->handlers[6].enabled = TRUE;
+    telnet->handlers[6].enable = MudHandler_MSP_Enable;
+    telnet->handlers[6].disable = MudHandler_MSP_Disable;
+    telnet->handlers[6].handle_sub_neg = MudHandler_MSP_HandleSubNeg;
 }
 
 gint
@@ -275,14 +299,14 @@
     mud_telnet_send_sub_req(telnet, 5, (guchar)TELOPT_NAWS, w1, w0, h1, h0);
 }
 
-MudTelnetBuffer
-mud_telnet_process(MudTelnet *telnet, guchar * buf, guint32 count)
+GString *
+mud_telnet_process(MudTelnet *telnet, guchar * buf, guint32 count, gint *len)
 {
-	guchar processed[32768];
 	size_t pos = 0;
 	guint32 i;
-	MudTelnetBuffer ret;
 	g_assert(telnet != NULL);
+	GString *ret = NULL;
+	GString *buffer = g_string_new_len((gchar *)buf, count);
 
 	for (i = 0;i < count;++i)
 	{
@@ -292,14 +316,18 @@
 				if (buf[i] == (guchar)TEL_IAC)
 					telnet->tel_state = TEL_STATE_IAC;
 				else
-					processed[pos++] = buf[i];
+				{
+					g_string_append_c(telnet->priv->processed, buffer->str[i]);
+					pos++;
+				}
 				break;
 
 			case TEL_STATE_IAC:
-				switch (buf[i])
+				switch ((guchar)buffer->str[i])
 				{
 					case (guchar)TEL_IAC:
-						processed[pos++] = buf[i];
+						pos++;
+						g_string_append_c(telnet->priv->processed, buffer->str[i]);
 						telnet->tel_state = TEL_STATE_TEXT;
 						break;
 
@@ -337,32 +365,32 @@
 						break;
 
 					default:
-						g_warning("Illegal IAC command %d received", buf[i]);
+						g_warning("Illegal IAC command %d received", buffer->str[i]);
 						telnet->tel_state = TEL_STATE_TEXT;
 						break;
 				}
 				break;
 
 			case TEL_STATE_DO:
-				mud_telnet_handle_positive_nego(telnet, buf[i],
+				mud_telnet_handle_positive_nego(telnet, (guchar)buffer->str[i],
 				    (guchar)TEL_WILL, (guchar)TEL_WONT, FALSE);
 				telnet->tel_state = TEL_STATE_TEXT;
 
 			case TEL_STATE_WILL:
-				mud_telnet_handle_positive_nego(telnet, buf[i],
+				mud_telnet_handle_positive_nego(telnet, (guchar)buffer->str[i],
 				    (guchar)TEL_DO, (guchar)TEL_DONT, TRUE);
 				telnet->tel_state = TEL_STATE_TEXT;
 				break;
 
 			case TEL_STATE_DONT:
 				mud_telnet_handle_negative_nego(telnet,
-				    buf[i], (guchar)TEL_WILL, (guchar)TEL_WONT, FALSE);
+				    (guchar)buffer->str[i], (guchar)TEL_WILL, (guchar)TEL_WONT, FALSE);
 				telnet->tel_state = TEL_STATE_TEXT;
 				break;
 
 			case TEL_STATE_WONT:
 				mud_telnet_handle_negative_nego(telnet,
-				    buf[i], (guchar)TEL_DO, (guchar)TEL_DONT, TRUE);
+				    (guchar)buffer->str[i], (guchar)TEL_DO, (guchar)TEL_DONT, TRUE);
 				telnet->tel_state = TEL_STATE_TEXT;
 				break;
 
@@ -379,7 +407,7 @@
 						telnet->tel_state = TEL_STATE_TEXT;
 					}
 					else
-						telnet->subreq_buffer[telnet->subreq_pos++] = buf[i];
+						telnet->subreq_buffer[telnet->subreq_pos++] = (guchar)buffer->str[i];
 				}
 				break;
 
@@ -393,17 +421,17 @@
 						telnet->tel_state = TEL_STATE_TEXT;
 					}
 					else
-						telnet->subreq_buffer[telnet->subreq_pos++] = buf[i];
+						telnet->subreq_buffer[telnet->subreq_pos++] = (guchar)buffer->str[i];
 
 					telnet->tel_state = TEL_STATE_SB;
 				}
 				else if (buf[i] == (guchar)TEL_SE)
 				{
-				    telnet->subreq_buffer[telnet->subreq_pos++] = buf[i];
+				    telnet->subreq_buffer[telnet->subreq_pos++] = (guchar)buffer->str[i];
 					mud_telnet_on_handle_subnego(telnet);
 					telnet->tel_state = TEL_STATE_TEXT;
 				} else {
-					g_warning("Erronous byte %d after an IAC inside a subrequest", buf[i]);
+					g_warning("Erronous byte %d after an IAC inside a subrequest", buffer->str[i]);
 					telnet->subreq_pos = 0;
 					telnet->tel_state = TEL_STATE_TEXT;
 				}
@@ -411,8 +439,14 @@
 		}
 	}
 
-	ret.buffer = processed;
-	ret.len = pos;
+	if(telnet->tel_state == TEL_STATE_TEXT)
+	{
+		ret = g_string_new_len(g_strdup(telnet->priv->processed->str), pos);
+		g_string_free(telnet->priv->processed, TRUE);
+		telnet->priv->processed = g_string_new(NULL);
+		*len = pos;
+	}
+
 
 	return ret;
 }
@@ -712,6 +746,7 @@
 				mud_telnet_on_enable_opt(telnet, opt_no, him);
 				return TRUE;
 			} else { // The opposite is queued
+				g_message("Refusing %d", opt_no);
 				mud_telnet_set_telopt_state(opt, TELOPT_STATE_WANTNO, bitshift);
 				mud_telnet_set_telopt_queue(opt, TELOPT_STATE_QUEUE_EMPTY, bitshift);
 				mud_telnet_send_iac(telnet, negative, opt_no);

Modified: trunk/src/mud-telnet.h
==============================================================================
--- trunk/src/mud-telnet.h	(original)
+++ trunk/src/mud-telnet.h	Mon Jun 30 09:54:58 2008
@@ -112,7 +112,8 @@
     HANDLER_ECHO,
     HANDLER_EOR,
     HANDLER_CHARSET,
-    HANDLER_ZMP
+    HANDLER_ZMP,
+    HANDLER_MSP
 };
 
 struct _MudTelnetClass
@@ -120,12 +121,6 @@
 	GObjectClass parent_class;
 };
 
-struct _MudTelnetBuffer
-{
-    guchar *buffer;
-    size_t len;
-};
-
 struct _MudTelnetHandler
 {
     enum TelnetHandlerType type;
@@ -141,8 +136,10 @@
 };
 
 #include <gnet.h>
-#include <mud-connection-view.h>
-#include <mud-telnet-zmp.h>
+#include "mud-connection-view.h"
+#include "mud-telnet-zmp.h"
+#include "mud-telnet-msp.h"
+
 struct _MudTelnet
 {
 	GObject parent_instance;
@@ -164,15 +161,24 @@
 
 	GHashTable *zmp_commands;
 	MudZMPCommand commands[2048];
+
+	MudMSPParser msp_parser;
+	MudMSPTypes msp_type;
+	MudMSPSound sound[2];
+	gchar *base_url;
+
+	GString *prev_buffer;
+
+	gchar *mud_name;
 };
 
 GType mud_telnet_get_type (void) G_GNUC_CONST;
 
-MudTelnet *mud_telnet_new(MudConnectionView *parent, GConn *connection);
+MudTelnet *mud_telnet_new(MudConnectionView *parent, GConn *connection, gchar *mud_name);
 
 void mud_telnet_register_handlers(MudTelnet *telnet);
 gint mud_telnet_isenabled(MudTelnet *telnet, guint8 option_number, gint him);
-MudTelnetBuffer mud_telnet_process(MudTelnet *telnet, guchar * buf, guint32 count);
+GString *mud_telnet_process(MudTelnet *telnet, guchar * buf, guint32 count, gint *length);
 void mud_telnet_send_sub_req(MudTelnet *telnet, guint32 count, ...);
 void mud_telnet_get_parent_size(MudTelnet *telnet, gint *w, gint *h);
 void mud_telnet_send_raw(MudTelnet *telnet, guint32 count, ...);

Modified: trunk/src/mud-window.c
==============================================================================
--- trunk/src/mud-window.c	(original)
+++ trunk/src/mud-window.c	Mon Jun 30 09:54:58 2008
@@ -38,6 +38,7 @@
 #include <gtk/gtktextbuffer.h>
 #include <gtk/gtktextiter.h>
 #include <gtk/gtkimagemenuitem.h>
+#include <gtk/gtkprogressbar.h>
 #include <vte/vte.h>
 #include <glib/gstring.h>
 #include <string.h>
@@ -317,9 +318,12 @@
 		    text = mud_connection_view_get_history_item(
 		        MUD_CONNECTION_VIEW(window->priv->current_view), HISTORY_UP);
 
-	   		gtk_text_buffer_set_text(buffer, text, strlen(text));
-	   	 	gtk_text_buffer_get_bounds(buffer, &start, &end);
-	   	 	gtk_text_buffer_select_range(buffer, &start, &end);
+			if(text)
+			{
+		   		gtk_text_buffer_set_text(buffer, text, strlen(text));
+		   	 	gtk_text_buffer_get_bounds(buffer, &start, &end);
+		   	 	gtk_text_buffer_select_range(buffer, &start, &end);
+	   	 	}
 
 	    	return TRUE;
 		}
@@ -329,9 +333,12 @@
 		    text = mud_connection_view_get_history_item(
 		        MUD_CONNECTION_VIEW(window->priv->current_view), HISTORY_DOWN);
 
-		    gtk_text_buffer_set_text(buffer, text, strlen(text));
-		    gtk_text_buffer_get_bounds(buffer, &start, &end);
-		    gtk_text_buffer_select_range(buffer, &start, &end);
+			if(text)
+			{
+			    gtk_text_buffer_set_text(buffer, text, strlen(text));
+			    gtk_text_buffer_get_bounds(buffer, &start, &end);
+			    gtk_text_buffer_select_range(buffer, &start, &end);
+		    }
 
 		    return TRUE;
 		}
@@ -737,7 +744,7 @@
 	/* start glading */
 	glade = glade_xml_new(GLADEDIR "/main.glade", "main_window", NULL);
 	window->priv->window = glade_xml_get_widget(glade, "main_window");
-	gtk_widget_show_all(window->priv->window);
+	//gtk_widget_show_all(window->priv->window);
 
 	/* connect quit buttons */
 	g_signal_connect(window->priv->window, "destroy", G_CALLBACK(mud_window_close), window);

Modified: trunk/src/utils.c
==============================================================================
--- trunk/src/utils.c	(original)
+++ trunk/src/utils.c	Mon Jun 30 09:54:58 2008
@@ -42,14 +42,13 @@
 gchar *
 strip_ansi(const gchar *orig)
 {
-  gchar *buf;
+  GString *buf = g_string_new(NULL);
   const gchar *c;
-  gint currChar = 0;
+  gchar *ret = NULL;
 
   if (!orig)
     return NULL;
 
-  buf = g_malloc(strlen(orig) * sizeof(gchar));
   for (c = orig; *c;)
   {
     switch (*c)
@@ -63,11 +62,15 @@
       	break;
 
     	default:
-			buf[currChar++] = *c++;
+			g_string_append_c(buf,  *c++);
     }
   }
 
-  return buf;
+  ret = g_strdup(buf->str);
+
+  g_string_free(buf, TRUE);
+
+  return ret;
 }
 
 void

Modified: trunk/ui/main.glade
==============================================================================
--- trunk/ui/main.glade	(original)
+++ trunk/ui/main.glade	Mon Jun 30 09:54:58 2008
@@ -466,12 +466,16 @@
       </child>
 
       <child>
-	<widget class="GtkVBox" id="vbox5">
+	<widget class="GtkVBox" id="content_box">
 	  <property name="visible">True</property>
 	  <property name="homogeneous">False</property>
 	  <property name="spacing">0</property>
 
 	  <child>
+	    <placeholder/>
+	  </child>
+
+	  <child>
 	    <widget class="GtkNotebook" id="notebook">
 	      <property name="visible">True</property>
 	      <property name="show_tabs">False</property>
@@ -547,6 +551,7 @@
 
 		      <child>
 			<widget class="GtkTextView" id="text_view">
+			  <property name="visible">True</property>
 			  <property name="can_focus">True</property>
 			  <property name="editable">True</property>
 			  <property name="overwrite">False</property>

Modified: trunk/ui/prefs.glade
==============================================================================
--- trunk/ui/prefs.glade	(original)
+++ trunk/ui/prefs.glade	Mon Jun 30 09:54:58 2008
@@ -584,6 +584,65 @@
 			  <property name="fill">False</property>
 			</packing>
 		      </child>
+
+		      <child>
+			<widget class="GtkHBox" id="hbox38">
+			  <property name="visible">True</property>
+			  <property name="homogeneous">False</property>
+			  <property name="spacing">0</property>
+
+			  <child>
+			    <widget class="GtkLabel" id="label51">
+			      <property name="visible">True</property>
+			      <property name="label" translatable="yes">
+Mud Sound Protocol:
+</property>
+			      <property name="use_underline">False</property>
+			      <property name="use_markup">False</property>
+			      <property name="justify">GTK_JUSTIFY_LEFT</property>
+			      <property name="wrap">False</property>
+			      <property name="selectable">False</property>
+			      <property name="xalign">0.5</property>
+			      <property name="yalign">0.5</property>
+			      <property name="xpad">0</property>
+			      <property name="ypad">0</property>
+			      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+			      <property name="width_chars">-1</property>
+			      <property name="single_line_mode">False</property>
+			      <property name="angle">0</property>
+			    </widget>
+			    <packing>
+			      <property name="padding">0</property>
+			      <property name="expand">False</property>
+			      <property name="fill">True</property>
+			    </packing>
+			  </child>
+
+			  <child>
+			    <widget class="GtkCheckButton" id="msp_check">
+			      <property name="visible">True</property>
+			      <property name="can_focus">True</property>
+			      <property name="label" translatable="yes">Enable Remote Downloading</property>
+			      <property name="use_underline">True</property>
+			      <property name="relief">GTK_RELIEF_NORMAL</property>
+			      <property name="focus_on_click">True</property>
+			      <property name="active">False</property>
+			      <property name="inconsistent">False</property>
+			      <property name="draw_indicator">True</property>
+			    </widget>
+			    <packing>
+			      <property name="padding">0</property>
+			      <property name="expand">True</property>
+			      <property name="fill">True</property>
+			    </packing>
+			  </child>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
 		    </widget>
 		    <packing>
 		      <property name="tab_expand">False</property>



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