diff options
author | berkeviktor@aol.com <berkeviktor@aol.com> | 2011-02-24 04:14:30 +0100 |
---|---|---|
committer | berkeviktor@aol.com <berkeviktor@aol.com> | 2011-02-24 04:14:30 +0100 |
commit | 4a6ceffb98a0b785494f680d3776c4bfc4052f9e (patch) | |
tree | 850703c1c841ccd99f58d0b06084615aaebe782c /src/common/dbus | |
parent | f16af8be941b596dedac3bf4e371ee2d21f4b598 (diff) |
add xchat r1489
Diffstat (limited to 'src/common/dbus')
-rw-r--r-- | src/common/dbus/Makefile.am | 56 | ||||
-rw-r--r-- | src/common/dbus/README | 198 | ||||
-rw-r--r-- | src/common/dbus/apps_xchat_url_handler.schemas | 37 | ||||
-rw-r--r-- | src/common/dbus/dbus-client.c | 118 | ||||
-rw-r--r-- | src/common/dbus/dbus-client.h | 27 | ||||
-rw-r--r-- | src/common/dbus/dbus-plugin.c | 1087 | ||||
-rw-r--r-- | src/common/dbus/dbus-plugin.h | 31 | ||||
-rw-r--r-- | src/common/dbus/example.c | 201 | ||||
-rw-r--r-- | src/common/dbus/example.py | 28 | ||||
-rw-r--r-- | src/common/dbus/marshallers.list | 1 | ||||
-rw-r--r-- | src/common/dbus/org.xchat.service.service.in | 3 | ||||
-rw-r--r-- | src/common/dbus/remote-object.xml | 142 |
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> |