summary refs log tree commit diff stats
path: root/src/common/dbus
diff options
context:
space:
mode:
authorberkeviktor@aol.com <berkeviktor@aol.com>2011-02-24 04:14:30 +0100
committerberkeviktor@aol.com <berkeviktor@aol.com>2011-02-24 04:14:30 +0100
commit4a6ceffb98a0b785494f680d3776c4bfc4052f9e (patch)
tree850703c1c841ccd99f58d0b06084615aaebe782c /src/common/dbus
parentf16af8be941b596dedac3bf4e371ee2d21f4b598 (diff)
add xchat r1489
Diffstat (limited to 'src/common/dbus')
-rw-r--r--src/common/dbus/Makefile.am56
-rw-r--r--src/common/dbus/README198
-rw-r--r--src/common/dbus/apps_xchat_url_handler.schemas37
-rw-r--r--src/common/dbus/dbus-client.c118
-rw-r--r--src/common/dbus/dbus-client.h27
-rw-r--r--src/common/dbus/dbus-plugin.c1087
-rw-r--r--src/common/dbus/dbus-plugin.h31
-rw-r--r--src/common/dbus/example.c201
-rw-r--r--src/common/dbus/example.py28
-rw-r--r--src/common/dbus/marshallers.list1
-rw-r--r--src/common/dbus/org.xchat.service.service.in3
-rw-r--r--src/common/dbus/remote-object.xml142
12 files changed, 1929 insertions, 0 deletions
diff --git a/src/common/dbus/Makefile.am b/src/common/dbus/Makefile.am
new file mode 100644
index 00000000..05ee9de6
--- /dev/null
+++ b/src/common/dbus/Makefile.am
@@ -0,0 +1,56 @@
+noinst_LIBRARIES = libxchatdbus.a
+libxchatdbus_a_SOURCES =			\
+	dbus-plugin.c				\
+	dbus-plugin.h				\
+	dbus-client.c				\
+	dbus-client.h
+
+EXTRA_DIST =				\
+	remote-object.xml		\
+	apps_xchat_url_handler.schemas	\
+	marshallers.list		\
+	example.py			\
+	org.xchat.service.service.in \
+	README
+
+BUILT_SOURCES =				\
+	marshallers.h			\
+	remote-object-glue.h
+
+CLEANFILES = $(BUILT_SOURCES)
+
+INCLUDES = $(COMMON_CFLAGS) $(DBUS_CFLAGS)
+
+noinst_PROGRAMS = example
+example_SOURCES = example.c 
+example_LDADD = $(DBUS_LIBS) $(GLIB_LIBS)
+
+remote-object-glue.h: remote-object.xml
+	$(LIBTOOL) --mode=execute $(DBUS_BINDING_TOOL) --prefix=remote_object --mode=glib-server --output=$@ $<
+
+marshallers.h: marshallers.list
+	$(LIBTOOL) --mode=execute $(GLIB_GENMARSHAL)  --header --body $< > $@
+
+# Dbus service file
+servicedir = $(DBUS_SERVICES_DIR)
+service_in_files = org.xchat.service.service.in
+service_DATA = $(service_in_files:.service.in=.service)
+
+# Rule to make the service file with bindir expanded
+$(service_DATA): $(service_in_files) Makefile
+	@sed -e "s|\@bindir\@|$(bindir)|" $< > $@
+
+if DO_GCONF
+GCONF_SCHEMA_CONFIG_SOURCE = `$(GCONFTOOL) --get-default-source`
+GCONF_SCHEMA_FILE_DIR = $(sysconfdir)/gconf/schemas
+schemadir = $(GCONF_SCHEMA_FILE_DIR)
+schema_DATA = apps_xchat_url_handler.schemas
+install-data-local:
+	if test -z "$(DESTDIR)" ; then \
+		for p in $(schema_DATA) ; do \
+			GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(srcdir)/$$p; \
+		done \
+	fi
+else
+install-data-local:
+endif
diff --git a/src/common/dbus/README b/src/common/dbus/README
new file mode 100644
index 00000000..d61cf4e0
--- /dev/null
+++ b/src/common/dbus/README
@@ -0,0 +1,198 @@
+For more help you can see the xchat plugin interface documentation.
+http://www.xchat.org/docs/plugin20.html
+WARNING: The dbus interface may change in the future.
+
+You can use the "/org/xchat/Remote" object with interface "org.xchat.plugin",
+but his context can be changed by other clients at any moment and
+you may receive signal asked by other clients. So for more complex usage it's
+better to get your own remote object. Using "Connect" method on interface
+"org.xchat.connection"
+
+Available methods on org.xchat.connection interface:
+
+"Connect"
+  - Parameters:
+    - gchar*: filename
+    - gchar*: name
+    - gchar*: description
+    - gchar*: version
+  - Returns:
+    - gchar*: Your own object's path.
+
+"Disconnect"
+  No parameter, no return value. It frees your remote object.
+
+Available methods on org.xchat.plugin interface:
+
+"Command"
+  - Parameters:
+    - gchar*: the command name without the "/". (e.g. "nick pseudo")
+
+"Print"
+  - Parameters:
+    - gchar*: text to print on the xchat window.
+
+"FindContext"
+  - Parameters:
+    - gchar*: the server name. Can be NULL.
+    - gchar*: the channel name. Can be NULL.
+  - Returns:
+    - guint: context ID
+
+"GetContext"
+  - Returns:
+    - guint: current context's ID
+
+"SetContext"
+  - Parameters:
+    - guint: context ID to switch, returned by "FindContext" or "GetContext"
+  - Returns:
+    - gboolean: 1 for success, 0 for failure.
+
+"GetInfo"
+  - Parameters:
+    - gchar*: ID of the information you want.
+  - Returns:
+    - gchar*: information you requested.
+
+"GetPrefs"
+  - Parameters:
+    - gchar*: Setting name required.
+  - Returns:
+    - int: 0-Failed 1-Returned a string 2-Returned an Integer
+           3-Returned a Boolean.
+    - gchar*: the information requested if it's a string.
+    - int: the information requested if it's a integer or boolean.
+
+"HookCommand"
+  - Parameters:
+    - gchar*: Name of the command (without the forward slash).
+    - int: Priority of this command.
+    - gchar*: String of text to display when the user executes /help
+              for this command. May be NULL if you're lazy.
+    - int: Value to returns when the command is catched. See XCHAT_EAT_*.
+  - Returns:
+    - guint: The ID of the hook.
+
+"HookServer"
+  - Parameters:
+    - gchar*: Name of the server event.
+    - int: Priority of this command.
+    - int: Value to returns when the command is catched. See XCHAT_EAT_*.
+  - Returns:
+    - guint: The ID of the hook.
+
+"HookPrint"
+  - Parameters:
+    - gchar*: Name of the print event.
+    - int: Priority of this command.
+    - int: Value to returns when the command is catched. See XCHAT_EAT_*.
+  - Returns:
+    - guint: The ID of the hook.
+
+"Unhook"
+  - Parameters:
+    - guint: ID of the hook to unhook.
+      (the return value of "HookCommand", "HookServer" or "HookPrint")
+
+"ListGet"
+  - Parameters:
+    - gchar*: The list name.
+  - Returns:
+    - guint: List ID.
+
+"ListNext"
+  - Parameters:
+    - guint: List ID returned by "ListGet".
+  - Returns:
+    - gboolean: says if there is no more item in the list.
+
+"ListStr"
+  - Parameters:
+    - guint: List ID returned by "ListGet".
+    - gchar*: Name of the information needed.
+  - Returns:
+    - gchar*: The information requested.
+Warning: "context" attribut of "channels" list should be get with "ListInt"
+
+"ListInt"
+  - Parameters:
+    - guint: List ID returned by "ListGet".
+    - gchar*: Name of the information needed.
+  - Returns:
+    - guint: The information requested.
+
+"ListTime"
+  - Parameters:
+    - guint: List ID returned by "ListGet".
+    - gchar*: Name of the information needed.
+  - Returns:
+    - guint64: The information requested.
+
+"ListFields"
+  - Parameters:
+    - gchar*: The list name.
+  - Returns:
+    - gchar**: information names in this list.
+
+"ListFree"
+  - Parameters:
+    - guint: List ID returned by "ListGet".
+
+"EmitPrint"
+  - Parameters:
+    - gchar*: Text event to print.
+    - gchar**: NULL terminated array of string.
+  - Returns:
+    - gboolean: 1-Success 0-Failure.
+
+"Nickcmp"
+  - Parameters:
+    - gchar*: String to compare.
+    - gchar*: String to compare.
+  - Returns:
+    - int: An integer less than, equal to, or greater than zero if s1 is found,
+           respectively, to be less than, to match, or be greater than s2. 
+
+"Strip"
+  - Parameters:
+    - gchar*: String to strip.
+    - int: Length of the string (or -1 for NULL terminated).
+    - int: Bit-field of flags: 0-Strip mIRC colors, 1-Strip text attributes. 
+  - Returns:
+    - gchar*: striped string.
+
+"SendModes"
+  - Parameters:
+    - gchar**: NULL terminated array of targets (strings). The names of people
+               whom the action will be performed on.
+    - int: Maximum modes to send per line.
+    - gchar: Mode sign, '-' or '+'.
+    - gchar: Mode char, e.g. 'o' for Ops.
+
+
+Available signals:
+
+"ServerSignal"
+  - Parameters:
+    - gchar**: word returned by xchat.
+    - gchar**: word_eol returned bu xchat.
+    - guint: the ID of the hook. (the return value of "HookServer").
+    - guint: the ID of the context where the event come from.
+
+"CommandSignal"
+  - Parameters:
+    - gchar**: word returned by xchat.
+    - gchar**: word_eol returned bu xchat.
+    - guint: the ID of the hook. (the return value of "HookCommand").
+    - guint: the ID of the context where the event come from.
+
+"PrintSignal"
+  - Parameters:
+    - gchar**: word returned by xchat.
+    - guint: the ID of the hook. (the return value of "HookPrint").
+    - guint: the ID of the context where the event come from.
+
+"UnloadSignal"
+  emited when the user asks to unload your program.
+  Please exit(0); when received !
diff --git a/src/common/dbus/apps_xchat_url_handler.schemas b/src/common/dbus/apps_xchat_url_handler.schemas
new file mode 100644
index 00000000..10ac948d
--- /dev/null
+++ b/src/common/dbus/apps_xchat_url_handler.schemas
@@ -0,0 +1,37 @@
+<gconfschemafile>
+	<schemalist>
+		<schema>
+			<key>/schemas/desktop/gnome/url-handlers/irc/command</key>
+			<applyto>/desktop/gnome/url-handlers/irc/command</applyto>
+			<owner>xchat</owner>
+			<type>string</type>
+			<default>xchat --existing --url=%u</default>
+			<locale name="C">
+				<short>The handler for "irc://" URLs</short>
+			</locale>
+		</schema>
+
+		<schema>
+			<key>/schemas/desktop/gnome/url-handlers/irc/enabled</key>
+			<applyto>/desktop/gnome/url-handlers/irc/enabled</applyto>
+			<owner>xchat</owner>
+			<type>bool</type>
+			<default>true</default>
+			<locale name="C">
+				<short>Set it at TRUE if you want it activated</short>
+			</locale>
+		</schema>
+
+		<schema>
+			<key>/schemas/desktop/gnome/url-handlers/irc/needs_terminal</key>
+			<applyto>/desktop/gnome/url-handlers/irc/needs_terminal</applyto>
+			<owner>xchat</owner>
+			<type>bool</type>
+			<default>false</default>
+			<locale name="C">
+				<short>Run xchat in a terminal?</short>
+			</locale>
+		</schema>
+
+	</schemalist>
+</gconfschemafile>
diff --git a/src/common/dbus/dbus-client.c b/src/common/dbus/dbus-client.c
new file mode 100644
index 00000000..ac6bf6dc
--- /dev/null
+++ b/src/common/dbus/dbus-client.c
@@ -0,0 +1,118 @@
+/* dbus-client.c - XChat command-line options for D-Bus
+ * Copyright (C) 2006 Claessens Xavier
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Claessens Xavier
+ * xclaesse@gmail.com
+ */
+
+#include <dbus/dbus-glib.h>
+#include "dbus-client.h"
+#include "../xchat.h"
+#include "../xchatc.h"
+
+#define DBUS_SERVICE "org.xchat.service"
+#define DBUS_REMOTE "/org/xchat/Remote"
+#define DBUS_REMOTE_INTERFACE "org.xchat.plugin"
+
+static void
+write_error (char *message,
+	     GError **error)
+{
+	if (error == NULL || *error == NULL) {
+		return;
+	}
+	g_printerr ("%s: %s\n", message, (*error)->message);
+	g_clear_error (error);
+}
+
+void
+xchat_remote (void)
+/* TODO: dbus_g_connection_unref (connection) are commented because it makes
+ * dbus to crash. Fixed in dbus >=0.70 ?!?
+ * https://launchpad.net/distros/ubuntu/+source/dbus/+bug/54375
+ */
+{
+	DBusGConnection *connection;
+	DBusGProxy *dbus = NULL;
+	DBusGProxy *remote_object = NULL;
+	gboolean xchat_running;
+	GError *error = NULL;
+	char *command = NULL;
+
+	/* GnomeVFS >=2.15 uses D-Bus and threads, so threads should be
+	 * initialised before opening for the first time a D-Bus connection */
+	if (!g_thread_supported ()) {
+		g_thread_init (NULL);
+	}
+	dbus_g_thread_init ();
+
+	/* if there is nothing to do, return now. */
+	if (!arg_existing || !(arg_url || arg_command)) {
+		return;
+	}
+
+	arg_dont_autoconnect = TRUE;
+
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+	if (!connection) {
+		write_error (_("Couldn't connect to session bus"), &error);
+		return;
+	}
+
+	/* Checks if xchat is already running */
+	dbus = dbus_g_proxy_new_for_name (connection,
+					  DBUS_SERVICE_DBUS,
+					  DBUS_PATH_DBUS,
+					  DBUS_INTERFACE_DBUS);
+	if (!dbus_g_proxy_call (dbus, "NameHasOwner", &error,
+				G_TYPE_STRING, DBUS_SERVICE,
+				G_TYPE_INVALID,
+				G_TYPE_BOOLEAN, &xchat_running,
+				G_TYPE_INVALID)) {
+		write_error (_("Failed to complete NameHasOwner"), &error);
+		xchat_running = FALSE;
+	}
+	g_object_unref (dbus);
+
+	if (!xchat_running) {
+		//dbus_g_connection_unref (connection);
+		return;
+	}
+
+	remote_object = dbus_g_proxy_new_for_name (connection,
+						   DBUS_SERVICE,
+						   DBUS_REMOTE,
+						   DBUS_REMOTE_INTERFACE);
+
+	if (arg_url) {
+		command = g_strdup_printf ("url %s", arg_url);
+	} else if (arg_command) {
+		command = g_strdup (arg_command);
+	}
+
+	if (command) {
+		if (!dbus_g_proxy_call (remote_object, "Command",
+					&error,
+					G_TYPE_STRING, command,
+					G_TYPE_INVALID,G_TYPE_INVALID)) {
+			write_error (_("Failed to complete Command"), &error);
+		}
+		g_free (command);
+	}
+
+	exit (0);
+}
diff --git a/src/common/dbus/dbus-client.h b/src/common/dbus/dbus-client.h
new file mode 100644
index 00000000..cafc2b71
--- /dev/null
+++ b/src/common/dbus/dbus-client.h
@@ -0,0 +1,27 @@
+/* dbus-client.h - XChat command-line options for D-Bus
+ * Copyright (C) 2006 Claessens Xavier
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Claessens Xavier
+ * xclaesse@gmail.com
+ */
+
+#ifndef __DBUS_PLUGIN_H__
+#define __DBUS_PLUGIN_H__
+
+void xchat_remote (void);
+
+#endif /* __DBUS_PLUGIN_H__ */
diff --git a/src/common/dbus/dbus-plugin.c b/src/common/dbus/dbus-plugin.c
new file mode 100644
index 00000000..012812cc
--- /dev/null
+++ b/src/common/dbus/dbus-plugin.c
@@ -0,0 +1,1087 @@
+/* dbus-plugin.c - xchat plugin for remote access using D-Bus
+ * Copyright (C) 2006 Claessens Xavier
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Claessens Xavier
+ * xclaesse@gmail.com
+ */
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+
+#include <config.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <glib/gi18n.h>
+#include "../xchat-plugin.h"
+
+#define PNAME _("remote access")
+#define PDESC _("plugin for remote access using DBUS")
+#define PVERSION ""
+
+#define DBUS_SERVICE "org.xchat.service"
+#define DBUS_OBJECT_PATH "/org/xchat"
+
+static xchat_plugin *ph;
+static guint last_context_id = 0;
+static GList *contexts = NULL;
+static GHashTable *clients = NULL;
+static DBusGConnection *connection;
+
+typedef struct RemoteObject RemoteObject;
+typedef struct RemoteObjectClass RemoteObjectClass;
+
+GType Remote_object_get_type (void);
+
+struct RemoteObject
+{
+	GObject parent;
+
+	guint last_hook_id;
+	guint last_list_id;
+	xchat_context *context;
+	char *dbus_path;
+	char *filename;
+	GHashTable *hooks;
+	GHashTable *lists;
+	void *handle;
+};
+
+struct RemoteObjectClass
+{
+	GObjectClass parent;
+};
+
+typedef struct 
+{
+	guint id;
+	int return_value;
+	xchat_hook *hook;
+	RemoteObject *obj;
+} HookInfo;
+
+typedef struct
+{
+	guint id;
+	xchat_context *context;
+} ContextInfo;
+
+enum
+{
+	SERVER_SIGNAL,
+	COMMAND_SIGNAL,
+	PRINT_SIGNAL,
+	UNLOAD_SIGNAL,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+#define REMOTE_TYPE_OBJECT              (remote_object_get_type ())
+#define REMOTE_OBJECT(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), REMOTE_TYPE_OBJECT, RemoteObject))
+#define REMOTE_OBJECT_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), REMOTE_TYPE_OBJECT, RemoteObjectClass))
+#define REMOTE_IS_OBJECT(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), REMOTE_TYPE_OBJECT))
+#define REMOTE_IS_OBJECT_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), REMOTE_TYPE_OBJECT))
+#define REMOTE_OBJECT_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), REMOTE_TYPE_OBJECT, RemoteObjectClass))
+#define REMOTE_OBJECT_ERROR (remote_object_error_quark ())
+#define REMOTE_TYPE_ERROR (remote_object_error_get_type ()) 
+
+G_DEFINE_TYPE (RemoteObject, remote_object, G_TYPE_OBJECT)
+
+/* Available services */
+
+static gboolean		remote_object_connect		(RemoteObject *obj,
+							 const char *filename,
+							 const char *name,
+							 const char *desc,
+							 const char *version,
+							 DBusGMethodInvocation *context);
+
+static gboolean		remote_object_disconnect	(RemoteObject *obj,
+							 DBusGMethodInvocation *context);
+
+static gboolean		remote_object_command		(RemoteObject *obj,
+							 const char *command,
+							 GError **error);
+
+static gboolean		remote_object_print		(RemoteObject *obj,
+							 const char *text,
+							 GError **error);
+
+static gboolean		remote_object_find_context	(RemoteObject *obj,
+							 const char *server,
+							 const char *channel,
+							 guint *ret_id,
+							 GError **error);
+
+static gboolean		remote_object_get_context	(RemoteObject *obj,
+							 guint *ret_id,
+							 GError **error);
+
+static gboolean		remote_object_set_context	(RemoteObject *obj,
+							 guint id,
+							 gboolean *ret,
+							 GError **error);
+
+static gboolean		remote_object_print		(RemoteObject *obj,
+							 const char *text,
+							 GError **error);
+
+static gboolean		remote_object_get_info		(RemoteObject *obj,
+							 const char *id,
+							 char **ret_info,
+							 GError **error);
+
+static gboolean		remote_object_get_prefs		(RemoteObject *obj,
+							 const char *name,
+							 int *ret_type,
+							 char **ret_str,
+							 int *ret_int,
+							 GError **error);
+
+static gboolean		remote_object_hook_command	(RemoteObject *obj,
+							 const char *name,
+							 int pri,
+							 const char *help_text,
+							 int return_value,
+							 guint *ret_id,
+							 GError **error);
+
+static gboolean		remote_object_hook_server	(RemoteObject *obj,
+							 const char *name,
+							 int pri,
+							 int return_value,
+							 guint *ret_id,
+							 GError **error);
+
+static gboolean		remote_object_hook_print	(RemoteObject *obj,
+							 const char *name,
+							 int pri,
+							 int return_value,
+							 guint *ret_id,
+							 GError **error);
+
+static gboolean		remote_object_unhook		(RemoteObject *obj,
+							 guint id,
+							 GError **error);
+
+static gboolean		remote_object_list_get		(RemoteObject *obj,
+							 const char *name,
+							 guint *ret_id,
+							 GError **error);
+
+static gboolean		remote_object_list_next		(RemoteObject *obj,
+							 guint id,
+							 gboolean *ret,
+							 GError **error);
+
+static gboolean		remote_object_list_str		(RemoteObject *obj,
+							 guint id,
+							 const char *name,
+							 char **ret_str,
+							 GError **error);
+
+static gboolean		remote_object_list_int		(RemoteObject *obj,
+							 guint id,
+							 const char *name,
+							 int *ret_int,
+							 GError **error);
+
+static gboolean		remote_object_list_time		(RemoteObject *obj,
+							 guint id,
+							 const char *name,
+							 guint64 *ret_time,
+							 GError **error);
+
+static gboolean		remote_object_list_fields	(RemoteObject *obj,
+							 const char *name,
+							 char ***ret,
+							 GError **error);
+
+static gboolean		remote_object_list_free		(RemoteObject *obj,
+							 guint id,
+							 GError **error);
+
+static gboolean		remote_object_emit_print	(RemoteObject *obj,
+							 const char *event_name,
+							 const char *args[],
+							 gboolean *ret,
+							 GError **error);
+
+static gboolean		remote_object_nickcmp		(RemoteObject *obj,
+							 const char *nick1,
+							 const char *nick2,
+							 int *ret,
+							 GError **error);
+
+static gboolean		remote_object_strip		(RemoteObject *obj,
+							 const char *str,
+							 int len,
+							 int flag,
+							 char **ret_str,
+							 GError **error);
+
+static gboolean		remote_object_send_modes	(RemoteObject *obj,
+							 const char *targets[],
+							 int modes_per_line,
+							 char sign,
+							 char mode,
+							 GError **error);
+
+#include "remote-object-glue.h"
+#include "marshallers.h"
+
+/* Useful functions */
+
+static char**		build_list			(char *word[]);
+static guint		context_list_find_id		(xchat_context *context);
+static xchat_context*	context_list_find_context	(guint id);
+
+/* Remote Object */
+
+static void
+hook_info_destroy (gpointer data)
+{
+	HookInfo *info = (HookInfo*)data;
+
+	if (info == NULL) {
+		return;
+	}
+	xchat_unhook (ph, info->hook);
+	g_free (info);
+}
+
+static void
+list_info_destroy (gpointer data)
+{
+	xchat_list_free (ph, (xchat_list*)data);
+}
+
+static void
+remote_object_finalize (GObject *obj)
+{
+	RemoteObject *self = (RemoteObject*)obj;
+
+	g_hash_table_destroy (self->lists);
+	g_hash_table_destroy (self->hooks);
+	g_free (self->dbus_path);
+	g_free (self->filename);
+	xchat_plugingui_remove (ph, self->handle);
+
+	G_OBJECT_CLASS (remote_object_parent_class)->finalize (obj);
+}
+
+static void
+remote_object_init (RemoteObject *obj)
+{
+	obj->hooks =
+		g_hash_table_new_full (g_int_hash,
+				       g_int_equal,
+				       NULL,
+				       hook_info_destroy);
+
+	obj->lists =
+		g_hash_table_new_full (g_int_hash,
+				       g_int_equal,
+				       g_free,
+				       list_info_destroy);
+	obj->dbus_path = NULL;
+	obj->filename = NULL;
+	obj->last_hook_id = 0;
+	obj->last_list_id = 0;
+	obj->context = xchat_get_context (ph);
+}
+
+static void
+remote_object_class_init (RemoteObjectClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+	gobject_class->finalize = remote_object_finalize;
+
+	signals[SERVER_SIGNAL] =
+		g_signal_new ("server_signal",
+			      G_OBJECT_CLASS_TYPE (klass),
+			      G_SIGNAL_RUN_LAST,
+			      0,
+			      NULL, NULL,
+			      g_cclosure_user_marshal_VOID__POINTER_POINTER_UINT_UINT,
+			      G_TYPE_NONE,
+			      4, G_TYPE_STRV, G_TYPE_STRV, G_TYPE_UINT, G_TYPE_UINT);
+
+	signals[COMMAND_SIGNAL] =
+		g_signal_new ("command_signal",
+			      G_OBJECT_CLASS_TYPE (klass),
+			      G_SIGNAL_RUN_LAST,
+			      0,
+			      NULL, NULL,
+			      g_cclosure_user_marshal_VOID__POINTER_POINTER_UINT_UINT,
+			      G_TYPE_NONE,
+			      4, G_TYPE_STRV, G_TYPE_STRV, G_TYPE_UINT, G_TYPE_UINT);
+
+	signals[PRINT_SIGNAL] =
+		g_signal_new ("print_signal",
+			      G_OBJECT_CLASS_TYPE (klass),
+			      G_SIGNAL_RUN_LAST,
+			      0,
+			      NULL, NULL,
+			      g_cclosure_user_marshal_VOID__POINTER_POINTER_UINT_UINT,
+			      G_TYPE_NONE,
+			      3, G_TYPE_STRV, G_TYPE_UINT, G_TYPE_UINT);
+
+	signals[UNLOAD_SIGNAL] =
+		g_signal_new ("unload_signal",
+			      G_OBJECT_CLASS_TYPE (klass),
+			      G_SIGNAL_RUN_LAST,
+			      0,
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE,
+			      0);
+}
+
+/* Implementation of services */
+
+static gboolean
+remote_object_connect (RemoteObject *obj,
+		       const char *filename,
+		       const char *name,
+		       const char *desc,
+		       const char *version,
+		       DBusGMethodInvocation *context)
+{
+	static guint count = 0;
+	char *sender, *path;
+	RemoteObject *remote_object;
+	
+	sender = dbus_g_method_get_sender (context);
+	remote_object = g_hash_table_lookup (clients, sender);
+	if (remote_object != NULL) {
+		dbus_g_method_return (context, remote_object->dbus_path);
+		g_free (sender);
+		return TRUE;
+	}
+	path = g_strdup_printf (DBUS_OBJECT_PATH"/%d", count++);
+	remote_object = g_object_new (REMOTE_TYPE_OBJECT, NULL);
+	remote_object->dbus_path = path;
+	remote_object->filename = g_path_get_basename (filename);
+	remote_object->handle = xchat_plugingui_add (ph,
+						     remote_object->filename,
+						     name,
+						     desc,
+						     version, NULL);
+	dbus_g_connection_register_g_object (connection,
+					     path,
+					     G_OBJECT (remote_object));
+
+	g_hash_table_insert (clients,
+			     sender,
+			     remote_object);
+
+	dbus_g_method_return (context, path);
+	return TRUE;
+}
+
+static gboolean
+remote_object_disconnect (RemoteObject *obj,
+			  DBusGMethodInvocation *context)
+{
+	char *sender;
+	
+	sender = dbus_g_method_get_sender (context);
+	g_hash_table_remove (clients, sender);
+	g_free (sender);
+
+	dbus_g_method_return (context);
+	return TRUE;
+}
+
+static gboolean
+remote_object_command (RemoteObject *obj,
+		       const char *command,
+		       GError **error)
+{
+	if (xchat_set_context (ph, obj->context)) {
+		xchat_command (ph, command);
+	}
+	return TRUE;
+}
+
+static gboolean
+remote_object_print (RemoteObject *obj,
+		     const char *text,
+		     GError **error)
+{
+	if (xchat_set_context (ph, obj->context)) {
+		xchat_print (ph, text);
+	}
+	return TRUE;
+}
+
+static gboolean
+remote_object_find_context (RemoteObject *obj,
+			    const char *server,
+			    const char *channel,
+			    guint *ret_id,
+			    GError **error)
+{
+	xchat_context *context;
+
+	if (*server == '\0') {
+		server = NULL;
+	}
+	if (*channel == '\0') {
+		channel = NULL;
+	}
+	context = xchat_find_context (ph, server, channel);
+	*ret_id = context_list_find_id (context);
+
+	return TRUE;
+}
+
+static gboolean
+remote_object_get_context (RemoteObject *obj,
+			   guint *ret_id,
+			   GError **error)
+{
+	*ret_id = context_list_find_id (obj->context);
+	return TRUE;
+}
+
+static gboolean
+remote_object_set_context (RemoteObject *obj,
+			   guint id,
+			   gboolean *ret,
+			   GError **error)
+{
+	xchat_context *context;
+	
+	context = context_list_find_context (id);
+	if (context == NULL) {
+		*ret = FALSE;
+		return TRUE;
+	}
+	obj->context = context;
+	*ret = TRUE;
+
+	return TRUE;
+}
+
+static gboolean
+remote_object_get_info (RemoteObject *obj,
+			const char *id,
+			char **ret_info,
+			GError **error)
+{
+	/* win_ptr is a GtkWindow* casted to char* and will crash
+	 * D-Bus if we send it as a string */
+	if (!xchat_set_context (ph, obj->context) ||
+	    g_str_equal (id, "win_ptr")) {
+		*ret_info = NULL;
+		return TRUE;
+	}
+	*ret_info = g_strdup (xchat_get_info (ph, id));
+	return TRUE;
+}
+
+static gboolean
+remote_object_get_prefs (RemoteObject *obj,
+			 const char *name,
+			 int *ret_type,
+			 char **ret_str,
+			 int *ret_int,
+			 GError **error)
+{
+	const char *str;
+
+	if (!xchat_set_context (ph, obj->context)) {
+		*ret_type = 0;
+		return TRUE;
+	}
+	*ret_type = xchat_get_prefs (ph, name, &str, ret_int);
+	*ret_str = g_strdup (str);
+
+	return TRUE;
+}
+
+static int
+server_hook_cb (char *word[],
+		char *word_eol[],
+		void *userdata)
+{
+	HookInfo *info = (HookInfo*)userdata;
+	char **arg1;
+	char **arg2;
+
+	arg1 = build_list (word + 1);
+	arg2 = build_list (word_eol + 1);
+	info->obj->context = xchat_get_context (ph);
+	g_signal_emit (info->obj,
+		       signals[SERVER_SIGNAL],
+		       0,
+		       arg1, arg2, info->id,
+		       context_list_find_id (info->obj->context));
+	g_strfreev (arg1);
+	g_strfreev (arg2);
+  
+	return info->return_value;
+}
+
+static int
+command_hook_cb (char *word[],
+		 char *word_eol[],
+		 void *userdata)
+{
+	HookInfo *info = (HookInfo*)userdata;
+	char **arg1;
+	char **arg2;
+
+	arg1 = build_list (word + 1);
+	arg2 = build_list (word_eol + 1);
+	info->obj->context = xchat_get_context (ph);
+	g_signal_emit (info->obj,
+		       signals[COMMAND_SIGNAL],
+		       0,
+		       arg1, arg2, info->id,
+		       context_list_find_id (info->obj->context));
+	g_strfreev (arg1);
+	g_strfreev (arg2);
+  
+	return info->return_value;
+}
+
+static int
+print_hook_cb (char *word[],
+	       void *userdata)
+{
+	HookInfo *info = (HookInfo*)userdata;
+	char **arg1;
+
+	arg1 = build_list (word + 1);
+	info->obj->context = xchat_get_context (ph);
+	g_signal_emit (info->obj,
+		       signals[PRINT_SIGNAL],
+		       0,
+		       arg1, info->id,
+		       context_list_find_id (info->obj->context));
+	g_strfreev (arg1);
+  
+	return info->return_value;
+}
+
+static gboolean
+remote_object_hook_command (RemoteObject *obj,
+			    const char *name,
+			    int priority,
+			    const char *help_text,
+			    int return_value,
+			    guint *ret_id,
+			    GError **error)
+{
+	HookInfo *info;
+
+	info = g_new0 (HookInfo, 1);
+	info->obj = obj;
+	info->return_value = return_value;
+	info->id = ++obj->last_hook_id;
+	info->hook = xchat_hook_command (ph,
+					 name,
+					 priority,
+					 command_hook_cb,
+					 help_text,
+					 info);
+	g_hash_table_insert (obj->hooks, &info->id, info);
+	*ret_id = info->id;
+
+	return TRUE;
+}
+
+static gboolean
+remote_object_hook_server (RemoteObject *obj,
+			   const char *name,
+			   int priority,
+			   int return_value,
+			   guint *ret_id,
+			   GError **error)
+{
+	HookInfo *info;
+
+	info = g_new0 (HookInfo, 1);
+	info->obj = obj;
+	info->return_value = return_value;
+	info->id = ++obj->last_hook_id;
+	info->hook = xchat_hook_server (ph,
+					name,
+					priority,
+					server_hook_cb,
+					info);
+	g_hash_table_insert (obj->hooks, &info->id, info);
+	*ret_id = info->id;
+
+	return TRUE;
+}
+
+static gboolean
+remote_object_hook_print (RemoteObject *obj,
+			  const char *name,
+			  int priority,
+			  int return_value,
+			  guint *ret_id,
+			  GError **error)
+{
+	HookInfo *info;
+
+	info = g_new0 (HookInfo, 1);
+	info->obj = obj;
+	info->return_value = return_value;
+	info->id = ++obj->last_hook_id;
+	info->hook = xchat_hook_print (ph,
+				       name,
+				       priority,
+				       print_hook_cb,
+				       info);
+	g_hash_table_insert (obj->hooks, &info->id, info);
+	*ret_id = info->id;
+
+	return TRUE;
+}
+
+static gboolean
+remote_object_unhook (RemoteObject *obj,
+		      guint id,
+		      GError **error)
+{
+	g_hash_table_remove (obj->hooks, &id);
+	return TRUE;
+}
+
+static gboolean
+remote_object_list_get (RemoteObject *obj,
+			const char *name,
+			guint *ret_id,
+			GError **error)
+{
+	xchat_list *xlist;
+	guint *id;
+
+	if (!xchat_set_context (ph, obj->context)) {
+		*ret_id = 0;
+		return TRUE;
+	}
+	xlist = xchat_list_get (ph, name);
+	if (xlist == NULL) {
+		*ret_id = 0;
+		return TRUE;
+	}
+	id = g_new (guint, 1);
+	*id = ++obj->last_list_id;
+	*ret_id = *id;
+	g_hash_table_insert (obj->lists,
+			     id,
+			     xlist);
+
+	return TRUE;
+}
+
+static gboolean
+remote_object_list_next	(RemoteObject *obj,
+			 guint id,
+			 gboolean *ret,
+			 GError **error)
+{
+	xchat_list *xlist;
+	
+	xlist = g_hash_table_lookup (obj->lists, &id);
+	if (xlist == NULL) {
+		*ret = FALSE;
+		return TRUE;
+	}
+	*ret = xchat_list_next (ph, xlist);
+
+	return TRUE;
+}			 
+
+static gboolean
+remote_object_list_str (RemoteObject *obj,
+			guint id,
+			const char *name,
+			char **ret_str,
+			GError **error)
+{
+	xchat_list *xlist;
+	
+	xlist = g_hash_table_lookup (obj->lists, &id);
+	if (xlist == NULL && !xchat_set_context (ph, obj->context)) {
+		*ret_str = NULL;
+		return TRUE;
+	}
+	if (g_str_equal (name, "context")) {
+		*ret_str = NULL;
+		return TRUE;
+	}
+	*ret_str = g_strdup (xchat_list_str (ph, xlist, name));
+
+	return TRUE;
+}
+
+static gboolean
+remote_object_list_int (RemoteObject *obj,
+			guint id,
+			const char *name,
+			int *ret_int,
+			GError **error)
+{
+	xchat_list *xlist;
+	
+	xlist = g_hash_table_lookup (obj->lists, &id);
+	if (xlist == NULL && !xchat_set_context (ph, obj->context)) {
+		*ret_int = -1;
+		return TRUE;
+	}
+	if (g_str_equal (name, "context")) {
+		xchat_context *context;
+		context = (xchat_context*)xchat_list_str (ph, xlist, name);
+		*ret_int = context_list_find_id (context);
+	} else {
+		*ret_int = xchat_list_int (ph, xlist, name);
+	}
+
+	return TRUE;
+}
+
+static gboolean
+remote_object_list_time (RemoteObject *obj,
+			 guint id,
+			 const char *name,
+			 guint64 *ret_time,
+			 GError **error)
+{
+	xchat_list *xlist;
+	
+	xlist = g_hash_table_lookup (obj->lists, &id);
+	if (xlist == NULL) {
+		*ret_time = (guint64) -1;
+		return TRUE;
+	}
+	*ret_time = xchat_list_time (ph, xlist, name);
+	
+	return TRUE;
+}
+
+static gboolean
+remote_object_list_fields (RemoteObject *obj,
+			   const char *name,
+			   char ***ret,
+			   GError **error)
+{
+	*ret = g_strdupv ((char**)xchat_list_fields (ph, name));
+	if (*ret == NULL) {
+		*ret = g_new0 (char*, 1);
+	}
+	return TRUE;
+}
+
+static gboolean
+remote_object_list_free (RemoteObject *obj,
+			 guint id,
+			 GError **error)
+{
+	g_hash_table_remove (obj->lists, &id);
+	return TRUE;
+}
+
+static gboolean
+remote_object_emit_print (RemoteObject *obj,
+			  const char *event_name,
+			  const char *args[],
+			  gboolean *ret,
+			  GError **error)
+{
+	const char *argv[4] = {NULL, NULL, NULL, NULL};
+	int i;
+	
+	for (i = 0; i < 4 && args[i] != NULL; i++) {
+		argv[i] = args[i];
+	}
+
+	*ret = xchat_set_context (ph, obj->context);
+	if (*ret) {
+		*ret = xchat_emit_print (ph, event_name, argv[0], argv[1],
+							 argv[2], argv[3]);
+	}
+
+	return TRUE;
+}
+
+static gboolean
+remote_object_nickcmp (RemoteObject *obj,
+		       const char *nick1,
+		       const char *nick2,
+		       int *ret,
+		       GError **error)
+{
+	xchat_set_context (ph, obj->context);
+	*ret = xchat_nickcmp (ph, nick1, nick2);
+	return TRUE;
+}
+
+static gboolean
+remote_object_strip (RemoteObject *obj,
+		     const char *str,
+		     int len,
+		     int flag,
+		     char **ret_str,
+		     GError **error)
+{
+	*ret_str = xchat_strip (ph, str, len, flag);
+	return TRUE;
+}
+
+static gboolean
+remote_object_send_modes (RemoteObject *obj,
+			  const char *targets[],
+			  int modes_per_line,
+			  char sign,
+			  char mode,
+			  GError **error)
+{
+	if (xchat_set_context (ph, obj->context)) {
+		xchat_send_modes (ph, targets,
+				  g_strv_length ((char**)targets),
+				  modes_per_line,
+				  sign, mode);
+	}
+	return TRUE;
+}
+
+/* DBUS stuffs */
+
+static void
+name_owner_changed (DBusGProxy *driver_proxy,
+		    const char *name,
+		    const char *old_owner,
+		    const char *new_owner,
+		    void       *user_data)
+{
+	if (*new_owner == '\0') {
+		/* this name has vanished */
+		g_hash_table_remove (clients, name);
+	}
+}
+
+static gboolean
+init_dbus (void)
+{
+	DBusGProxy *proxy;
+	RemoteObject *remote;
+	guint request_name_result;
+	GError *error = NULL;
+
+	dbus_g_object_type_install_info (REMOTE_TYPE_OBJECT,
+					 &dbus_glib_remote_object_object_info);
+
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+	if (connection == NULL) {
+		xchat_printf (ph, _("Couldn't connect to session bus: %s\n"),
+			      error->message);
+		g_error_free (error);
+		return FALSE;
+	}
+
+	proxy = dbus_g_proxy_new_for_name (connection,
+					   DBUS_SERVICE_DBUS,
+					   DBUS_PATH_DBUS,
+					   DBUS_INTERFACE_DBUS);
+
+	if (!dbus_g_proxy_call (proxy, "RequestName", &error,
+				G_TYPE_STRING, DBUS_SERVICE,
+				G_TYPE_UINT, DBUS_NAME_FLAG_ALLOW_REPLACEMENT,
+				G_TYPE_INVALID,
+				G_TYPE_UINT, &request_name_result,
+				G_TYPE_INVALID)) {
+		xchat_printf (ph, _("Failed to acquire %s: %s\n"),
+			      DBUS_SERVICE,
+			      error->message);
+		g_error_free (error);
+
+		return FALSE;
+	}
+
+	dbus_g_proxy_add_signal (proxy, "NameOwnerChanged",
+				 G_TYPE_STRING,
+				 G_TYPE_STRING,
+				 G_TYPE_STRING,
+				 G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (proxy, "NameOwnerChanged", 
+				     G_CALLBACK (name_owner_changed),
+				     NULL, NULL);
+
+	remote = g_object_new (REMOTE_TYPE_OBJECT, NULL);
+	dbus_g_connection_register_g_object (connection,
+					     DBUS_OBJECT_PATH"/Remote",
+					     G_OBJECT (remote));
+
+	return TRUE;
+}
+
+/* xchat_plugin stuffs */
+
+static char**
+build_list (char *word[])
+{
+	guint i;
+	guint num = 0;
+	char **result;
+
+	if (word == NULL) {
+		return NULL;
+	}
+  
+	while (word[num] && word[num][0]) {
+		num++;
+	}
+	
+	result = g_new0 (char*, num + 1);
+	for (i = 0; i < num; i++) {
+		result[i] = g_strdup (word[i]);
+	}
+
+	return result;
+}
+
+static guint
+context_list_find_id (xchat_context *context)
+{
+	GList *l = NULL;
+
+	for (l = contexts; l != NULL; l = l->next) {
+		if (((ContextInfo*)l->data)->context == context) {
+			return ((ContextInfo*)l->data)->id;
+		}
+	}
+
+	return 0;
+}
+
+static xchat_context*
+context_list_find_context (guint id)
+{
+	GList *l = NULL;
+
+	for (l = contexts; l != NULL; l = l->next) {
+		if (((ContextInfo*)l->data)->id == id) {
+			return ((ContextInfo*)l->data)->context;
+		}
+	}
+
+	return NULL;
+}
+
+static int
+open_context_cb (char *word[],
+		 void *userdata)
+{
+	ContextInfo *info;
+	
+	info = g_new0 (ContextInfo, 1);
+	info->id = ++last_context_id;
+	info->context = xchat_get_context (ph);
+	contexts = g_list_prepend (contexts, info);
+
+	return XCHAT_EAT_NONE;
+}
+
+static int
+close_context_cb (char *word[],
+		  void *userdata)
+{
+	GList *l;
+	xchat_context *context = xchat_get_context (ph);
+
+	for (l = contexts; l != NULL; l = l->next) {
+		if (((ContextInfo*)l->data)->context == context) {
+			g_free (l->data);
+			contexts = g_list_delete_link (contexts, l);
+			break;
+		}
+	}
+
+	return XCHAT_EAT_NONE;
+}
+
+static gboolean
+clients_find_filename_foreach (gpointer key,
+			       gpointer value,
+			       gpointer user_data)
+{
+	RemoteObject *obj = REMOTE_OBJECT (value);
+	return g_str_equal (obj->filename, (char*)user_data);
+}
+
+static int
+unload_plugin_cb (char *word[], char *word_eol[], void *userdata)
+{
+	RemoteObject *obj;
+	
+	obj = g_hash_table_find (clients,
+				 clients_find_filename_foreach,
+				 word[2]);
+	if (obj != NULL) {
+		g_signal_emit (obj, 
+			       signals[UNLOAD_SIGNAL],
+			       0);
+		return XCHAT_EAT_ALL;
+	}
+	
+	return XCHAT_EAT_NONE;
+}
+
+int
+dbus_plugin_init (xchat_plugin *plugin_handle,
+		  char **plugin_name,
+		  char **plugin_desc,
+		  char **plugin_version,
+		  char *arg)
+{
+	ph = plugin_handle;
+	*plugin_name = PNAME;
+	*plugin_desc = PDESC;
+	*plugin_version = PVERSION;
+
+	if (init_dbus()) {
+		/*xchat_printf (ph, _("%s loaded successfully!\n"), PNAME);*/
+
+		clients = g_hash_table_new_full (g_str_hash,
+						 g_str_equal,
+						 g_free,
+						 g_object_unref);
+
+		xchat_hook_print (ph, "Open Context",
+				  XCHAT_PRI_NORM,
+				  open_context_cb,
+				  NULL);
+
+		xchat_hook_print (ph, "Close Context",
+				  XCHAT_PRI_NORM,
+				  close_context_cb,
+				  NULL);
+
+		xchat_hook_command (ph, "unload",
+				    XCHAT_PRI_HIGHEST,
+				    unload_plugin_cb, NULL, NULL);
+	}
+
+	return TRUE; 
+}
diff --git a/src/common/dbus/dbus-plugin.h b/src/common/dbus/dbus-plugin.h
new file mode 100644
index 00000000..bda8f61c
--- /dev/null
+++ b/src/common/dbus/dbus-plugin.h
@@ -0,0 +1,31 @@
+/* dbus-plugin.c - xchat plugin for remote access using DBUS
+ * Copyright (C) 2006 Claessens Xavier
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Claessens Xavier
+ * xclaesse@gmail.com
+ */
+
+#ifndef XCHAT_DBUS_PLUGIN_H
+#define XCHAT_DBUS_PLUGIN_H
+
+int	dbus_plugin_init	(xchat_plugin *plugin_handle,
+				 char **plugin_name,
+				 char **plugin_desc,
+				 char **plugin_version,
+				 char *arg);
+
+#endif
diff --git a/src/common/dbus/example.c b/src/common/dbus/example.c
new file mode 100644
index 00000000..1d072785
--- /dev/null
+++ b/src/common/dbus/example.c
@@ -0,0 +1,201 @@
+/* example.c - program to demonstrate some D-BUS stuffs.
+ * Copyright (C) 2006 Claessens Xavier
+ *
+ * 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.
+ *
+ * Claessens Xavier
+ * xclaesse@gmail.com
+ */
+
+#include <config.h>
+#include <dbus/dbus-glib.h>
+#include <stdlib.h>
+#include "marshallers.h"
+
+#define DBUS_SERVICE "org.xchat.service"
+#define DBUS_REMOTE "/org/xchat/Remote"
+#define DBUS_REMOTE_CONNECTION_INTERFACE "org.xchat.connection"
+#define DBUS_REMOTE_PLUGIN_INTERFACE "org.xchat.plugin"
+
+guint command_id;
+guint server_id;
+
+static void
+write_error (char *message,
+	     GError **error)
+{
+	if (error == NULL || *error == NULL) {
+		return;
+	}
+	g_printerr ("%s: %s\n", message, (*error)->message);
+	g_clear_error (error);
+}
+
+static void
+test_server_cb (DBusGProxy *proxy,
+		char *word[],
+		char *word_eol[],
+		guint hook_id,
+		guint context_id,
+		gpointer user_data)
+{
+	if (hook_id == server_id) {
+		g_print ("message: %s\n", word_eol[0]);
+	}
+}
+
+static void
+test_command_cb (DBusGProxy *proxy,
+		 char *word[],
+		 char *word_eol[],
+		 guint hook_id,
+		 guint context_id,
+		 gpointer user_data)
+{
+	GError *error = NULL;
+
+	if (hook_id == command_id) {
+		if (!dbus_g_proxy_call (proxy, "Unhook",
+					&error,
+					G_TYPE_UINT, hook_id,
+					G_TYPE_INVALID, G_TYPE_INVALID)) {
+			write_error ("Failed to complete unhook", &error);
+		}
+		/* Now if you write "/test blah" again in the xchat window
+		 * you'll get a "Unknown command" error message */
+		g_print ("test command received: %s\n", word_eol[1]);
+		if (!dbus_g_proxy_call (proxy, "Print",
+					&error,
+					G_TYPE_STRING, "test command succeed",
+					G_TYPE_INVALID,
+					G_TYPE_INVALID)) {
+			write_error ("Failed to complete Print", &error);
+		}
+	}
+}
+
+static void
+unload_cb (void)
+{
+	g_print ("Good bye !\n");
+	exit (EXIT_SUCCESS);
+}
+
+int
+main (int argc, char **argv)
+{
+	DBusGConnection *connection;
+	DBusGProxy *remote_object;
+	GMainLoop *mainloop;
+	gchar *path;
+	GError *error = NULL;
+
+	g_type_init ();
+
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+	if (connection == NULL) {
+		write_error ("Couldn't connect to session bus", &error);
+		return EXIT_FAILURE;
+	}
+  
+	remote_object = dbus_g_proxy_new_for_name (connection,
+						   DBUS_SERVICE,
+						   DBUS_REMOTE,
+						   DBUS_REMOTE_CONNECTION_INTERFACE);
+	if (!dbus_g_proxy_call (remote_object, "Connect",
+				&error,
+				G_TYPE_STRING, argv[0],
+				G_TYPE_STRING, "example",
+				G_TYPE_STRING, "Example of a D-Bus client",
+				G_TYPE_STRING, "1.0",
+				G_TYPE_INVALID,
+				G_TYPE_STRING, &path, G_TYPE_INVALID)) {
+		write_error ("Failed to complete Connect", &error);
+		return EXIT_FAILURE;
+	}
+	g_object_unref (remote_object);
+
+	remote_object = dbus_g_proxy_new_for_name (connection,
+						   DBUS_SERVICE,
+						   path,
+						   DBUS_REMOTE_PLUGIN_INTERFACE);
+	g_free (path);
+
+	if (!dbus_g_proxy_call (remote_object, "HookCommand",
+				&error,
+				G_TYPE_STRING, "test",
+				G_TYPE_INT, 0,
+				G_TYPE_STRING, "Simple D-BUS example",
+				G_TYPE_INT, 1, G_TYPE_INVALID,
+				G_TYPE_UINT, &command_id, G_TYPE_INVALID)) {
+		write_error ("Failed to complete HookCommand", &error);
+		return EXIT_FAILURE;
+	}
+	g_print ("Command hook id=%d\n", command_id);
+
+	if (!dbus_g_proxy_call (remote_object, "HookServer",
+				&error,
+				G_TYPE_STRING, "RAW LINE",
+				G_TYPE_INT, 0,
+				G_TYPE_INT, 0, G_TYPE_INVALID,
+				G_TYPE_UINT, &server_id, G_TYPE_INVALID)) {
+		write_error ("Failed to complete HookServer", &error);
+		return EXIT_FAILURE;
+	}
+	g_print ("Server hook id=%d\n", server_id);
+
+	dbus_g_object_register_marshaller (
+		g_cclosure_user_marshal_VOID__POINTER_POINTER_UINT_UINT,
+		G_TYPE_NONE,
+		G_TYPE_STRV, G_TYPE_STRV, G_TYPE_UINT, G_TYPE_UINT,
+		G_TYPE_INVALID);
+
+	dbus_g_object_register_marshaller (
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE,
+		G_TYPE_INVALID);
+
+	dbus_g_proxy_add_signal (remote_object, "CommandSignal",
+				 G_TYPE_STRV,
+				 G_TYPE_STRV,
+				 G_TYPE_UINT,
+				 G_TYPE_UINT,
+				 G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (remote_object, "CommandSignal",
+				     G_CALLBACK (test_command_cb),
+				     NULL, NULL);
+
+	dbus_g_proxy_add_signal (remote_object, "ServerSignal",
+				 G_TYPE_STRV,
+				 G_TYPE_STRV,
+				 G_TYPE_UINT,
+				 G_TYPE_UINT,
+				 G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (remote_object, "ServerSignal",
+				     G_CALLBACK (test_server_cb),
+				     NULL, NULL);
+
+	dbus_g_proxy_add_signal (remote_object, "UnloadSignal",
+				 G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (remote_object, "UnloadSignal",
+				     G_CALLBACK (unload_cb),
+				     NULL, NULL);
+
+	/* Now you can write on the xchat windows: "/test arg1 arg2 ..." */
+	mainloop = g_main_loop_new (NULL, FALSE);
+	g_main_loop_run (mainloop);
+
+	return EXIT_SUCCESS;
+}
diff --git a/src/common/dbus/example.py b/src/common/dbus/example.py
new file mode 100644
index 00000000..08bfdac3
--- /dev/null
+++ b/src/common/dbus/example.py
@@ -0,0 +1,28 @@
+#! /usr/bin/python
+
+import dbus
+
+bus = dbus.SessionBus()
+proxy = bus.get_object('org.xchat.service', '/org/xchat/Remote')
+remote = dbus.Interface(proxy, 'org.xchat.connection')
+path = remote.Connect ("example.py",
+		       "Python example",
+		       "Example of a D-Bus client written in python",
+		       "1.0")
+proxy = bus.get_object('org.xchat.service', path)
+xchat = dbus.Interface(proxy, 'org.xchat.plugin')
+
+channels = xchat.ListGet ("channels")
+while xchat.ListNext (channels):
+	name = xchat.ListStr (channels, "channel")
+	print "------- " + name + " -------"
+	xchat.SetContext (xchat.ListInt (channels, "context"))
+	xchat.EmitPrint ("Channel Message", ["John", "Hi there", "@"])
+	users = xchat.ListGet ("users")
+	while xchat.ListNext (users):
+		print "Nick: " + xchat.ListStr (users, "nick")
+	xchat.ListFree (users)
+xchat.ListFree (channels)
+
+print xchat.Strip ("\00312Blue\003 \002Bold!\002", -1, 1|2)
+
diff --git a/src/common/dbus/marshallers.list b/src/common/dbus/marshallers.list
new file mode 100644
index 00000000..bc3c4ad5
--- /dev/null
+++ b/src/common/dbus/marshallers.list
@@ -0,0 +1 @@
+VOID:POINTER,POINTER,UINT,UINT
diff --git a/src/common/dbus/org.xchat.service.service.in b/src/common/dbus/org.xchat.service.service.in
new file mode 100644
index 00000000..19490121
--- /dev/null
+++ b/src/common/dbus/org.xchat.service.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.xchat.service
+Exec=@bindir@/xchat
diff --git a/src/common/dbus/remote-object.xml b/src/common/dbus/remote-object.xml
new file mode 100644
index 00000000..88a8ae7c
--- /dev/null
+++ b/src/common/dbus/remote-object.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<node name="/">
+
+  <interface name="org.xchat.connection">
+    <method name="Connect">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <arg type="s" name="filename" direction="in"/>
+      <arg type="s" name="name" direction="in"/>
+      <arg type="s" name="desc" direction="in"/>
+      <arg type="s" name="version" direction="in"/>
+      <arg type="s" name="path" direction="out"/>
+    </method>  
+    <method name="Disconnect">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+    </method>
+  </interface>
+
+  <interface name="org.xchat.plugin">
+    <method name="Command">
+      <arg type="s" name="command" direction="in"/>
+    </method>
+    <method name="Print">
+      <arg type="s" name="text" direction="in"/>
+    </method>
+    <method name="FindContext">
+      <arg type="s" name="server" direction="in"/>
+      <arg type="s" name="channel" direction="in"/>
+      <arg type="u" name="ret_id" direction="out"/>
+    </method>
+    <method name="GetContext">
+      <arg type="u" name="ret_id" direction="out"/>
+    </method>
+    <method name="SetContext">
+      <arg type="u" name="id" direction="in"/>
+      <arg type="b" name="ret" direction="out"/>
+    </method>
+    <method name="GetInfo">
+      <arg type="s" name="id" direction="in"/>
+      <arg type="s" name="ret_info" direction="out"/>
+    </method>
+    <method name="GetPrefs">
+      <arg type="s" name="name" direction="in"/>
+      <arg type="i" name="ret_type" direction="out"/>
+      <arg type="s" name="ret_str" direction="out"/>
+      <arg type="i" name="ret_int" direction="out"/>
+    </method>
+    <method name="HookCommand">
+      <arg type="s" name="name" direction="in"/>
+      <arg type="i" name="priority" direction="in"/>
+      <arg type="s" name="help_text" direction="in"/>
+      <arg type="i" name="return_value" direction="in"/>
+      <arg type="u" name="ret_id" direction="out"/>
+    </method>
+    <method name="HookServer">
+      <arg type="s" name="name" direction="in"/>
+      <arg type="i" name="priority" direction="in"/>
+      <arg type="i" name="return_value" direction="in"/>
+      <arg type="u" name="ret_id" direction="out"/>
+    </method>
+    <method name="HookPrint">
+      <arg type="s" name="name" direction="in"/>
+      <arg type="i" name="priority" direction="in"/>
+      <arg type="i" name="return_value" direction="in"/>
+      <arg type="u" name="ret_id" direction="out"/>
+    </method>
+    <method name="Unhook">
+      <arg type="u" name="id" direction="in"/>
+    </method>
+    <method name="ListGet">
+      <arg type="s" name="name" direction="in"/>
+      <arg type="u" name="ret_id" direction="out"/>
+    </method>
+    <method name="ListNext">
+      <arg type="u" name="id" direction="in"/>
+      <arg type="b" name="ret" direction="out"/>
+    </method>
+    <method name="ListStr">
+      <arg type="u" name="id" direction="in"/>
+      <arg type="s" name="name" direction="in"/>
+      <arg type="s" name="ret_str" direction="out"/>
+    </method>
+    <method name="ListInt">
+      <arg type="u" name="id" direction="in"/>
+      <arg type="s" name="name" direction="in"/>
+      <arg type="i" name="ret_int" direction="out"/>
+    </method>
+    <method name="ListTime">
+      <arg type="u" name="id" direction="in"/>
+      <arg type="s" name="name" direction="in"/>
+      <arg type="t" name="ret_time" direction="out"/>
+    </method>
+    <method name="ListFields">
+      <arg type="s" name="name" direction="in"/>
+      <arg type="as" name="ret" direction="out"/>
+    </method>
+    <method name="ListFree">
+      <arg type="u" name="id" direction="in"/>
+    </method>
+    <method name="EmitPrint">
+      <arg type="s" name="event_name" direction="in"/>
+      <arg type="as" name="args" direction="in"/>
+      <arg type="b" name="ret" direction="out"/>
+    </method>
+    <method name="Nickcmp">
+      <arg type="s" name="nick1" direction="in"/>
+      <arg type="s" name="nick2" direction="in"/>
+      <arg type="i" name="ret" direction="out"/>
+    </method>
+    <method name="Strip">
+      <arg type="s" name="str" direction="in"/>
+      <arg type="i" name="len" direction="in"/>
+      <arg type="i" name="flag" direction="in"/>
+      <arg type="s" name="ret_str" direction="out"/>
+    </method>
+    <method name="SendModes">
+      <arg type="as" name="targets" direction="in"/>
+      <arg type="i" name="modes_per_line" direction="in"/>
+      <arg type="y" name="sign" direction="in"/>
+      <arg type="y" name="mode" direction="in"/>
+    </method>
+
+    <signal name="CommandSignal">
+      <arg type="as" name="word"/>
+      <arg type="as" name="word_eol"/>
+      <arg type="u" name="hook_id"/>
+      <arg type="u" name="context_id"/>
+    </signal>
+    <signal name="ServerSignal">
+      <arg type="as" name="word"/>
+      <arg type="as" name="word_eol"/>
+      <arg type="u" name="hook_id"/>
+      <arg type="u" name="context_id"/>
+    </signal>
+    <signal name="PrintSignal">
+      <arg type="as" name="word"/>
+      <arg type="u" name="hook_id"/>
+      <arg type="u" name="context_id"/>
+    </signal>
+    <signal name="UnloadSignal"/>
+  </interface>
+</node>