changeset 6822:7dba3e17cb21

[gaim-migrate @ 7366] Added plugin IPC. Its use is shown in plugins/ipc-test-server.c and plugins/ipc-test-client.c. committer: Tailor Script <tailor@pidgin.im>
author Christian Hammond <chipx86@chipx86.com>
date Sat, 13 Sep 2003 09:31:03 +0000
parents 636b5215552e
children 2a6f5eb2d561
files ChangeLog plugins/ipc-test-client.c plugins/ipc-test-server.c plugins/raw.c src/plugin.c src/plugin.h src/signals.c src/signals.h
diffstat 8 files changed, 549 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Fri Sep 12 23:32:10 2003 +0000
+++ b/ChangeLog	Sat Sep 13 09:31:03 2003 +0000
@@ -15,6 +15,7 @@
 	  online accounts as colored.
 	* Fixed the text replacement plugin.
 	* Added SSL support, compatible with GNUTLS and Mozilla NSS.
+	* Added plugin IPC.
 	* Added support for gettext 0.12.x.
 	* The right-click menu for conversation tabs now shows the tab icon
 	  and status, if tab icons are enabled. (Jesse Farmer)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/ipc-test-client.c	Sat Sep 13 09:31:03 2003 +0000
@@ -0,0 +1,109 @@
+/*
+ * IPC test client plugin.
+ *
+ * Copyright (C) 2003 Christian Hammond.
+ *
+ * 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.
+ */
+#include "internal.h"
+#include "debug.h"
+#include "plugin.h"
+
+#define IPC_TEST_CLIENT_PLUGIN_ID "core-ipc-test-client"
+
+static gboolean
+plugin_load(GaimPlugin *plugin)
+{
+	GaimPlugin *server_plugin;
+	gboolean ok;
+	int result;
+
+	server_plugin = gaim_plugins_find_with_id("core-ipc-test-server");
+
+	if (server_plugin == NULL)
+	{
+		gaim_debug_error("ipc-test-client",
+						 "Unable to locate plugin core-ipc-test-server, "
+						 "needed for IPC.\n");
+
+		return TRUE;
+	}
+
+	result = (int)gaim_plugin_ipc_call(server_plugin, "add", &ok, 36, 6);
+
+	if (!ok)
+	{
+		gaim_debug_error("ipc-test-client",
+						 "Unable to call IPC function 'add' in "
+						 "core-ipc-test-server plugin.");
+
+		return TRUE;
+	}
+
+	gaim_debug_info("ipc-test-client", "36 + 6 = %d\n", result);
+
+	result = (int)gaim_plugin_ipc_call(server_plugin, "sub", &ok, 50, 8);
+
+	if (!ok)
+	{
+		gaim_debug_error("ipc-test-client",
+						 "Unable to call IPC function 'sub' in "
+						 "core-ipc-test-server plugin.");
+
+		return TRUE;
+	}
+
+	gaim_debug_info("ipc-test-client", "50 - 8 = %d\n", result);
+
+	return TRUE;
+}
+
+static GaimPluginInfo info =
+{
+	2,                                                /**< api_version    */
+	GAIM_PLUGIN_STANDARD,                             /**< type           */
+	NULL,                                             /**< ui_requirement */
+	0,                                                /**< flags          */
+	NULL,                                             /**< dependencies   */
+	GAIM_PRIORITY_DEFAULT,                            /**< priority       */
+
+	IPC_TEST_CLIENT_PLUGIN_ID,                        /**< id             */
+	N_("IPC Test Client"),                            /**< name           */
+	VERSION,                                          /**< version        */
+	                                                  /**  summary        */
+	N_("Test plugin IPC support, as a client."),
+	                                                  /**  description    */
+	N_("Test plugin IPC support, as a client. This locates the server "
+	   "plugin and calls the commands registered."),
+	"Christian Hammond <chipx86@gnupdate.org>",       /**< author         */
+	GAIM_WEBSITE,                                     /**< homepage       */
+
+	plugin_load,                                      /**< load           */
+	NULL,                                             /**< unload         */
+	NULL,                                             /**< destroy        */
+
+	NULL,                                             /**< ui_info        */
+	NULL                                              /**< extra_info     */
+};
+
+static void
+init_plugin(GaimPlugin *plugin)
+{
+	info.dependencies = g_list_append(info.dependencies,
+									  "core-ipc-test-server");
+}
+
+GAIM_INIT_PLUGIN(ipctestclient, init_plugin, info)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/ipc-test-server.c	Sat Sep 13 09:31:03 2003 +0000
@@ -0,0 +1,94 @@
+/*
+ * IPC test server plugin.
+ *
+ * Copyright (C) 2003 Christian Hammond.
+ *
+ * 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.
+ */
+#define IPC_TEST_SERVER_PLUGIN_ID "core-ipc-test-server"
+
+#include "internal.h"
+#include "debug.h"
+#include "plugin.h"
+
+static int
+add_func(int i1, int i2)
+{
+	gaim_debug_misc("ipc-test-server", "Got %d, %d, returning %d\n",
+					i1, i2, i1 + i2);
+	return i1 + i2;
+}
+
+static int
+sub_func(int i1, int i2)
+{
+	gaim_debug_misc("ipc-test-server", "Got %d, %d, returning %d\n",
+					i1, i2, i1 - i2);
+	return i1 - i2;
+}
+
+static gboolean
+plugin_load(GaimPlugin *plugin)
+{
+	gaim_plugin_ipc_register(plugin, "add", GAIM_CALLBACK(add_func),
+							 gaim_marshal_INT__INT_INT,
+							 gaim_value_new(GAIM_TYPE_INT), 2,
+							 gaim_value_new(GAIM_TYPE_INT),
+							 gaim_value_new(GAIM_TYPE_INT));
+
+	gaim_plugin_ipc_register(plugin, "sub", GAIM_CALLBACK(sub_func),
+							 gaim_marshal_INT__INT_INT,
+							 gaim_value_new(GAIM_TYPE_INT), 2,
+							 gaim_value_new(GAIM_TYPE_INT),
+							 gaim_value_new(GAIM_TYPE_INT));
+
+	return TRUE;
+}
+
+static GaimPluginInfo info =
+{
+	2,                                                /**< api_version    */
+	GAIM_PLUGIN_STANDARD,                             /**< type           */
+	NULL,                                             /**< ui_requirement */
+	0,                                                /**< flags          */
+	NULL,                                             /**< dependencies   */
+	GAIM_PRIORITY_DEFAULT,                            /**< priority       */
+
+	IPC_TEST_SERVER_PLUGIN_ID,                        /**< id             */
+	N_("IPC Test Server"),                            /**< name           */
+	VERSION,                                          /**< version        */
+	                                                  /**  summary        */
+	N_("Test plugin IPC support, as a server."),
+	                                                  /**  description    */
+	N_("Test plugin IPC support, as a server. This registers the IPC "
+	   "commands."),
+	"Christian Hammond <chipx86@gnupdate.org>",       /**< author         */
+	GAIM_WEBSITE,                                     /**< homepage       */
+
+	plugin_load,                                      /**< load           */
+	NULL,                                             /**< unload         */
+	NULL,                                             /**< destroy        */
+
+	NULL,                                             /**< ui_info        */
+	NULL                                              /**< extra_info     */
+};
+
+static void
+init_plugin(GaimPlugin *plugin)
+{
+}
+
+GAIM_INIT_PLUGIN(ipctestserver, init_plugin, info)
--- a/plugins/raw.c	Fri Sep 12 23:32:10 2003 +0000
+++ b/plugins/raw.c	Sat Sep 13 09:31:03 2003 +0000
@@ -41,6 +41,7 @@
 
 	txt = gtk_entry_get_text(entry);
 
