changeset 11660:a3302d271199

[gaim-migrate @ 13945] Thanks to the hard work of Eoin 'ecoffey' Coffey, here is the mono plugin loader. It needs a lot of api wrapping a bit more autotools loving, but with the basic API that is wrapped, it works quite well. committer: Tailor Script <tailor@pidgin.im>
author Gary Kramlich <grim@reaperworld.com>
date Fri, 14 Oct 2005 05:00:17 +0000
parents d9a7befbc3f1
children 8ebc2219fae3
files COPYRIGHT configure.ac plugins/Makefile.am plugins/mono/.cvsignore plugins/mono/BooPlugin.boo plugins/mono/GetBuddyBack.cs plugins/mono/MPlugin.cs plugins/mono/Makefile.am plugins/mono/api/.cvsignore plugins/mono/api/Buddy.cs plugins/mono/api/BuddyList.cs plugins/mono/api/Debug.cs plugins/mono/api/Event.cs plugins/mono/api/GaimPlugin.cs plugins/mono/api/Makefile.am plugins/mono/api/Signal.cs plugins/mono/loader/.cvsignore plugins/mono/loader/Makefile.am plugins/mono/loader/blist-glue.c plugins/mono/loader/debug-glue.c plugins/mono/loader/mono-glue.h plugins/mono/loader/mono-helper.c plugins/mono/loader/mono-helper.h plugins/mono/loader/mono.c plugins/mono/loader/signal-glue.c
diffstat 25 files changed, 1004 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Fri Oct 14 03:47:37 2005 +0000
+++ b/COPYRIGHT	Fri Oct 14 05:00:17 2005 +0000
@@ -44,6 +44,7 @@
 Vincas Ciziunas
 Jonathan Clark
 Joe Clarke
+Eoin Coffey
 Jason Cohen
 Todd Cohen
 Nathan Conrad
--- a/configure.ac	Fri Oct 14 03:47:37 2005 +0000
+++ b/configure.ac	Fri Oct 14 05:00:17 2005 +0000
@@ -294,6 +294,7 @@
 AM_CONDITIONAL(DYNAMIC_ZEPHYR, test "x$dynamic_zephyr" = "xyes")
 
 AC_ARG_ENABLE(audio,   [  --disable-audio         compile without libao/libaudiofile for sound playing],,enable_audio=yes)
+AC_ARG_ENABLE(mono,    [  --disable-mono		  compile without Mono runtime support],,enable_mono=yes)
 AC_ARG_ENABLE(plugins, [  --disable-plugins       compile without plugin support],,enable_plugins=yes)
 AC_ARG_ENABLE(perl,    [  --disable-perl          compile without perl scripting],,enable_perl=yes)
 AC_ARG_ENABLE(tcl,     [  --disable-tcl	          compile without Tcl scripting],,enable_tcl=yes)
@@ -571,6 +572,45 @@
 
 GC_TM_GMTOFF
 
+dnl #######################################################################
+dnl # Check for Mono support
+dnl #######################################################################
+
+if test "$enable_mono" = yes ; then
+	AC_MSG_CHECKING(for Mono compile flags)
+	MONO_CFLAGS=`pkg-config --cflags mono 2> /dev/null`
+	if test $? != 0 ; then
+		AC_MSG_RESULT([not found, building without mono.])
+		MONO_CFLAGS=
+		MONO_LIBS=
+		enable_mono = no
+	else
+		MONO_LIBS=`pkg-config --libs mono 2> /dev/null`
+		AC_MSG_RESULT(ok)
+		
+		oldLIBS="$LIBS"
+		LIBS="$LIBS $MONO_LIBS"
+		AC_MSG_CHECKING(for libmono)
+		AC_CHECK_FUNCS(mono_jit_init, [], enable_mono=no)
+		LIBS="$oldLIBS"
+		
+		oldCPPFLAGS="$CPPFLAGS"
+		CPPFLAGS="$CPPFLAGS $MONO_CFLAGS"
+		AC_CHECK_HEADERS(mono/jit/jit.h, [], enable_mono=no)
+		AC_CHECK_HEADERS(mono/metadata/object.h, [], enable_mono=no)
+		CPPFLAGS="$oldCPPFLAGS"
+		
+		AC_DEFINE(ENABLE_MONO, 1, [Define if mono enabled.])
+	fi
+else
+	MONO_CFLAGS=
+	MONO_LIBS=
+	enable_mono = no
+fi
+
+AC_SUBST(MONO_CFLAGS)
+AC_SUBST(MONO_LIBS)
+AM_CONDITIONAL(USE_MONO, test "x$enable_mono" = "xyes")
 
 dnl #######################################################################
 dnl # Check for Perl support
