/* dbus-plugin.c - hexchat 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Claessens Xavier * xclaesse@gmail.com */ #define DBUS_API_SUBJECT_TO_CHANGE #include #include #include #include #include "hexchat-plugin.h" #include "dbus-plugin.h" #define PNAME _("remote access") #define PDESC _("plugin for remote access using DBUS") #define PVERSION "" #define DBUS_SERVICE "org.hexchat.service" #define DBUS_OBJECT_PATH "/org/hexchat" static hexchat_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; hexchat_context *context; char *dbus_path; char *filename; GHashTable *hooks; GHashTable *lists; void *handle; }; struct RemoteObjectClass { GObjectClass parent; }; typedef struct { guint id; int return_value; hexchat_hook *hook; RemoteObject *obj; } HookInfo; typedef struct { guint id; hexchat_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 "../marshal.h" /* Useful functions */ static char** build_list (char *word[]); st
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibvc", "zlibvc.vcxproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "zlibstat.vcxproj", "{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlib", "testzlib.vcxproj", "{AA6666AA-E09F-4135-9C0C-4FE50C3C654B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlibdll", "testzlibdll.vcxproj", "{C52F9E7B-498A-42BE-8DB4-85A15694366A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minizip", "minizip.vcxproj", "{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniunz", "miniunz.vcxproj", "{C52F9E7B-498A-42BE-8DB4-85A15694382A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "install", "install.vcxproj", "{6064E3A9-3939-4937-A387-C09299FC2952}"
	ProjectSection(ProjectDependencies) = postProject
		{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8} = {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}
		{C52F9E7B-498A-42BE-8DB4-85A15694366A} = {C52F9E7B-498A-42BE-8DB4-85A15694366A}
		{C52F9E7B-498A-42BE-8DB4-85A15694382A} = {C52F9E7B-498A-42BE-8DB4-85A15694382A}
		{AA6666AA-E09F-4135-9C0C-4FE50C3C654B} = {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}
		{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B} = {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}
		{8FD826F8-3739-44E6-8CC8-997122E53B8D} = {8FD826F8-3739-44E6-8CC8-997122E53B8D}
	EndProjectSection
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Release|Win32 = Release|Win32
		Release|x64 = Release|x64
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.ActiveCfg = Release|Win32
		{8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.Build.0 = Release|Win32
		{8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.ActiveCfg = Release|x64
		{8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.Build.0 = Release|x64
		{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.ActiveCfg = Release|Win32
		{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.Build.0 = Release|Win32
		{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.ActiveCfg = Release|x64
		{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.Build.0 = Release|x64
		{AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32
		{AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64
		{C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.ActiveCfg = Release|Win32
		{C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.Build.0 = Release|Win32
		{C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.ActiveCfg = Release|x64
		{C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.Build.0 = Release|x64
		{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32
		{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32
		{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64
		{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64
		{C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.ActiveCfg = Release|Win32
		{C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.Build.0 = Release|Win32
		{C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.ActiveCfg = Release|x64
		{C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.Build.0 = Release|x64
		{6064E3A9-3939-4937-A387-C09299FC2952}.Release|Win32.ActiveCfg = Release|Win32
		{6064E3A9-3939-4937-A387-C09299FC2952}.Release|Win32.Build.0 = Release|Win32
		{6064E3A9-3939-4937-A387-C09299FC2952}.Release|x64.ActiveCfg = Release|x64
		{6064E3A9-3939-4937-A387-C09299FC2952}.Release|x64.Build.0 = Release|x64
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
EndGlobal
oolean remote_object_list_str (RemoteObject *obj, guint id, const char *name, char **ret_str, GError **error) { hexchat_list *xlist; xlist = g_hash_table_lookup (obj->lists, &id); if (xlist == NULL && !hexchat_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 (hexchat_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) { hexchat_list *xlist; xlist = g_hash_table_lookup (obj->lists, &id); if (xlist == NULL && !hexchat_set_context (ph, obj->context)) { *ret_int = -1; return TRUE; } if (g_str_equal (name, "context")) { hexchat_context *context; context = (hexchat_context*)hexchat_list_str (ph, xlist, name); *ret_int = context_list_find_id (context); } else { *ret_int = hexchat_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) { hexchat_list *xlist; xlist = g_hash_table_lookup (obj->lists, &id); if (xlist == NULL) { *ret_time = (guint64) -1; return TRUE; } *ret_time = hexchat_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**)hexchat_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 = hexchat_set_context (ph, obj->context); if (*ret) { *ret = hexchat_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) { hexchat_set_context (ph, obj->context); *ret = hexchat_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 = hexchat_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 (hexchat_set_context (ph, obj->context)) { hexchat_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) { hexchat_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)) { hexchat_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; } /* hexchat_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 (hexchat_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 hexchat_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 = hexchat_get_context (ph); contexts = g_list_prepend (contexts, info); return HEXCHAT_EAT_NONE; } static int close_context_cb (char *word[], void *userdata) { GList *l; hexchat_context *context = hexchat_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 HEXCHAT_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 HEXCHAT_EAT_ALL; } return HEXCHAT_EAT_NONE; } int dbus_plugin_init (hexchat_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()) { /*hexchat_printf (ph, _("%s loaded successfully!\n"), PNAME);*/ clients = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); hexchat_hook_print (ph, "Open Context", HEXCHAT_PRI_NORM, open_context_cb, NULL); hexchat_hook_print (ph, "Close Context", HEXCHAT_PRI_NORM, close_context_cb, NULL); hexchat_hook_command (ph, "unload", HEXCHAT_PRI_HIGHEST, unload_plugin_cb, NULL, NULL); } return TRUE; }