+	gaim_debug_misc("raw", "prpl num = %d\n", gaim_account_get_protocol(account));
 	switch (gaim_account_get_protocol(account)) {
 		case GAIM_PROTO_TOC:
 			{
@@ -76,6 +77,8 @@
 			break;
 
 		default:
+			gaim_debug_error("raw", "Unknown protocol ID %d\n",
+							 gaim_account_get_protocol(account));
 			break;
 	}
 
--- a/src/plugin.c	Fri Sep 12 23:32:10 2003 +0000
+++ b/src/plugin.c	Sat Sep 13 09:31:03 2003 +0000
@@ -17,23 +17,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
-/*
- * ----------------
- * The Plug-in plugin
- *
- * Plugin support is currently being maintained by Mike Saraf
- * msaraf@dwc.edu
- *
- * Well, I didn't see any work done on it for a while, so I'm going to try
- * my hand at it. - Eric warmenhoven@yahoo.com
- *
- * Mike is my roomate.  I can assure you that he's lazy :-P
- * -- Rob rob@marko.net
- *
- * Yeah, well now I'm re-writing a good portion of it! The perl stuff was
- * a hack. Tsk tsk! -- Christian <chipx86@gnupdate.org>
- */
 #include "internal.h"
 
 #include "accountopt.h"
@@ -54,6 +37,24 @@
 #endif
 #endif
 
+typedef struct
+{
+	GHashTable *commands;
+	size_t command_count;
+
+} GaimPluginIpcInfo;
+
+typedef struct
+{
+	GaimCallback func;
+	GaimSignalMarshalFunc marshal;
+
+	int num_params;
+	GaimValue **params;
+	GaimValue *ret_value;
+
+} GaimPluginIpcCommand;
+
 static GList *loaded_plugins = NULL;
 static GList *plugins = NULL;
 static GList *plugin_loaders = NULL;
@@ -395,6 +396,7 @@
 	}
 
 	gaim_signals_disconnect_by_handle(plugin);