@@ -1379,6 +1419,9 @@
 		   plugins/docklet/Makefile
 		   plugins/gevolution/Makefile
 		   plugins/gestures/Makefile
+		   plugins/mono/Makefile
+		   plugins/mono/api/Makefile
+		   plugins/mono/loader/Makefile
 		   plugins/musicmessaging/Makefile
 		   plugins/perl/Makefile
 		   plugins/perl/common/Makefile.PL
@@ -1421,6 +1464,7 @@
 echo SSL Library/Libraries......... : $msg_ssl
 echo
 echo Build with Plugin support..... : $enable_plugins
+echo Build with Mono support....... : $enable_mono
 echo Build with Perl support....... : $enable_perl
 echo Build with Tcl support........ : $enable_tcl
 echo Build with Tk support......... : $enable_tk
--- a/plugins/Makefile.am	Fri Oct 14 03:47:37 2005 +0000
+++ b/plugins/Makefile.am	Fri Oct 14 05:00:17 2005 +0000
@@ -19,6 +19,10 @@
 MUSICMESSAGING_DIR = musicmessaging
 endif
 
+if USE_MONO
+MONO_DIR = mono
+endif
+
 SUBDIRS = \
 	docklet \
 	$(GEVOLUTION_DIR) \
@@ -27,7 +31,8 @@
 	ssl \
 	$(TCL_DIR) \
 	ticker \