+	gaim_plugin_ipc_unregister_all(plugin);
 
 	/* TODO */
 	if (unload_cb != NULL)
@@ -499,6 +501,201 @@
 	return plugin->loaded;
 }
 
+/**************************************************************************
+ * Plugin IPC
+ **************************************************************************/
+static void
+destroy_ipc_info(void *data)
+{
+	GaimPluginIpcCommand *ipc_command = (GaimPluginIpcCommand *)data;
+	int i;
+
+	for (i = 0; i < ipc_command->num_params; i++)
+		gaim_value_destroy(ipc_command->params[i]);
+
+	if (ipc_command->ret_value != NULL)
+		gaim_value_destroy(ipc_command->ret_value);
+
+	g_free(ipc_command);
+}
+
+gboolean
+gaim_plugin_ipc_register(GaimPlugin *plugin, const char *command,
+						 GaimCallback func, GaimSignalMarshalFunc marshal,
+						 GaimValue *ret_value, int num_params, ...)
+{
+	GaimPluginIpcInfo *ipc_info;
+	GaimPluginIpcCommand *ipc_command;
+
+	g_return_val_if_fail(plugin  != NULL, FALSE);
+	g_return_val_if_fail(command != NULL, FALSE);
+	g_return_val_if_fail(func    != NULL, FALSE);
+	g_return_val_if_fail(marshal != NULL, FALSE);
+
+	if (plugin->ipc_data == NULL)
+	{
+		ipc_info = plugin->ipc_data = g_new0(GaimPluginIpcInfo, 1);
+		ipc_info->commands = g_hash_table_new_full(g_str_hash, g_str_equal,
+												   g_free, destroy_ipc_info);
+	}
+	else
+		ipc_info = (GaimPluginIpcInfo *)plugin->ipc_data;
+
+	ipc_command = g_new0(GaimPluginIpcCommand, 1);
+	ipc_command->func       = func;
+	ipc_command->marshal    = marshal;
+	ipc_command->num_params = num_params;
+	ipc_command->ret_value  = ret_value;
+
+	if (num_params > 0)
+	{
+		va_list args;
+		int i;
+
+		ipc_command->params = g_new0(GaimValue *, num_params);
+
+		va_start(args, num_params);
+
+		for (i = 0; i < num_params; i++)
+			ipc_command->params[i] = va_arg(args, GaimValue *);
+
+		va_end(args);
+	}
+
+	g_hash_table_replace(ipc_info->commands, g_strdup(command), ipc_command);
+
+	ipc_info->command_count++;
+
+	return TRUE;
+}
+
+void
+gaim_plugin_ipc_unregister(GaimPlugin *plugin, const char *command)
+{
+	GaimPluginIpcInfo *ipc_info;
+
+	g_return_if_fail(plugin  != NULL);
+	g_return_if_fail(command != NULL);
+
+	ipc_info = (GaimPluginIpcInfo *)plugin->ipc_data;
+
+	if (ipc_info == NULL ||
+		g_hash_table_lookup(ipc_info->commands, command) == NULL)
+	{
+		gaim_debug_error("plugins",
+						 "IPC command '%s' was not registered for plugin %s\n",
+						 command, plugin->info->name);
+		return;
+	}
+
+	g_hash_table_remove(ipc_info->commands, command);
+
+	ipc_info->command_count--;
+
+	if (ipc_info->command_count == 0)
+	{
+		g_hash_table_destroy(ipc_info->commands);
+		g_free(ipc_info);
+
+		plugin->ipc_data = NULL;
+	}
+}
+
+void
+gaim_plugin_ipc_unregister_all(GaimPlugin *plugin)
+{
+	GaimPluginIpcInfo *ipc_info;
+
+	g_return_if_fail(plugin != NULL);
+
+	if (plugin->ipc_data == NULL)
+		return; /* Silently ignore it. */
+
+	ipc_info = (GaimPluginIpcInfo *)plugin->ipc_data;
+
+	g_hash_table_destroy(ipc_info->commands);
+	g_free(ipc_info);
+
+	plugin->ipc_data = NULL;
+}
+
+gboolean
+gaim_plugin_ipc_get_params(GaimPlugin *plugin, const char *command,
+						   GaimValue **ret_value, int *num_params,
+						   GaimValue ***params)
+{
+	GaimPluginIpcInfo *ipc_info;
+	GaimPluginIpcCommand *ipc_command;
+
+	g_return_val_if_fail(plugin  != NULL, FALSE);
+	g_return_val_if_fail(command != NULL, FALSE);
+
+	ipc_info = (GaimPluginIpcInfo *)plugin->ipc_data;
+
+	if (ipc_info == NULL ||
+		(ipc_command = g_hash_table_lookup(ipc_info->commands,
+										   command)) == NULL)
+	{
+		gaim_debug_error("plugins",
+						 "IPC command '%s' was not registered for plugin %s\n",
+						 command, plugin->info->name);
+
+		return FALSE;
+	}
+
+	if (num_params != NULL)
+		*num_params = ipc_command->num_params;
+
+	if (params != NULL)
+		*params = ipc_command->params;
+
+	if (ret_value != NULL)
+		*ret_value = ipc_command->ret_value;
+
+	return TRUE;
+}
+
+void *
+gaim_plugin_ipc_call(GaimPlugin *plugin, const char *command,
+					 gboolean *ok, ...)
+{
+	GaimPluginIpcInfo *ipc_info;
+	GaimPluginIpcCommand *ipc_command;
+	va_list args;
+	void *ret_value;
+
+	if (ok != NULL)
+		*ok = FALSE;
+
+	g_return_val_if_fail(plugin  != NULL, NULL);
+	g_return_val_if_fail(command != NULL, NULL);
+
+	ipc_info = (GaimPluginIpcInfo *)plugin->ipc_data;
+
+	if (ipc_info == NULL ||
+		(ipc_command = g_hash_table_lookup(ipc_info->commands,
+										   command)) == NULL)
+	{
+		gaim_debug_error("plugins",
+						 "IPC command '%s' was not registered for plugin %s\n",
+						 command, plugin->info->name);
+
+		return NULL;
+	}
+
+	va_start(args, ok);
+	ipc_command->marshal(ipc_command->func, args, NULL, &ret_value);
+	va_end(args);
+
+	if (ok != NULL)
+		*ok = TRUE;
+
+	return ret_value;
+}
+
+/**************************************************************************
+ * Plugins subsystem
+ **************************************************************************/
 void
 gaim_plugins_set_search_paths(size_t count, char **paths)
 {
--- a/src/plugin.h	Fri Sep 12 23:32:10 2003 +0000
+++ b/src/plugin.h	Sat Sep 13 09:31:03 2003 +0000
@@ -24,6 +24,8 @@
 #define _GAIM_PLUGIN_H_
 
 #include <gmodule.h>
+#include "signals.h"
+#include "value.h"
 
 typedef struct _GaimPlugin     GaimPlugin;         /**< GaimPlugin       */
 typedef struct _GaimPluginInfo GaimPluginInfo;     /**< GaimPluginInfo   */
@@ -88,8 +90,6 @@
 	gboolean (*load)(GaimPlugin *plugin);
 	gboolean (*unload)(GaimPlugin *plugin);
 	void     (*destroy)(GaimPlugin *plugin);
-
-	/* XXX GaimSignalBroadcastFunc broadcast; */
 };
 
 /**
@@ -103,6 +103,7 @@
 	char *path;                            /**< The path to the plugin.   */
 	GaimPluginInfo *info;                  /**< The plugin information.   */
 	char *error;
+	void *ipc_data;                        /**< IPC data.                 */
 	void *extra;                           /**< Plugin-specific data.     */
 };
 
@@ -225,6 +226,76 @@
 /*@}*/
 
 /**************************************************************************/
+/** @name Plugin IPC API                                                  */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Registers an IPC command in a plugin.
+ *
+ * @param plugin     The plugin to register the command with.
+ * @param command    The name of the command.
+ * @param func       The function to execute.
+ * @param marshal    The marshalling function.
+ * @param ret_value  The return value type.
+ * @param num_values The number of parameters.
+ * @param ...        The parameter types.
+ *
+ * @return TRUE if the function was registered successfully, or
+ *         FALSE otherwise.
+ */
+gboolean gaim_plugin_ipc_register(GaimPlugin *plugin, const char *command,
+								  GaimCallback func,
+								  GaimSignalMarshalFunc marshal,
+								  GaimValue *ret_value, int num_params, ...);
+
+/**
+ * Unregisters an IPC command in a plugin.
+ *
+ * @param plugin  The plugin to unregister the command from.
+ * @param command The name of the command.
+ */
+void gaim_plugin_ipc_unregister(GaimPlugin *plugin, const char *command);
+
+/**
+ * Unregisters all IPC commands in a plugin.
+ *
+ * @param plugin The plugin to unregister the commands from.
+ */
+void gaim_plugin_ipc_unregister_all(GaimPlugin *plugin);
+
+/**
+ * Returns a list of value types used for an IPC command.
+ *
+ * @param plugin     The plugin.
+ * @param command    The name of the command.
+ * @param ret_value  The returned return value.
+ * @param num_params The returned number of parameters.
+ * @param params     The returned list of parameters.
+ *
+ * @return TRUE if the command was found, or FALSE otherwise.
+ */
+gboolean gaim_plugin_ipc_get_params(GaimPlugin *plugin, const char *command,
+									GaimValue **ret_value, int *num_params,
+									GaimValue ***params);
+
+/**
+ * Executes an IPC command.
+ *
+ * @param plugin  The plugin to execute the command on.
+ * @param command The name of the command.
+ * @param ok      TRUE if the call was successful, or FALSE otherwise.
+ * @param ...     The parameters to pass.
+ *
+ * @return The return value, which will be NULL if the command doesn't
+ *         return a value.
+ */
+void *gaim_plugin_ipc_call(GaimPlugin *plugin, const char *command,
+						   gboolean *ok, ...);
+
+/*@}*/
+
+/**************************************************************************/
 /** @name Plugins API                                                     */
 /**************************************************************************/
 /*@{*/