-	$(MUSICMESSAGING_DIR)
+	$(MUSICMESSAGING_DIR) \
+	$(MONO_DIR)
 
 plugindir = $(libdir)/gaim
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/.cvsignore	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,3 @@
+Makefile
+Makefile.in
+*.dll
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/BooPlugin.boo	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,22 @@
+import Gaim
+
+class BooPlugin(GaimPlugin):
+
+	def handle(*args as (object)):
+		b as Buddy
+		b = args[0]
+		Debug.debug(Debug.INFO, "booplugin",  "Boo Plugin knows that " + b.Alias + " is away\n")
+		
+	override def Load():
+		Debug.debug(Debug.INFO, "booplugin", "loading...\n")
+		BuddyList.OnBuddyAway.connect(self, handle)
+		
+	override def Unload():
+		Debug.debug(Debug.INFO, "booplugin", "unloading...\n")
+		
+	override def Destroy():
+		Debug.debug(Debug.INFO, "booplugin", "destroying...\n")
+		
+	override def Info():
+		return GaimPluginInfo("Boo Plugin", "0.1", "Test Boo Plugin", "Longer Description", "Eoin Coffey", "urled")
+		
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/GetBuddyBack.cs	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,32 @@
+using Gaim;
+
+public class GetBuddyBack : GaimPlugin
+{
+	public void HandleSig(object[] args)
+	{
+		Buddy buddy = (Buddy)args[0];
+		
+		Debug.debug(Debug.INFO, "buddyback", "buddy " + buddy.Name + " is back!\n");
+	}
+	
+	public override void Load()
+	{
+		Debug.debug(Debug.INFO, "buddyback", "loading...\n");
+		
+		/*Signal.connect(BuddyList.GetHandle(), this, "buddy-back", new Signal.Handler(HandleSig));*/
+		BuddyList.OnBuddyBack.connect(this, new Signal.Handler(HandleSig));
+	}
+	
+	public override void Unload()
+	{
+	}
+	
+	public override void Destroy()
+	{
+	}
+	
+	public override GaimPluginInfo Info()
+	{
+		return new GaimPluginInfo("C# Get Buddy Back", "0.1", "Prints when a Buddy returns", "Longer Description", "Eoin Coffey", "urled");
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/MPlugin.cs	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,34 @@
+using Gaim;
+
+public class MPlugin : GaimPlugin
+{
+	public void HandleSig(object[] args)
+	{
+		Buddy buddy = (Buddy)args[0];
+		
+		Debug.debug(Debug.INFO, "mplug", "buddy " + buddy.Name + " went away\n");
+	}
+	
+	public override void Load()
+	{
+		Debug.debug(Debug.INFO, "mplug", "loading...\n");
+		
+		/*Signal.connect(BuddyList.GetHandle(), this, "buddy-away", new Signal.Handler(HandleSig));*/
+		BuddyList.OnBuddyAway.connect(this, new Signal.Handler(HandleSig));
+	}
+	
+	public override void Unload()
+	{
+		Debug.debug(Debug.INFO, "mplug", "unloading...\n");
+	}
+	
+	public override void Destroy()
+	{
+		Debug.debug(Debug.INFO, "mplug", "destroying...\n");
+	}
+	
+	public override GaimPluginInfo Info()
+	{
+		return new GaimPluginInfo("C# Plugin", "0.1", "Test C# Plugin", "Longer Description", "Eoin Coffey", "urled");
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/Makefile.am	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,15 @@
+SUBDIRS = api loader
+
+TARGETS = MPlugin.dll GetBuddyBack.dll
+
+all: $(TARGETS)
+	
+install-exec-am:
+	$(INSTALL) -m 644 $(TARGETS) $(libdir)/gaim
+
+clean-generic:
+	rm -rf $(TARGETS)
+
+SUFFIXES = .cs .dll
+.cs.dll:
+	mcs -t:library -lib:./api -out:$*.dll -r:GaimAPI.dll $*.cs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/api/.cvsignore	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,3 @@
+GaimAPI.dll
+Makefile
+Makefile.in
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/api/Buddy.cs	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,11 @@
+namespace Gaim
+{
+	public class Buddy
+	{
+		private string name;
+		private string alias;
+				
+		public string Name { get { return name; } set { name = value; } }
+		public string Alias { get { return alias; } set { alias = value; } }
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/api/BuddyList.cs	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,21 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Gaim
+{
+	public class BuddyList
+	{
+		[MethodImplAttribute(MethodImplOptions.InternalCall)]
+		extern private static IntPtr _get_handle();
+
+		private static IntPtr handle = _get_handle();
+		
+		public static Event OnBuddyAway = new Event(handle, "buddy-away");
+		public static Event OnBuddyBack = new Event(handle, "buddy-back");
+		
+		public static IntPtr GetHandle()
+		{
+			return _get_handle();
+		}		
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/api/Debug.cs	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,28 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Gaim
+{
+	public class Debug
+	{
+		public static int ALL = 0;
+		public static int MISC = 1;
+		public static int INFO = 2;
+		public static int WARNING = 3;
+		public static int ERROR = 4;
+		public static int FATAL = 5;
+		
+		[MethodImplAttribute(MethodImplOptions.InternalCall)]
+		extern private static void _debug(int type, string cat, string str);
+		
+		public static void debug(int type, string cat, string format)
+		{
+			_debug(type, cat, format);
+		}
+		
+		public static void debug(int type, string cat, string format, params object[] args)
+		{
+			_debug(type, cat, String.Format(format, args));
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/api/Event.cs	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,21 @@
+using System;
+
+namespace Gaim
+{
+	public class Event
+	{
+		private IntPtr handle;
+		private string signal;
+		
+		public Event(IntPtr h, string s)
+		{
+			handle = h;
+			signal = s;
+		}
+	
+		public void connect(object plugin, Signal.Handler handler)
+		{
+			Signal.connect(handle, plugin, signal, handler);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/api/GaimPlugin.cs	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,38 @@
+namespace Gaim
+{
+	public class GaimPluginInfo
+	{
+		private string name;
+		private string version;
+		private string summary;
+		private string description;
+		private string author;
+		private string homepage;
+		
+		public GaimPluginInfo(string name, string version, string summary, string description, string author, string homepage)
+		{
+			this.name = name;
+			this.version = version;
+			this.summary = summary;
+			this.description = description;
+			this.author = author;
+			this.homepage = homepage;	
+		}
+		
+		public string Name { get { return name; } }
+		public string Version { get { return version; } }
+		public string Summary { get { return summary; } }
+		public string Description { get { return description; } }
+		public string Author { get { return author; } }
+		public string Homepage { get { return homepage; } }
+	}
+	
+	abstract public class GaimPlugin
+	{	
+		public abstract void Load();
+		public abstract void Unload();
+		public abstract void Destroy();
+		
+		public abstract GaimPluginInfo Info();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/api/Makefile.am	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,22 @@
+SOURCES=\
+	GaimPlugin.cs \
+	Debug.cs \
+	BuddyList.cs \
+	Buddy.cs \
+	Signal.cs \
+	Event.cs
+
+TARGET=GaimAPI.dll
+
+all: $(TARGET)
+
+$(TARGET): $(SOURCES)
+	mcs -t:library -out:$(TARGET) $(SOURCES)
+
+.PHONY: install clean
+
+install:
+	$(INSTALL) -m 644 $(TARGET) $(libdir)/gaim
+	
+clean:
+	rm -rf $(TARGET)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/api/Signal.cs	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,18 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Gaim
+{
+	public class Signal
+	{
+		[MethodImplAttribute(MethodImplOptions.InternalCall)]
+		extern private static int _connect(IntPtr handle, object plugin, string signal, object evnt);
+		
+		public delegate void Handler(object[] args);
+		
+		public static int connect(IntPtr handle, object plugin, string signal, object evnt)
+		{
+			return _connect(handle, plugin, signal, evnt);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/loader/.cvsignore	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,7 @@
+.deps
+.libs
+Makefile
+Makefile.in
+*.la
+*.lo
+*.loT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/loader/Makefile.am	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,22 @@
+plugindir = $(libdir)/gaim
+
+plugin_LTLIBRARIES = mono.la
+
+mono_la_SOURCES	= \
+	mono.c \
+	mono-helper.c \
+	debug-glue.c \
+	signal-glue.c \
+	blist-glue.c
+
+mono_la_LDFLAGS  = -module -avoid-version
+
+mono_la_LIBADD = $(MONO_LIBS)
+
+AM_CPPFLAGS = \
+	-DVERSION=\"$(VERSION)\" \
+	-I$(top_srcdir) \
+	-I$(top_srcdir)/src \
+	$(DEBUG_CFLAGS) \
+	$(PLUGIN_CFLAGS) \
+	$(MONO_CFLAGS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/loader/blist-glue.c	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,35 @@
+#include <string.h>
+#include "blist.h"
+#include "mono-helper.h"
+
+MonoObject* gaim_blist_get_handle_glue(void)
+{
+	void *handle = gaim_blist_get_handle();
+	
+	return mono_value_box(mono_loader_get_domain(), mono_get_intptr_class(), &handle);
+}
+
+MonoObject* gaim_blist_build_buddy_object(void* data)
+{
+	MonoObject *obj = NULL;
+	MonoClass *klass = NULL;
+			
+	GaimBuddy *buddy = (GaimBuddy*)data;
+	
+	klass = mono_class_from_name(mono_loader_get_api_image(), "Gaim", "Buddy");
+	if (!klass) {
+		gaim_debug(GAIM_DEBUG_FATAL, "mono", "couldn't build the class!\n");
+	}
+	
+	obj = mono_object_new(mono_loader_get_domain(), klass);
+	if (!obj) {
+		gaim_debug(GAIM_DEBUG_FATAL, "mono", "couldn't create the object!\n");
+	}
+	
+	mono_runtime_object_init(obj);
+	
+	mono_loader_set_prop_string(obj, "Name", (char*)gaim_buddy_get_name(buddy));
+	mono_loader_set_prop_string(obj, "Alias", (char*)gaim_buddy_get_alias(buddy));
+	
+	return obj;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/loader/debug-glue.c	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,16 @@
+#include "mono-glue.h"
+#include "debug.h"
+
+void gaim_debug_glue(int type, MonoString *cat, MonoString *str)
+{
+	char *ccat;
+	char *cstr;
+	
+	ccat = mono_string_to_utf8(cat);
+	cstr = mono_string_to_utf8(str);
+	
+	gaim_debug(type, ccat, cstr);
+	
+	g_free(ccat);
+	g_free(cstr);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/loader/mono-glue.h	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,17 @@
+#ifndef _GAIM_MONO_LOADER_GLUE_H_
+#define _GAIM_MONO_LOADER_GLUE_H_
+
+#include <mono/jit/jit.h>
+#include <mono/metadata/object.h>
+#include <mono/metadata/environment.h>
+#include <mono/metadata/assembly.h>
+
+void gaim_debug_glue(int type, MonoString *cat, MonoString *str);
+
+int gaim_signal_connect_glue(MonoObject *h, MonoObject *plugin, MonoString *signal, MonoObject *func);
+
+MonoObject* gaim_blist_get_handle_glue(void);
+
+MonoObject* gaim_blist_build_buddy_object(void* buddy);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/loader/mono-helper.c	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,166 @@
+/*
+ * Mono Plugin Loader
+ *
+ * -- Thanks to the perl plugin loader for all the great tips ;-)
+ *
+ * Eoin Coffey
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <string.h>
+#include "mono-helper.h"
+#include "mono-glue.h"
+#include "value.h"
+
+MonoClass* mono_loader_find_plugin_class(MonoImage *image)
+{
+	MonoClass *klass, *pklass = NULL;
+	int i, total;
+
+	total = mono_image_get_table_rows (image, MONO_TABLE_TYPEDEF);
+	for (i = 1; i <= total; ++i) {
+		klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
+		pklass = mono_class_get_parent(klass);
+		if (pklass) 
+			if (strcmp("GaimPlugin", mono_class_get_name(pklass)) == 0)
+				return klass;
+	}
+	
+	return NULL;
+}
+
+void mono_loader_set_prop_string(MonoObject *obj, char *field, char *data)
+{
+	MonoClass *klass;
+	MonoProperty *prop;
+	MonoString *str;
+	gpointer args[1];
+	
+	klass = mono_object_get_class(obj);
+	
+	prop = mono_class_get_property_from_name(klass, field);
+	
+	str = mono_string_new(mono_loader_get_domain(), data);
+	
+	args[0] = str;
+	
+	mono_property_set_value(prop, obj, args, NULL);
+}
+
+gchar* mono_loader_get_prop_string(MonoObject *obj, char *field)
+{
+	MonoClass *klass;
+	MonoProperty *prop;
+	MonoString *str;
+	
+	klass = mono_object_get_class(obj);
+	
+	prop = mono_class_get_property_from_name(klass, field);
+	
+	str = (MonoString*)mono_property_get_value(prop, obj, NULL, NULL);
+	
+	return mono_string_to_utf8(str);
+}
+
+gboolean mono_loader_is_api_dll(MonoImage *image)
+{	
+	MonoClass *klass;
+	int i, total;
+
+	total = mono_image_get_table_rows (image, MONO_TABLE_TYPEDEF);
+	for (i = 1; i <= total; ++i) {
+		klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
+		if (strcmp(mono_class_get_name(klass), "Debug") == 0)
+			if (strcmp(mono_class_get_namespace(klass), "Gaim") == 0) {
+				mono_loader_set_api_image(image);
+				return TRUE;
+			}
+	}
+	
+	return FALSE;
+}
+
+MonoObject* mono_loader_object_from_gaim_type(GaimType type, gpointer data)
+{
+	return NULL;
+}
+
+MonoObject* mono_loader_object_from_gaim_subtype(GaimSubType type, gpointer data)
+{
+	MonoObject *obj;
+	
+	switch (type) {
+		case GAIM_SUBTYPE_BLIST_BUDDY:
+			obj = gaim_blist_build_buddy_object(data);
+		break;
+		default:
+		break;
+	}
+	
+	return obj;
+}
+
+static MonoDomain *_domain;
+
+MonoDomain* mono_loader_get_domain(void)
+{
+	return _domain;
+}
+
+void mono_loader_set_domain(MonoDomain *d)
+{
+	_domain = d;
+}
+
+static MonoImage *_api_image = NULL;
+
+void mono_loader_set_api_image(MonoImage *image)
+{
+	_api_image = image;
+}
+
+MonoImage* mono_loader_get_api_image()
+{
+	return _api_image;
+}
+
+void mono_loader_init_internal_calls(void)
+{
+	mono_add_internal_call("Gaim.Debug::_debug", gaim_debug_glue);
+	mono_add_internal_call("Gaim.Signal::_connect", gaim_signal_connect_glue);
+	mono_add_internal_call("Gaim.BuddyList::_get_handle", gaim_blist_get_handle_glue);
+}
+
+static GHashTable *plugins_hash = NULL;
+
+void mono_loader_add_plugin(GaimMonoPlugin *plugin)
+{
+	if (!plugins_hash)
+		plugins_hash = g_hash_table_new(NULL, NULL);
+		
+	g_hash_table_insert(plugins_hash, plugin->klass, plugin);
+}
+
+gboolean mono_loader_remove_plugin(GaimMonoPlugin *plugin)
+{
+	return g_hash_table_remove(plugins_hash, plugin->klass);
+}
+
+gpointer mono_loader_find_plugin(GaimMonoPlugin *plugin)
+{
+	return g_hash_table_lookup(plugins_hash, plugin->klass);
+}
+
+gpointer mono_loader_find_plugin_by_class(MonoClass *klass)
+{
+	return g_hash_table_lookup(plugins_hash, klass);
+}
+
+GHashTable* mono_loader_get_plugin_hash()
+{
+	return plugins_hash;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/loader/mono-helper.h	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,59 @@
+#ifndef _GAIM_MONO_LOADER_MONO_HELPER_H_
+#define _GAIM_MONO_LOADER_MONO_HELPER_H_
+
+#include <mono/jit/jit.h>
+#include <mono/metadata/object.h>
+#include <mono/metadata/environment.h>
+#include <mono/metadata/assembly.h>
+#include <mono/metadata/debug-helpers.h>
+#include <mono/metadata/tokentype.h>
+#include "plugin.h"
+#include "value.h"
+#include "debug.h"
+
+typedef struct {
+	GaimPlugin *plugin;
+	MonoAssembly *assm;
+	MonoClass *klass;
+	MonoObject *obj;	
+	MonoMethod *init;
+	MonoMethod *load;
+	MonoMethod *unload;
+	MonoMethod *destroy;
+} GaimMonoPlugin;
+
+MonoClass* mono_loader_find_plugin_class(MonoImage *image);
+
+gchar* mono_loader_get_prop_string(MonoObject *obj, char *field);
+
+void mono_loader_set_prop_string(MonoObject *obj, char *field, char *data);
+
+gboolean mono_loader_is_api_dll(MonoImage *image);
+
+MonoDomain* mono_loader_get_domain(void);
+
+void mono_loader_set_domain(MonoDomain *d);
+
+void mono_loader_init_internal_calls(void);
+
+MonoObject* mono_loader_object_from_gaim_type(GaimType type, gpointer data);
+
+MonoObject* mono_loader_object_from_gaim_subtype(GaimSubType type, gpointer data);
+
+void mono_loader_set_api_image(MonoImage *image);
+
+MonoImage* mono_loader_get_api_image();
+
+/* hash table stuff; probably don't need it anymore */
+
+void mono_loader_add_plugin(GaimMonoPlugin *plugin);
+
+gboolean mono_loader_remove_plugin(GaimMonoPlugin *plugin);
+
+gpointer mono_loader_find_plugin(GaimMonoPlugin *plugin);
+
+gpointer mono_loader_find_plugin_by_class(MonoClass *klass);
+
+GHashTable* mono_loader_get_plugin_hash();
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/loader/mono.c	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,241 @@
+/*
+ * Mono Plugin Loader
+ *
+ * -- Thanks to the perl plugin loader for all the great tips ;-)
+ *
+ * Eoin Coffey
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "internal.h"
+#include "debug.h"
+#include "plugin.h"
+#include "version.h"
+#include "mono-helper.h"
+
+#define MONO_PLUGIN_ID "core-mono"
+
+/* This is where our code executes */
+static MonoDomain *domain;
+
+/* probes the given plugin to determine if its a plugin */
+static gboolean probe_mono_plugin(GaimPlugin *plugin)
+{
+	MonoAssembly *assm;
+	MonoMethod *m = NULL;
+	MonoMethod *info_method = NULL;
+	MonoObject *plugin_info;
+	gboolean found_load = FALSE, found_unload = FALSE, found_destroy = FALSE, found_info = FALSE;
+	gpointer iter = NULL;
+	
+	GaimPluginInfo *info;
+	GaimMonoPlugin *mplug;
+	
+	char *file = plugin->path;
+	
+	assm = mono_domain_assembly_open(domain, file);
+	
+	if (!assm) {
+		return FALSE;
+	} 
+		
+	gaim_debug(GAIM_DEBUG_INFO, "mono", "Probing plugin\n");
+	
+	if (mono_loader_is_api_dll(mono_assembly_get_image(assm))) {
+		gaim_debug(GAIM_DEBUG_INFO, "mono", "Found our GaimAPI.dll\n");
+		return FALSE;
+	}
+		
+	info = g_new0(GaimPluginInfo, 1);
+	mplug = g_new0(GaimMonoPlugin, 1);
+		
+	mplug->assm = assm;
+		
+	mplug->klass = mono_loader_find_plugin_class(mono_assembly_get_image(mplug->assm));
+	if (!mplug->klass) {
+		gaim_debug(GAIM_DEBUG_ERROR, "mono", "no plugin class in \'%s\'\n", file);
+		return FALSE;
+	}
+	
+	mplug->obj = mono_object_new(domain, mplug->klass);
+	if (!mplug->obj) {
+		gaim_debug(GAIM_DEBUG_ERROR, "mono", "obj not valid\n");
+		return FALSE;
+	}
+	
+	mono_runtime_object_init(mplug->obj);
+	
+	while ((m = mono_class_get_methods(mplug->klass, &iter))) {
+		if (strcmp(mono_method_get_name(m), "Load") == 0) {
+			mplug->load = m;
+			found_load = TRUE;
+		} else if (strcmp(mono_method_get_name(m), "Unload") == 0) {
+			mplug->unload = m;
+			found_unload = TRUE;
+		} else if (strcmp(mono_method_get_name(m), "Destroy") == 0) {
+			mplug->destroy = m;
+			found_destroy = TRUE;
+		} else if (strcmp(mono_method_get_name(m), "Info") == 0) {
+			info_method = m;
+			found_info = TRUE;
+		}
+	}
+	
+	if (!(found_load && found_unload && found_destroy && found_info)) {
+		gaim_debug(GAIM_DEBUG_ERROR, "mono", "did not find the required methods\n");
+		return FALSE;
+	}
+	
+	plugin_info = mono_runtime_invoke(info_method, mplug->obj, NULL, NULL);
+	
+	/* now that the methods are filled out we can populate
+	   the info struct with all the needed info */
+	
+	info->name = mono_loader_get_prop_string(plugin_info, "Name");
+	info->version = mono_loader_get_prop_string(plugin_info, "Version");
+	info->summary = mono_loader_get_prop_string(plugin_info, "Summary");
+	info->description = mono_loader_get_prop_string(plugin_info, "Description");
+	info->author = mono_loader_get_prop_string(plugin_info, "Author");
+	info->homepage = mono_loader_get_prop_string(plugin_info, "Homepage");
+		
+	info->magic = GAIM_PLUGIN_MAGIC;
+	info->major_version = GAIM_MAJOR_VERSION;
+	info->minor_version = GAIM_MINOR_VERSION;
+	info->type = GAIM_PLUGIN_STANDARD;
+		
+	/* this plugin depends on us; duh */
+	info->dependencies = g_list_append(info->dependencies, MONO_PLUGIN_ID);
+	mplug->plugin = plugin;
+				
+	plugin->info = info;
+	info->extra_info = mplug;
+	
+	mono_loader_add_plugin(mplug);
+	
+	return gaim_plugin_register(plugin);
+}
+
+/* Loads a Mono Plugin by calling 'load' in the class */
+static gboolean load_mono_plugin(GaimPlugin *plugin)
+{
+	GaimMonoPlugin *mplug;
+	
+	gaim_debug(GAIM_DEBUG_INFO, "mono", "Loading plugin\n");
+	
+	mplug = (GaimMonoPlugin*)plugin->info->extra_info;
+	
+	mono_runtime_invoke(mplug->load, mplug->obj, NULL, NULL);
+	
+	return TRUE;
+}
+
+/* Unloads a Mono Plugin by calling 'unload' in the class */
+static gboolean unload_mono_plugin(GaimPlugin *plugin)
+{
+	GaimMonoPlugin *mplug;
+	
+	gaim_debug(GAIM_DEBUG_INFO, "mono", "Unloading plugin\n");
+	
+	mplug = (GaimMonoPlugin*)plugin->info->extra_info;
+	
+	gaim_signals_disconnect_by_handle((gpointer)mplug->klass);
+	
+	mono_runtime_invoke(mplug->unload, mplug->obj, NULL, NULL);
+	
+	return TRUE;
+}
+
+/* Destroys a Mono Plugin by calling 'destroy' in the class,
+   and cleaning up all the malloced memory */
+static gboolean destroy_mono_plugin(GaimPlugin *plugin)
+{
+	GaimMonoPlugin *mplug;
+	
+	gaim_debug(GAIM_DEBUG_INFO, "mono", "Destroying plugin\n");
+	
+	mplug = (GaimMonoPlugin*)plugin->info->extra_info;
+	
+	mono_runtime_invoke(mplug->destroy, mplug->obj, NULL, NULL);
+	
+	if (plugin->info) {
+		if (plugin->info->name) g_free(plugin->info->name);
+		if (plugin->info->version) g_free(plugin->info->version);
+		if (plugin->info->summary) g_free(plugin->info->summary);
+		if (plugin->info->description) g_free(plugin->info->description);
+		if (plugin->info->author) g_free(plugin->info->author);
+		if (plugin->info->homepage) g_free(plugin->info->homepage);
+	}
+	
+	if (mplug) {
+		if (mplug->assm) {
+			mono_assembly_close(mplug->assm);
+		}
+		
+		g_free(mplug);
+		mplug = NULL;
+	}
+	
+	return TRUE;
+}
+
+gboolean plugin_destroy(GaimPlugin *plugin)
+{
+	mono_jit_cleanup(domain);	
+	
+	return TRUE;
+}
+
+static GaimPluginLoaderInfo loader_info =
+{
+	NULL,
+	probe_mono_plugin,
+	load_mono_plugin,
+	unload_mono_plugin,
+	destroy_mono_plugin
+};
+
+static GaimPluginInfo info =
+{
+	GAIM_PLUGIN_MAGIC,
+	GAIM_MAJOR_VERSION,
+	GAIM_MINOR_VERSION,
+	GAIM_PLUGIN_LOADER,
+	NULL,
+	0,
+	NULL,
+	GAIM_PRIORITY_DEFAULT,
+	MONO_PLUGIN_ID,
+	N_("Mono Plugin Loader"),
+	VERSION,
+	N_("Loads .NET plugins with Mono."),
+	N_("Loads .NET plugins with Mono."),
+	"Eoin Coffey <ecoffey@simla.colostate.edu>",
+	GAIM_WEBSITE,
+	NULL,
+	NULL,
+	plugin_destroy,
+	NULL,
+	&loader_info,
+	NULL,
+	NULL
+};
+
+/* Creates the domain to execute in, and setups our CS Gaim API (note:
+   in the future the 'mono_add_internal_call' will be spread through out
+   the source to whatever module is exposing the API; this function will
+   simply call helper functions to do so) */
+static void init_plugin(GaimPlugin *plugin)
+{
+	domain = mono_jit_init("gaim");
+	
+	mono_loader_set_domain(domain);
+	
+	mono_loader_init_internal_calls();
+	
+	loader_info.exts = g_list_append(loader_info.exts, "dll");
+}
+
+GAIM_INIT_PLUGIN(mono, init_plugin, info)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mono/loader/signal-glue.c	Fri Oct 14 05:00:17 2005 +0000
@@ -0,0 +1,122 @@
+#include "mono-glue.h"
+#include "mono-helper.h"
+#include "debug.h"
+#include "blist.h"
+#include "signals.h"
+#include "value.h"
+
+typedef struct {
+	MonoObject *func;
+	char *signal;
+	GaimValue **values;
+	GaimValue *ret_value;
+	int num_vals;
+} SignalData;
+
+static GaimCallback get_callback(SignalData *sig_data);
+
+static gpointer dispatch_callback(SignalData *sig_data, int num_vals, ...)
+{
+	MonoArray *array;
+	MonoObject *obj;
+	int i;
+	gpointer meth_args[1];
+	gpointer gaim_obj;
+	
+	va_list args;
+	
+	va_start(args, num_vals);
+	
+	array = mono_array_new(mono_loader_get_domain(), mono_get_object_class(), num_vals);
+	
+	for (i = 0; i < num_vals; i++) {
+		if (gaim_value_get_type(sig_data->values[i]) == GAIM_TYPE_SUBTYPE) {
+			gaim_obj = va_arg(args, gpointer);
+			obj = mono_loader_object_from_gaim_subtype(gaim_value_get_subtype(sig_data->values[i]), gaim_obj);
+			mono_array_set(array, MonoObject*, i, obj);
+		} else {
+			gaim_obj = va_arg(args, gpointer);
+			obj = mono_loader_object_from_gaim_type(gaim_value_get_type(sig_data->values[i]), gaim_obj);
+			mono_array_set(array, MonoObject*, i, obj);
+		}
+	}
+	
+	va_end(args);
+	
+	meth_args[0] = array;
+	
+	return mono_runtime_delegate_invoke(sig_data->func, meth_args, NULL);	
+}
+
+static void cb_void__pointer(void *arg1, void *data)
+{
+	dispatch_callback((SignalData*)data, ((SignalData*)data)->num_vals, arg1);
+	
+}
+
+int gaim_signal_connect_glue(MonoObject* h, MonoObject *plugin, MonoString *signal, MonoObject *func)
+{
+	char *sig;
+	void **instance = NULL;
+	SignalData *sig_data;
+		
+	sig = mono_string_to_utf8(signal);
+	gaim_debug(GAIM_DEBUG_INFO, "mono", "connecting signal: %s\n", sig);
+	
+	instance = (void*)mono_object_unbox(h);
+
+	sig_data = g_new0(SignalData, 1);
+	
+	sig_data->func = func;
+	sig_data->signal = sig;
+	
+	gaim_signal_get_values(*instance, sig, &sig_data->ret_value, &sig_data->num_vals, &sig_data->values);
+
+	return gaim_signal_connect(*instance, sig, (gpointer)mono_object_get_class(plugin), get_callback(sig_data), (gpointer)sig_data);
+}
+
+static int determine_index(GaimType type)
+{
+	switch (type) {
+		case GAIM_TYPE_SUBTYPE:
+		case GAIM_TYPE_STRING:
+		case GAIM_TYPE_OBJECT:
+		case GAIM_TYPE_POINTER:
+		case GAIM_TYPE_BOXED:
+			return 1;
+		break;
+		default:
+			return type;
+		break;
+	}
+}
+
+static gpointer callbacks[]= { 
+										NULL,
+										cb_void__pointer,
+									};
+
+static int callbacks_array_size = sizeof(callbacks) / sizeof(GaimCallback);
+	
+
+static GaimCallback get_callback(SignalData *sig_data)
+{
+	int i, index = 0;
+
+	if (sig_data->ret_value == NULL)
+		index = 0;
+	else
+		index = gaim_value_get_type(sig_data->ret_value);
+	
+	for (i = 0; i < sig_data->num_vals; i++) {
+		index += determine_index(gaim_value_get_type(sig_data->values[i]));
+	}
+	
+	if (index >= callbacks_array_size || callbacks[index] == NULL) {
+		gaim_debug(GAIM_DEBUG_ERROR, "mono", "couldn't find a callback function for signal: %s\n", sig_data->signal);
+		return NULL;
+	}
+	
+	gaim_debug(GAIM_DEBUG_MISC, "mono", "using callback at index: %d\n", index);
+	return GAIM_CALLBACK(callbacks[index]);
+}