--- a/src/signals.c	Fri Sep 12 23:32:10 2003 +0000
+++ b/src/signals.c	Sat Sep 13 09:31:03 2003 +0000
@@ -536,6 +536,25 @@
 }
 
 void
+gaim_marshal_VOID__INT(GaimCallback cb, va_list args, void *data,
+					   void **return_val)
+{
+	gint arg1 = va_arg(args, gint);
+
+	((void (*)(gint, void *))cb)(arg1, data);
+}
+
+void
+gaim_marshal_VOID__INT_INT(GaimCallback cb, va_list args, void *data,
+						   void **return_val)
+{
+	gint arg1 = va_arg(args, gint);
+	gint arg2 = va_arg(args, gint);
+
+	((void (*)(gint, gint, void *))cb)(arg1, arg2, data);
+}
+
+void
 gaim_marshal_VOID__POINTER(GaimCallback cb, va_list args, void *data,
 						   void **return_val)
 {
@@ -621,6 +640,33 @@
 }
 
 void
+gaim_marshal_INT__INT(GaimCallback cb, va_list args, void *data,
+					  void **return_val)
+{
+	gint ret_val;
+	gint arg1 = va_arg(args, gint);
+
+	ret_val = ((gint (*)(gint, void *))cb)(arg1, data);
+
+	if (return_val != NULL)
+		*return_val = GINT_TO_POINTER(ret_val);
+}
+
+void
+gaim_marshal_INT__INT_INT(GaimCallback cb, va_list args, void *data,
+						  void **return_val)
+{
+	gint ret_val;
+	gint arg1 = va_arg(args, gint);
+	gint arg2 = va_arg(args, gint);
+
+	ret_val = ((gint (*)(gint, gint, void *))cb)(arg1, arg2, data);
+
+	if (return_val != NULL)
+		*return_val = GINT_TO_POINTER(ret_val);
+}
+
+void
 gaim_marshal_BOOLEAN__POINTER(GaimCallback cb, va_list args, void *data,
 							  void **return_val)
 {
--- a/src/signals.h	Fri Sep 12 23:32:10 2003 +0000
+++ b/src/signals.h	Sat Sep 13 09:31:03 2003 +0000
@@ -213,6 +213,10 @@
 
 void gaim_marshal_VOID(
 		GaimCallback cb, va_list args, void *data, void **return_val);
+void gaim_marshal_VOID__INT(
+		GaimCallback cb, va_list args, void *data, void **return_val);
+void gaim_marshal_VOID__INT_INT(
+		GaimCallback cb, va_list args, void *data, void **return_val);
 void gaim_marshal_VOID__POINTER(
 		GaimCallback cb, va_list args, void *data, void **return_val);
 void gaim_marshal_VOID__POINTER_POINTER(
@@ -228,6 +232,11 @@
 void gaim_marshal_VOID__POINTER_POINTER_POINTER_UINT_UINT(
 		GaimCallback cb, va_list args, void *data, void **return_val);
 
+void gaim_marshal_INT__INT(
+		GaimCallback cb, va_list args, void *data, void **return_val);
+void gaim_marshal_INT__INT_INT(
+		GaimCallback cb, va_list args, void *data, void **return_val);
+
 void gaim_marshal_BOOLEAN__POINTER(
 		GaimCallback cb, va_list args, void *data, void **return_val);
 void gaim_marshal_BOOLEAN__POINTER_POINTER(