Started the new GObject plugin API soc.2013.gobjectification.plugins

Sun, 28 Jul 2013 18:27:54 +0530

author
Ankit Vani <a@nevitus.org>
date
Sun, 28 Jul 2013 18:27:54 +0530
branch
soc.2013.gobjectification.plugins
changeset 36357
1a49a1a9ce18
parent 36356
2d4fe57fade2
child 36358
a3ef1c1c7b55

Started the new GObject plugin API

libpurple/plugin.c file | annotate | diff | comparison | revisions
libpurple/plugin.h file | annotate | diff | comparison | revisions
--- a/libpurple/plugin.c	Sat Jul 27 16:46:06 2013 +0530
+++ b/libpurple/plugin.c	Sun Jul 28 18:27:54 2013 +0530
@@ -19,1596 +19,118 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#define _PURPLE_PLUGIN_C_
-
-#include "internal.h"
-
-#include "accountopt.h"
-#include "core.h"
-#include "dbus-maybe.h"
-#include "debug.h"
-#include "notify.h"
-#include "prefs.h"
-#include "prpl.h"
-#include "request.h"
-#include "signals.h"
-#include "util.h"
-#include "valgrind.h"
-#include "version.h"
+#include "plugin.h"
 
-typedef struct
-{
-	GHashTable *commands;
-	size_t command_count;
-
-} PurplePluginIpcInfo;
+#define PURPLE_PLUGIN_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_PLUGIN, PurplePluginPrivate))
 
-typedef struct
-{
-	PurpleCallback func;
-	PurpleSignalMarshalFunc marshal;
-
-	int num_params;
-	GType *param_types;
-	GType ret_type;
-
-} PurplePluginIpcCommand;
+/** @copydoc _PurplePluginPrivate */
+typedef struct _PurplePluginPrivate  PurplePluginPrivate;
 
-static GList *search_paths     = NULL;
-static GList *plugins          = NULL;
-static GList *loaded_plugins   = NULL;
-static GList *protocol_plugins = NULL;
-#ifdef PURPLE_PLUGINS
-static GList *load_queue       = NULL;
-static GList *plugin_loaders   = NULL;
-static GList *plugins_to_disable = NULL;
-#endif
-
-#ifdef PURPLE_PLUGINS
-
-static gboolean
-has_file_extension(const char *filename, const char *ext)
-{
-	int len, extlen;
+/**************************************************************************
+ * Private data
+ **************************************************************************/
+struct _PurplePluginPrivate {
+	gboolean unloadable;
+};
 
-	if (filename == NULL || *filename == '\0' || ext == NULL)
-		return 0;
-
-	extlen = strlen(ext);
-	len = strlen(filename) - extlen;
-
-	if (len < 0)
-		return 0;
+/* Plugin property enums */
+enum
+{
+	PROP_0,
+	PROP_UNLOADABLE,
+	PROP_LAST
+};
 
-	return (strncmp(filename + len, ext, extlen) == 0);
-}
-
-static gboolean
-is_native(const char *filename)
-{
-	const char *last_period;
-
-	last_period = strrchr(filename, '.');
-	if (last_period == NULL)
-		return FALSE;
+static GPluginPluginImplementationClass *parent_class;
 
-	return !(strcmp(last_period, ".dll") &
-			 strcmp(last_period, ".sl") &
-			 strcmp(last_period, ".so"));
-}
+/**************************************************************************
+ * Plugin API
+ **************************************************************************/
 
-static char *
-purple_plugin_get_basename(const char *filename)
-{
-	const char *basename;
-	const char *last_period;
-
-	basename = strrchr(filename, G_DIR_SEPARATOR);
-	if (basename != NULL)
-		basename++;
-	else
-		basename = filename;
 
-	if (is_native(basename) &&
-		((last_period = strrchr(basename, '.')) != NULL))
-			return g_strndup(basename, (last_period - basename));
-
-	return g_strdup(basename);
-}
-
-static gboolean
-loader_supports_file(PurplePlugin *loader, const char *filename)
-{
-	GList *exts;
-
-	for (exts = PURPLE_PLUGIN_LOADER_INFO(loader)->exts; exts != NULL; exts = exts->next) {
-		if (has_file_extension(filename, (char *)exts->data)) {
-			return TRUE;
-		}
-	}
-
-	return FALSE;
-}
+/**************************************************************************
+ * GObject code
+ **************************************************************************/
+/* GObject Property names */
+#define PROP_UNLOADABLE_S  "unloadable"
 
-static PurplePlugin *
-find_loader_for_plugin(const PurplePlugin *plugin)
+/* Set method for GObject properties */
+static void
+purple_plugin_set_property(GObject *obj, guint param_id, const GValue *value,
+		GParamSpec *pspec)
 {
-	PurplePlugin *loader;
-	GList *l;
-
-	if (plugin->path == NULL)
-		return NULL;
-
-	for (l = purple_plugins_get_loaded(); l != NULL; l = l->next) {
-		loader = l->data;
-
-		if (loader->info->type == PURPLE_PLUGIN_LOADER &&
-			loader_supports_file(loader, plugin->path)) {
-
-			return loader;
-		}
-
-		loader = NULL;
-	}
+	PurplePlugin *plugin = PURPLE_PLUGIN(obj);
 
-	return NULL;
-}
-
-#endif /* PURPLE_PLUGINS */
-
-/**
- * Negative if a before b, 0 if equal, positive if a after b.
- */
-static gint
-compare_prpl(PurplePlugin *a, PurplePlugin *b)
-{
-	if(PURPLE_IS_PROTOCOL_PLUGIN(a)) {
-		if(PURPLE_IS_PROTOCOL_PLUGIN(b))
-			return strcmp(a->info->name, b->info->name);
-		else
-			return -1;
-	} else {
-		if(PURPLE_IS_PROTOCOL_PLUGIN(b))
-			return 1;
-		else
-			return 0;
+	switch (param_id) {
+		case PROP_UNLOADABLE:
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
 	}
 }
 
-PurplePlugin *
-purple_plugin_new(gboolean native, const char *path)
-{
-	PurplePlugin *plugin;
-
-	plugin = g_new0(PurplePlugin, 1);
-
-	plugin->native_plugin = native;
-	plugin->path = g_strdup(path);
-
-	PURPLE_DBUS_REGISTER_POINTER(plugin, PurplePlugin);
-
-	return plugin;
-}
-
-PurplePlugin *
-purple_plugin_probe(const char *filename)
+/* Get method for GObject properties */
+static void
+purple_plugin_get_property(GObject *obj, guint param_id, GValue *value,
+		GParamSpec *pspec)
 {
-#ifdef PURPLE_PLUGINS
-	PurplePlugin *plugin = NULL;
-	PurplePlugin *loader;
-	gpointer unpunned;
-	gchar *basename = NULL;
-	gboolean (*purple_init_plugin)(PurplePlugin *);
-
-	purple_debug_misc("plugins", "probing %s\n", filename);
-	g_return_val_if_fail(filename != NULL, NULL);
-
-	if (!g_file_test(filename, G_FILE_TEST_EXISTS))
-		return NULL;
-
-	/* If this plugin has already been probed then exit */
-	basename = purple_plugin_get_basename(filename);
-	plugin = purple_plugins_find_with_basename(basename);
-	g_free(basename);
-	if (plugin != NULL)
-	{
-		if (purple_strequal(filename, plugin->path))
-			return plugin;
-		else if (!purple_plugin_is_unloadable(plugin))
-		{
-			purple_debug_warning("plugins", "Not loading %s. "
-							"Another plugin with the same name (%s) has already been loaded.\n",
-							filename, plugin->path);
-			return plugin;
-		}
-		else
-		{
-			/* The old plugin was a different file and it was unloadable.
-			 * There's no guarantee that this new file with the same name
-			 * will be loadable, but unless it fails in one of the silent
-			 * ways and the first one didn't, it's not any worse.  The user
-			 * will still see a greyed-out plugin, which is what we want. */
-			purple_plugin_destroy(plugin);
-		}
-	}
-
-	plugin = purple_plugin_new(has_file_extension(filename, G_MODULE_SUFFIX), filename);
-
-	if (plugin->native_plugin) {
-		const char *error;
-#ifdef _WIN32
-		/* Suppress error popups for failing to load plugins */
-		UINT old_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
-#endif
-
-		/*
-		 * We pass G_MODULE_BIND_LOCAL here to prevent symbols from
-		 * plugins being added to the global name space.
-		 *
-		 * G_MODULE_BIND_LOCAL was added in glib 2.3.3.
-		 */
-		plugin->handle = g_module_open(filename, G_MODULE_BIND_LOCAL);
-
-		if (plugin->handle == NULL)
-		{
-			const char *error = g_module_error();
-			if (error != NULL && purple_str_has_prefix(error, filename))
-			{
-				error = error + strlen(filename);
-
-				/* These are just so we don't crash.  If we
-				 * got this far, they should always be true. */
-				if (*error == ':')
-					error++;
-				if (*error == ' ')
-					error++;
-			}
-
-			if (error == NULL || !*error)
-			{
-				plugin->error = g_strdup(_("Unknown error"));
-				purple_debug_error("plugins", "%s is not loadable: Unknown error\n",
-						 plugin->path);
-			}
-			else
-			{
-				plugin->error = g_strdup(error);
-				purple_debug_error("plugins", "%s is not loadable: %s\n",
-						 plugin->path, plugin->error);
-			}
-			plugin->handle = g_module_open(filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
-
-			if (plugin->handle == NULL)
-			{
-#ifdef _WIN32
-				/* Restore the original error mode */
-				SetErrorMode(old_error_mode);
-#endif
-				purple_plugin_destroy(plugin);
-				return NULL;
-			}
-			else
-			{
-				/* We were able to load the plugin with lazy symbol binding.
-				 * This means we're missing some symbol.  Mark it as
-				 * unloadable and keep going so we get the info to display
-				 * to the user so they know to rebuild this plugin. */
-				plugin->unloadable = TRUE;
-			}
-		}
-
-		if (!g_module_symbol(plugin->handle, "purple_init_plugin",
-							 &unpunned))
-		{
-			purple_debug_error("plugins", "%s is not usable because the "
-							 "'purple_init_plugin' symbol could not be "
-							 "found.  Does the plugin call the "
-							 "PURPLE_INIT_PLUGIN() macro?\n", plugin->path);
-
-			g_module_close(plugin->handle);
-			error = g_module_error();
-			if (error != NULL)
-				purple_debug_error("plugins", "Error closing module %s: %s\n",
-								 plugin->path, error);
-			plugin->handle = NULL;
-
-#ifdef _WIN32
-			/* Restore the original error mode */
-			SetErrorMode(old_error_mode);
-#endif
-			purple_plugin_destroy(plugin);
-			return NULL;
-		}
-		purple_init_plugin = unpunned;
-
-#ifdef _WIN32
-		/* Restore the original error mode */
-		SetErrorMode(old_error_mode);
-#endif
-	}
-	else {
-		loader = find_loader_for_plugin(plugin);
-
-		if (loader == NULL) {
-			purple_plugin_destroy(plugin);
-			return NULL;
-		}
-
-		purple_init_plugin = PURPLE_PLUGIN_LOADER_INFO(loader)->probe;
-	}
-
-	if (!purple_init_plugin(plugin) || plugin->info == NULL)
-	{
-		purple_plugin_destroy(plugin);
-		return NULL;
-	}
-	else if (plugin->info->ui_requirement &&
-			!purple_strequal(plugin->info->ui_requirement, purple_core_get_ui()))
-	{
-		plugin->error = g_strdup_printf(_("You are using %s, but this plugin requires %s."),
-					purple_core_get_ui(), plugin->info->ui_requirement);
-		purple_debug_error("plugins", "%s is not loadable: The UI requirement is not met. (%s)\n", plugin->path, plugin->error);
-		plugin->unloadable = TRUE;
-		return plugin;
-	}
-
-	/*
-	 * Check to make sure a plugin has defined an id.
-	 * Not having this check caused purple_plugin_unload to
-	 * enter an infinite loop in certain situations by passing
-	 * purple_find_plugin_by_id a NULL value. -- ecoffey
-	 */
-	if (plugin->info->id == NULL || *plugin->info->id == '\0')
-	{
-		plugin->error = g_strdup(_("This plugin has not defined an ID."));
-		purple_debug_error("plugins", "%s is not loadable: info->id is not defined.\n", plugin->path);
-		plugin->unloadable = TRUE;
-		return plugin;
-	}
-
-	/* Really old plugins. */
-	if (plugin->info->magic != PURPLE_PLUGIN_MAGIC)
-	{
-		if (plugin->info->magic >= 2 && plugin->info->magic <= 4)
-		{
-			struct _PurplePluginInfo2
-			{
-				unsigned int api_version;
-				PurplePluginType type;
-				char *ui_requirement;
-				unsigned long flags;
-				GList *dependencies;
-				PurplePluginPriority priority;
-
-				char *id;
-				char *name;
-				char *version;
-				char *summary;
-				char *description;
-				char *author;
-				char *homepage;
-
-				gboolean (*load)(PurplePlugin *plugin);
-				gboolean (*unload)(PurplePlugin *plugin);
-				void (*destroy)(PurplePlugin *plugin);
-
-				void *ui_info;
-				void *extra_info;
-				PurplePluginUiInfo *prefs_info;
-				GList *(*actions)(PurplePlugin *plugin, gpointer context);
-			} *info2 = (struct _PurplePluginInfo2 *)plugin->info;
-
-			/* This leaks... but only for ancient plugins, so deal with it. */
-			plugin->info = g_new0(PurplePluginInfo, 1);
-
-			/* We don't really need all these to display the plugin info, but
-			 * I'm copying them all for good measure. */
-			plugin->info->magic          = info2->api_version;
-			plugin->info->type           = info2->type;
-			plugin->info->ui_requirement = info2->ui_requirement;
-			plugin->info->flags          = info2->flags;
-			plugin->info->dependencies   = info2->dependencies;
-			plugin->info->id             = info2->id;
-			plugin->info->name           = info2->name;
-			plugin->info->version        = info2->version;
-			plugin->info->summary        = info2->summary;
-			plugin->info->description    = info2->description;
-			plugin->info->author         = info2->author;
-			plugin->info->homepage       = info2->homepage;
-			plugin->info->load           = info2->load;
-			plugin->info->unload         = info2->unload;
-			plugin->info->destroy        = info2->destroy;
-			plugin->info->ui_info        = info2->ui_info;
-			plugin->info->extra_info     = info2->extra_info;
-
-			if (info2->api_version >= 3)
-				plugin->info->prefs_info = info2->prefs_info;
-
-			if (info2->api_version >= 4)
-				plugin->info->actions    = info2->actions;
-
-
-			plugin->error = g_strdup_printf(_("Plugin magic mismatch %d (need %d)"),
-							 plugin->info->magic, PURPLE_PLUGIN_MAGIC);
-			purple_debug_error("plugins", "%s is not loadable: Plugin magic mismatch %d (need %d)\n",
-					  plugin->path, plugin->info->magic, PURPLE_PLUGIN_MAGIC);
-			plugin->unloadable = TRUE;
-			return plugin;
-		}
-
-		purple_debug_error("plugins", "%s is not loadable: Plugin magic mismatch %d (need %d)\n",
-				 plugin->path, plugin->info->magic, PURPLE_PLUGIN_MAGIC);
-		purple_plugin_destroy(plugin);
-		return NULL;
-	}
-
-	if (plugin->info->major_version != PURPLE_MAJOR_VERSION ||
-			plugin->info->minor_version > PURPLE_MINOR_VERSION)
-	{
-		plugin->error = g_strdup_printf(_("ABI version mismatch %d.%d.x (need %d.%d.x)"),
-						 plugin->info->major_version, plugin->info->minor_version,
-						 PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION);
-		purple_debug_error("plugins", "%s is not loadable: ABI version mismatch %d.%d.x (need %d.%d.x)\n",
-				 plugin->path, plugin->info->major_version, plugin->info->minor_version,
-				 PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION);
-		plugin->unloadable = TRUE;
-		return plugin;
-	}
-
-	if (plugin->info->type == PURPLE_PLUGIN_PROTOCOL)
-	{
-		/* If plugin is a PRPL, make sure it implements the required functions */
-		if ((PURPLE_PLUGIN_PROTOCOL_INFO(plugin)->list_icon == NULL) ||
-		    (PURPLE_PLUGIN_PROTOCOL_INFO(plugin)->login == NULL) ||
-		    (PURPLE_PLUGIN_PROTOCOL_INFO(plugin)->close == NULL))
-		{
-			plugin->error = g_strdup(_("Plugin does not implement all required functions (list_icon, login and close)"));
-			purple_debug_error("plugins", "%s is not loadable: %s\n",
-					 plugin->path, plugin->error);
-			plugin->unloadable = TRUE;
-			return plugin;
-		}
-
-		/* For debugging, let's warn about prpl prefs. */
-		if (plugin->info->prefs_info != NULL)
-		{
-			purple_debug_error("plugins", "%s has a prefs_info, but is a prpl. This is no longer supported.\n",
-			                 plugin->path);
-		}
-	}
-
-	return plugin;
-#else
-	return NULL;
-#endif /* !PURPLE_PLUGINS */
-}
-
-#ifdef PURPLE_PLUGINS
-static gint
-compare_plugins(gconstpointer a, gconstpointer b)
-{
-	const PurplePlugin *plugina = a;
-	const PurplePlugin *pluginb = b;
-
-	return strcmp(plugina->info->name, pluginb->info->name);
-}
-#endif /* PURPLE_PLUGINS */
-
-gboolean
-purple_plugin_load(PurplePlugin *plugin)
-{
-#ifdef PURPLE_PLUGINS
-	GList *dep_list = NULL;
-	GList *l;
-
-	g_return_val_if_fail(plugin != NULL, FALSE);
-
-	if (purple_plugin_is_loaded(plugin))
-		return TRUE;
-
-	if (purple_plugin_is_unloadable(plugin))
-		return FALSE;
-
-	g_return_val_if_fail(plugin->error == NULL, FALSE);
-
-	/*
-	 * Go through the list of the plugin's dependencies.
-	 *
-	 * First pass: Make sure all the plugins needed are probed.
-	 */
-	for (l = plugin->info->dependencies; l != NULL; l = l->next)
-	{
-		const char *dep_name = (const char *)l->data;
-		PurplePlugin *dep_plugin;
-
-		dep_plugin = purple_plugins_find_with_id(dep_name);
-
-		if (dep_plugin == NULL)
-		{
-			char *tmp;
-
-			tmp = g_strdup_printf(_("The required plugin %s was not found. "
-			                        "Please install this plugin and try again."),
-			                      dep_name);
-
-			purple_notify_error(NULL, NULL,
-			                  _("Unable to load the plugin"), tmp);
-			g_free(tmp);
-
-			g_list_free(dep_list);
-
-			return FALSE;
-		}
-
-		dep_list = g_list_append(dep_list, dep_plugin);
-	}
-
-	/* Second pass: load all the required plugins. */
-	for (l = dep_list; l != NULL; l = l->next)
-	{
-		PurplePlugin *dep_plugin = (PurplePlugin *)l->data;
-
-		if (!purple_plugin_is_loaded(dep_plugin))
-		{
-			if (!purple_plugin_load(dep_plugin))
-			{
-				char *tmp;
-
-				tmp = g_strdup_printf(_("The required plugin %s was unable to load."),
-				                      plugin->info->name);
-
-				purple_notify_error(NULL, NULL,
-				                 _("Unable to load your plugin."), tmp);
-				g_free(tmp);
-
-				g_list_free(dep_list);
-
-				return FALSE;
-			}
-		}
-	}
-
-	/* Third pass: note that other plugins are dependencies of this plugin.
-	 * This is done separately in case we had to bail out earlier. */
-	for (l = dep_list; l != NULL; l = l->next)
-	{
-		PurplePlugin *dep_plugin = (PurplePlugin *)l->data;
-		dep_plugin->dependent_plugins = g_list_prepend(dep_plugin->dependent_plugins, (gpointer)plugin->info->id);
-	}
-
-	g_list_free(dep_list);
-
-	if (plugin->native_plugin)
-	{
-		if (plugin->info->load != NULL && !plugin->info->load(plugin))
-			return FALSE;
-	}
-	else {
-		PurplePlugin *loader;
-		PurplePluginLoaderInfo *loader_info;
-
-		loader = find_loader_for_plugin(plugin);
-
-		if (loader == NULL)
-			return FALSE;
-
-		loader_info = PURPLE_PLUGIN_LOADER_INFO(loader);
-
-		if (loader_info->load != NULL)
-		{
-			if (!loader_info->load(plugin))
-				return FALSE;
-		}
-	}
-
-	loaded_plugins = g_list_insert_sorted(loaded_plugins, plugin, compare_plugins);
-
-	plugin->loaded = TRUE;
-
-	purple_signal_emit(purple_plugins_get_handle(), "plugin-load", plugin);
-
-	return TRUE;
+	PurplePlugin *plugin = PURPLE_PLUGIN(obj);
 
-#else
-	return TRUE;
-#endif /* !PURPLE_PLUGINS */
-}
-
-gboolean
-purple_plugin_unload(PurplePlugin *plugin)
-{
-#ifdef PURPLE_PLUGINS
-	GList *l;
-	GList *ll;
-
-	g_return_val_if_fail(plugin != NULL, FALSE);
-	g_return_val_if_fail(purple_plugin_is_loaded(plugin), FALSE);
-
-	purple_debug_info("plugins", "Unloading plugin %s\n", plugin->info->name);
-
-	/* Unload all plugins that depend on this plugin. */
-	for (l = plugin->dependent_plugins; l != NULL; l = ll) {
-		const char * dep_name = (const char *)l->data;
-		PurplePlugin *dep_plugin;
-
-		/* Store a pointer to the next element in the list.
-		 * This is because we'll be modifying this list in the loop. */
-		ll = l->next;
-
-		dep_plugin = purple_plugins_find_with_id(dep_name);
-
-		if (dep_plugin != NULL && purple_plugin_is_loaded(dep_plugin))
-		{
-			if (!purple_plugin_unload(dep_plugin))
-			{
-				g_free(plugin->error);
-				plugin->error = g_strdup_printf(_("%s requires %s, but it failed to unload."),
-				                                _(plugin->info->name),
-				                                _(dep_plugin->info->name));
-				return FALSE;
-			}
-			else
-			{
-#if 0
-				/* This isn't necessary. This has already been done when unloading dep_plugin. */
-				plugin->dependent_plugins = g_list_delete_link(plugin->dependent_plugins, l);
-#endif
-			}
-		}
-	}
-
-	/* Remove this plugin from each dependency's dependent_plugins list. */
-	for (l = plugin->info->dependencies; l != NULL; l = l->next)
-	{
-		const char *dep_name = (const char *)l->data;
-		PurplePlugin *dependency;
-
-		dependency = purple_plugins_find_with_id(dep_name);
-
-		if (dependency != NULL)
-			dependency->dependent_plugins = g_list_remove(dependency->dependent_plugins, plugin->info->id);
-		else
-			purple_debug_error("plugins", "Unable to remove from dependency list for %s\n", dep_name);
-	}
-
-	if (plugin->native_plugin) {
-		if (plugin->info->unload && !plugin->info->unload(plugin))
-			return FALSE;
-
-		if (plugin->info->type == PURPLE_PLUGIN_PROTOCOL) {
-			PurplePluginProtocolInfo *prpl_info;
-			GList *l;
-
-			prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
-
-			for (l = prpl_info->user_splits; l != NULL; l = l->next)
-				purple_account_user_split_destroy(l->data);
-
-			for (l = prpl_info->protocol_options; l != NULL; l = l->next)
-				purple_account_option_destroy(l->data);
-
-			if (prpl_info->user_splits != NULL) {
-				g_list_free(prpl_info->user_splits);
-				prpl_info->user_splits = NULL;
-			}
-
-			if (prpl_info->protocol_options != NULL) {
-				g_list_free(prpl_info->protocol_options);
-				prpl_info->protocol_options = NULL;
-			}
-		}
-	} else {
-		PurplePlugin *loader;
-		PurplePluginLoaderInfo *loader_info;
-
-		loader = find_loader_for_plugin(plugin);
-
-		if (loader == NULL)
-			return FALSE;
-
-		loader_info = PURPLE_PLUGIN_LOADER_INFO(loader);
-
-		if (loader_info->unload && !loader_info->unload(plugin))
-			return FALSE;
-	}
-
-	/* cancel any pending dialogs the plugin has */
-	purple_request_close_with_handle(plugin);
-	purple_notify_close_with_handle(plugin);
-
-	purple_signals_disconnect_by_handle(plugin);
-	purple_plugin_ipc_unregister_all(plugin);
-
-	loaded_plugins = g_list_remove(loaded_plugins, plugin);
-	if ((plugin->info != NULL) && PURPLE_IS_PROTOCOL_PLUGIN(plugin))
-		protocol_plugins = g_list_remove(protocol_plugins, plugin);
-	plugins_to_disable = g_list_remove(plugins_to_disable, plugin);
-	plugin->loaded = FALSE;
-
-	/* We wouldn't be anywhere near here if the plugin wasn't loaded, so
-	 * if plugin->error is set at all, it had to be from a previous
-	 * unload failure.  It's obviously okay now.
-	 */
-	g_free(plugin->error);
-	plugin->error = NULL;
-
-	purple_signal_emit(purple_plugins_get_handle(), "plugin-unload", plugin);
-
-	purple_prefs_disconnect_by_handle(plugin);
-
-	return TRUE;
-#else
-	return TRUE;
-#endif /* PURPLE_PLUGINS */
-}
-
-void
-purple_plugin_disable(PurplePlugin *plugin)
-{
-#ifdef PURPLE_PLUGINS
-	g_return_if_fail(plugin != NULL);
-
-	if (!g_list_find(plugins_to_disable, plugin))
-		plugins_to_disable = g_list_prepend(plugins_to_disable, plugin);
-#endif
-}
-
-gboolean
-purple_plugin_reload(PurplePlugin *plugin)
-{
-#ifdef PURPLE_PLUGINS
-	g_return_val_if_fail(plugin != NULL, FALSE);
-	g_return_val_if_fail(purple_plugin_is_loaded(plugin), FALSE);
-
-	if (!purple_plugin_unload(plugin))
-		return FALSE;
-
-	if (!purple_plugin_load(plugin))
-		return FALSE;
-
-	return TRUE;
-#else
-	return TRUE;
-#endif /* !PURPLE_PLUGINS */
-}
-
-void
-purple_plugin_destroy(PurplePlugin *plugin)
-{
-#ifdef PURPLE_PLUGINS
-	g_return_if_fail(plugin != NULL);
-
-	if (purple_plugin_is_loaded(plugin))
-		purple_plugin_unload(plugin);
-
-	plugins = g_list_remove(plugins, plugin);
-
-	if (load_queue != NULL)
-		load_queue = g_list_remove(load_queue, plugin);
-
-	/* true, this may leak a little memory if there is a major version
-	 * mismatch, but it's a lot better than trying to free something
-	 * we shouldn't, and crashing while trying to load an old plugin */
-	if(plugin->info == NULL || plugin->info->magic != PURPLE_PLUGIN_MAGIC ||
-			plugin->info->major_version != PURPLE_MAJOR_VERSION)
-	{
-		if(plugin->handle)
-			g_module_close(plugin->handle);
-
-		g_free(plugin->path);
-		g_free(plugin->error);
-
-		PURPLE_DBUS_UNREGISTER_POINTER(plugin);
-
-		g_free(plugin);
-		return;
-	}
-
-	if (plugin->info != NULL)
-		g_list_free(plugin->info->dependencies);
-
-	if (plugin->native_plugin)
-	{
-		if (plugin->info != NULL && plugin->info->type == PURPLE_PLUGIN_LOADER)
-		{
-			PurplePluginLoaderInfo *loader_info;
-			GList *exts, *l, *next_l;
-			PurplePlugin *p2;
-
-			loader_info = PURPLE_PLUGIN_LOADER_INFO(plugin);
-
-			if (loader_info != NULL && loader_info->exts != NULL)
-			{
-				for (exts = PURPLE_PLUGIN_LOADER_INFO(plugin)->exts;
-					 exts != NULL;
-					 exts = exts->next) {
-
-					for (l = purple_plugins_get_all(); l != NULL; l = next_l)
-					{
-						next_l = l->next;
-
-						p2 = l->data;
-
-						if (p2->path != NULL &&
-							has_file_extension(p2->path, exts->data))
-						{
-							purple_plugin_destroy(p2);
-						}
-					}
-				}
-
-				g_list_free(loader_info->exts);
-				loader_info->exts = NULL;
-			}
-
-			plugin_loaders = g_list_remove(plugin_loaders, plugin);
-		}
-
-		if (plugin->info != NULL && plugin->info->destroy != NULL)
-			plugin->info->destroy(plugin);
-
-		/*
-		 * I find it extremely useful to do this when using valgrind, as
-		 * it keeps all the plugins open, meaning that valgrind is able to
-		 * resolve symbol names in leak traces from plugins.
-		 */
-		if (!g_getenv("PURPLE_LEAKCHECK_HELP") && !RUNNING_ON_VALGRIND)
-		{
-			if (plugin->handle != NULL)
-				g_module_close(plugin->handle);
-		}
-	}
-	else
-	{
-		PurplePlugin *loader;
-		PurplePluginLoaderInfo *loader_info;
-
-		loader = find_loader_for_plugin(plugin);
-
-		if (loader != NULL)
-		{
-			loader_info = PURPLE_PLUGIN_LOADER_INFO(loader);
-
-			if (loader_info->destroy != NULL)
-				loader_info->destroy(plugin);
-		}
-	}
-
-	g_free(plugin->path);
-	g_free(plugin->error);
-
-	PURPLE_DBUS_UNREGISTER_POINTER(plugin);
-
-	g_free(plugin);
-#endif /* !PURPLE_PLUGINS */
-}
-
-gboolean
-purple_plugin_is_loaded(const PurplePlugin *plugin)
-{
-	g_return_val_if_fail(plugin != NULL, FALSE);
-
-	return plugin->loaded;
-}
-
-gboolean
-purple_plugin_is_unloadable(const PurplePlugin *plugin)
-{
-	g_return_val_if_fail(plugin != NULL, FALSE);
-
-	return plugin->unloadable;
-}
-
-const gchar *
-purple_plugin_get_id(const PurplePlugin *plugin) {
-	g_return_val_if_fail(plugin, NULL);
-	g_return_val_if_fail(plugin->info, NULL);
-
-	return plugin->info->id;
-}
-
-const gchar *
-purple_plugin_get_name(const PurplePlugin *plugin) {
-	g_return_val_if_fail(plugin, NULL);
-	g_return_val_if_fail(plugin->info, NULL);
-
-	return _(plugin->info->name);
-}
-
-const gchar *
-purple_plugin_get_version(const PurplePlugin *plugin) {
-	g_return_val_if_fail(plugin, NULL);
-	g_return_val_if_fail(plugin->info, NULL);
-
-	return plugin->info->version;
-}
-
-const gchar *
-purple_plugin_get_summary(const PurplePlugin *plugin) {
-	g_return_val_if_fail(plugin, NULL);
-	g_return_val_if_fail(plugin->info, NULL);
-
-	return _(plugin->info->summary);
-}
-
-const gchar *
-purple_plugin_get_description(const PurplePlugin *plugin) {
-	g_return_val_if_fail(plugin, NULL);
-	g_return_val_if_fail(plugin->info, NULL);
-
-	return _(plugin->info->description);
-}
-
-const gchar *
-purple_plugin_get_author(const PurplePlugin *plugin) {
-	g_return_val_if_fail(plugin, NULL);
-	g_return_val_if_fail(plugin->info, NULL);
-
-	return _(plugin->info->author);
-}
-
-const gchar *
-purple_plugin_get_homepage(const PurplePlugin *plugin) {
-	g_return_val_if_fail(plugin, NULL);
-	g_return_val_if_fail(plugin->info, NULL);
-
-	return plugin->info->homepage;
-}
-
-/**************************************************************************
- * Plugin IPC
- **************************************************************************/
-static void
-destroy_ipc_info(void *data)
-{
-	PurplePluginIpcCommand *ipc_command = (PurplePluginIpcCommand *)data;
-
-	g_free(ipc_command->param_types);
-	g_free(ipc_command);
-}
-
-gboolean
-purple_plugin_ipc_register(PurplePlugin *plugin, const char *command,
-						 PurpleCallback func, PurpleSignalMarshalFunc marshal,
-						 GType ret_type, int num_params, ...)
-{
-	PurplePluginIpcInfo *ipc_info;
-	PurplePluginIpcCommand *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(PurplePluginIpcInfo, 1);
-		ipc_info->commands = g_hash_table_new_full(g_str_hash, g_str_equal,
-												   g_free, destroy_ipc_info);
-	}
-	else
-		ipc_info = (PurplePluginIpcInfo *)plugin->ipc_data;
-
-	ipc_command = g_new0(PurplePluginIpcCommand, 1);
-	ipc_command->func       = func;
-	ipc_command->marshal    = marshal;
-	ipc_command->num_params = num_params;
-	ipc_command->ret_type   = ret_type;
-
-	if (num_params > 0)
-	{
-		va_list args;
-		int i;
-
-		ipc_command->param_types = g_new0(GType, num_params);
-
-		va_start(args, num_params);
-
-		for (i = 0; i < num_params; i++)
-			ipc_command->param_types[i] = va_arg(args, GType);
-
-		va_end(args);
-	}
-
-	g_hash_table_replace(ipc_info->commands, g_strdup(command), ipc_command);
-
-	ipc_info->command_count++;
-
-	return TRUE;
-}
-
-void
-purple_plugin_ipc_unregister(PurplePlugin *plugin, const char *command)
-{
-	PurplePluginIpcInfo *ipc_info;
-
-	g_return_if_fail(plugin  != NULL);
-	g_return_if_fail(command != NULL);
-
-	ipc_info = (PurplePluginIpcInfo *)plugin->ipc_data;
-
-	if (ipc_info == NULL ||
-		g_hash_table_lookup(ipc_info->commands, command) == NULL)
-	{
-		purple_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;
+	switch (param_id) {
+		case PROP_UNLOADABLE:
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
 	}
 }
 
-void
-purple_plugin_ipc_unregister_all(PurplePlugin *plugin)
-{
-	PurplePluginIpcInfo *ipc_info;
-
-	g_return_if_fail(plugin != NULL);
-
-	if (plugin->ipc_data == NULL)
-		return; /* Silently ignore it. */
-
-	ipc_info = (PurplePluginIpcInfo *)plugin->ipc_data;
-
-	g_hash_table_destroy(ipc_info->commands);
-	g_free(ipc_info);
-
-	plugin->ipc_data = NULL;
-}
-
-gboolean
-purple_plugin_ipc_get_types(PurplePlugin *plugin, const char *command,
-						   GType *ret_type, int *num_params,
-						   GType **param_types)
+/* GObject initialization function */
+static void
+purple_plugin_init(GTypeInstance *instance, gpointer klass)
 {
-	PurplePluginIpcInfo *ipc_info;
-	PurplePluginIpcCommand *ipc_command;
-
-	g_return_val_if_fail(plugin  != NULL, FALSE);
-	g_return_val_if_fail(command != NULL, FALSE);
-
-	ipc_info = (PurplePluginIpcInfo *)plugin->ipc_data;
-
-	if (ipc_info == NULL ||
-		(ipc_command = g_hash_table_lookup(ipc_info->commands,
-										   command)) == NULL)
-	{
-		purple_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 (param_types != NULL)
-		*param_types = ipc_command->param_types;
-
-	if (ret_type != NULL)
-		*ret_type = ipc_command->ret_type;
-
-	return TRUE;
-}
-
-void *
-purple_plugin_ipc_call(PurplePlugin *plugin, const char *command,
-					 gboolean *ok, ...)
-{
-	PurplePluginIpcInfo *ipc_info;
-	PurplePluginIpcCommand *ipc_command;
-	va_list args;
-	void *ret_value;
+	PurplePluginPrivate *priv = PURPLE_PLUGIN_GET_PRIVATE(instance);
 
-	if (ok != NULL)
-		*ok = FALSE;
-
-	g_return_val_if_fail(plugin  != NULL, NULL);
-	g_return_val_if_fail(command != NULL, NULL);
-
-	ipc_info = (PurplePluginIpcInfo *)plugin->ipc_data;
-
-	if (ipc_info == NULL ||
-		(ipc_command = g_hash_table_lookup(ipc_info->commands,
-										   command)) == NULL)
-	{
-		purple_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 *
-purple_plugins_get_handle(void) {
-	static int handle;
-
-	return &handle;
-}
-
-void
-purple_plugins_init(void) {
-	void *handle = purple_plugins_get_handle();
-
-	purple_plugins_add_search_path(LIBDIR);
-
-	purple_signal_register(handle, "plugin-load",
-						 purple_marshal_VOID__POINTER,
-						 G_TYPE_NONE, 1, PURPLE_TYPE_PLUGIN);
-	purple_signal_register(handle, "plugin-unload",
-						 purple_marshal_VOID__POINTER,
-						 G_TYPE_NONE, 1, PURPLE_TYPE_PLUGIN);
-}
-
-void
-purple_plugins_uninit(void)
-{
-	void *handle = purple_plugins_get_handle();
-
-	purple_signals_disconnect_by_handle(handle);
-	purple_signals_unregister_by_instance(handle);
-
-	while (search_paths) {
-		g_free(search_paths->data);
-		search_paths = g_list_delete_link(search_paths, search_paths);
-	}
+	priv->unloadable = TRUE;
 }
 
-/**************************************************************************
- * Plugins API
- **************************************************************************/
-void
-purple_plugins_add_search_path(const char *path)
-{
-	g_return_if_fail(path != NULL);
-
-	if (g_list_find_custom(search_paths, path, (GCompareFunc)strcmp))
-		return;
-
-	search_paths = g_list_append(search_paths, g_strdup(path));
-}
-
-GList *
-purple_plugins_get_search_paths()
-{
-	return search_paths;
-}
-
-void
-purple_plugins_unload_all(void)
-{
-#ifdef PURPLE_PLUGINS
-
-	while (loaded_plugins != NULL)
-		purple_plugin_unload(loaded_plugins->data);
-
-#endif /* PURPLE_PLUGINS */
-}
-
-void
-purple_plugins_unload(PurplePluginType type)
-{
-#ifdef PURPLE_PLUGINS
-	GList *l;
-
-	for (l = plugins; l; l = l->next) {
-		PurplePlugin *plugin = l->data;
-		if (plugin->info->type == type && purple_plugin_is_loaded(plugin))
-			purple_plugin_unload(plugin);
-	}
-
-#endif /* PURPLE_PLUGINS */
-}
-
-void
-purple_plugins_destroy_all(void)
-{
-#ifdef PURPLE_PLUGINS
-
-	while (plugins != NULL)
-		purple_plugin_destroy(plugins->data);
-
-#endif /* PURPLE_PLUGINS */
-}
-
-void
-purple_plugins_save_loaded(const char *key)
+/* GObject dispose function */
+static void
+purple_plugin_dispose(GObject *object)
 {
-#ifdef PURPLE_PLUGINS
-	GList *pl;
-	GList *files = NULL;
-
-	for (pl = purple_plugins_get_loaded(); pl != NULL; pl = pl->next) {
-		PurplePlugin *plugin = pl->data;
-
-		if (plugin->info->type != PURPLE_PLUGIN_PROTOCOL &&
-		    plugin->info->type != PURPLE_PLUGIN_LOADER &&
-		    !g_list_find(plugins_to_disable, plugin)) {
-			files = g_list_append(files, plugin->path);
-		}
-	}
-
-	purple_prefs_set_path_list(key, files);
-	g_list_free(files);
-#endif
-}
-
-void
-purple_plugins_load_saved(const char *key)
-{
-#ifdef PURPLE_PLUGINS
-	GList *f, *files;
-
-	g_return_if_fail(key != NULL);
-
-	files = purple_prefs_get_path_list(key);
-
-	for (f = files; f; f = f->next)
-	{
-		char *filename;
-		char *basename;
-		PurplePlugin *plugin;
-
-		if (f->data == NULL)
-			continue;
-
-		filename = f->data;
-
-		/*
-		 * We don't know if the filename uses Windows or Unix path
-		 * separators (because people might be sharing a prefs.xml
-		 * file across systems), so we find the last occurrence
-		 * of either.
-		 */
-		basename = strrchr(filename, '/');
-		if ((basename == NULL) || (basename < strrchr(filename, '\\')))
-			basename = strrchr(filename, '\\');
-		if (basename != NULL)
-			basename++;
-
-		/* Strip the extension */
-		if (basename)
-			basename = purple_plugin_get_basename(basename);
-
-		if (((plugin = purple_plugins_find_with_filename(filename)) != NULL) ||
-				(basename && (plugin = purple_plugins_find_with_basename(basename)) != NULL) ||
-				((plugin = purple_plugin_probe(filename)) != NULL))
-		{
-			purple_debug_info("plugins", "Loading saved plugin %s\n",
-							plugin->path);
-			purple_plugin_load(plugin);
-		}
-		else
-		{
-			purple_debug_error("plugins", "Unable to find saved plugin %s\n",
-							 filename);
-		}
-
-		g_free(basename);
-
-		g_free(f->data);
-	}
-
-	g_list_free(files);
-#endif /* PURPLE_PLUGINS */
+	G_OBJECT_CLASS(parent_class)->dispose(object);
 }
 
-
-void
-purple_plugins_probe(const char *ext)
+/* GObject finalize function */
+static void
+purple_plugin_finalize(GObject *object)
 {
-#ifdef PURPLE_PLUGINS
-	GDir *dir;
-	const gchar *file;
-	gchar *path;
-	PurplePlugin *plugin;
-	GList *cur;
-	const char *search_path;
-
-	if (!g_module_supported())
-		return;
-
-	/* Probe plugins */
-	for (cur = search_paths; cur != NULL; cur = cur->next)
-	{
-		search_path = cur->data;
-
-		dir = g_dir_open(search_path, 0, NULL);
-
-		if (dir != NULL)
-		{
-			while ((file = g_dir_read_name(dir)) != NULL)
-			{
-				path = g_build_filename(search_path, file, NULL);
-
-				if (ext == NULL || has_file_extension(file, ext))
-					purple_plugin_probe(path);
-
-				g_free(path);
-			}
-
-			g_dir_close(dir);
-		}
-	}
-
-	/* See if we have any plugins waiting to load */
-	while (load_queue != NULL)
-	{
-		plugin = (PurplePlugin *)load_queue->data;
-
-		load_queue = g_list_remove(load_queue, plugin);
-
-		if (plugin == NULL || plugin->info == NULL)
-			continue;
-
-		if (plugin->info->type == PURPLE_PLUGIN_LOADER)
-		{
-			/* We'll just load this right now. */
-			if (!purple_plugin_load(plugin))
-			{
-				purple_plugin_destroy(plugin);
-
-				continue;
-			}
-
-			plugin_loaders = g_list_append(plugin_loaders, plugin);
-
-			for (cur = PURPLE_PLUGIN_LOADER_INFO(plugin)->exts;
-				 cur != NULL;
-				 cur = cur->next)
-			{
-				purple_plugins_probe(cur->data);
-			}
-		}
-		else if (plugin->info->type == PURPLE_PLUGIN_PROTOCOL)
-		{
-			/* We'll just load this right now. */
-			if (!purple_plugin_load(plugin))
-			{
-				purple_plugin_destroy(plugin);
-
-				continue;
-			}
-
-			/* Make sure we don't load two PRPLs with the same name? */
-			if (purple_find_prpl(plugin->info->id))
-			{
-				/* Nothing to see here--move along, move along */
-				purple_plugin_destroy(plugin);
-
-				continue;
-			}
-
-			protocol_plugins = g_list_insert_sorted(protocol_plugins, plugin,
-													(GCompareFunc)compare_prpl);
-		}
-	}
-#endif /* PURPLE_PLUGINS */
+	G_OBJECT_CLASS(parent_class)->finalize(object);
 }
 
-gboolean
-purple_plugin_register(PurplePlugin *plugin)
+/* Class initializer function */
+static void purple_plugin_class_init(PurplePluginClass *klass)
 {
-	g_return_val_if_fail(plugin != NULL, FALSE);
-
-	/* If this plugin has been registered already then exit */
-	if (g_list_find(plugins, plugin))
-		return TRUE;
-
-	/* Ensure the plugin has the requisite information */
-	if (plugin->info->type == PURPLE_PLUGIN_LOADER)
-	{
-		PurplePluginLoaderInfo *loader_info;
-
-		loader_info = PURPLE_PLUGIN_LOADER_INFO(plugin);
-
-		if (loader_info == NULL)
-		{
-			purple_debug_error("plugins", "%s is not loadable, loader plugin missing loader_info\n",
-							   plugin->path);
-			return FALSE;
-		}
-	}
-	else if (plugin->info->type == PURPLE_PLUGIN_PROTOCOL)
-	{
-		PurplePluginProtocolInfo *prpl_info;
-
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
-
-		if (prpl_info == NULL)
-		{
-			purple_debug_error("plugins", "%s is not loadable, protocol plugin missing prpl_info\n",
-							   plugin->path);
-			return FALSE;
-		}
-	}
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
 
-#ifdef PURPLE_PLUGINS
-	/* This plugin should be probed and maybe loaded--add it to the queue */
-	load_queue = g_list_append(load_queue, plugin);
-#else
-	if (plugin->info != NULL)
-	{
-		if (plugin->info->type == PURPLE_PLUGIN_PROTOCOL)
-			protocol_plugins = g_list_insert_sorted(protocol_plugins, plugin,
-													(GCompareFunc)compare_prpl);
-		if (plugin->info->load != NULL)
-			if (!plugin->info->load(plugin))
-				return FALSE;
-	}
-#endif
-
-	plugins = g_list_append(plugins, plugin);
-
-	return TRUE;
-}
-
-gboolean
-purple_plugins_enabled(void)
-{
-#ifdef PURPLE_PLUGINS
-	return TRUE;
-#else
-	return FALSE;
-#endif
-}
+	parent_class = g_type_class_peek_parent(klass);
 
-PurplePlugin *
-purple_plugins_find_with_name(const char *name)
-{
-	PurplePlugin *plugin;
-	GList *l;
-
-	for (l = plugins; l != NULL; l = l->next) {
-		plugin = l->data;
-
-		if (purple_strequal(plugin->info->name, name))
-			return plugin;
-	}
-
-	return NULL;
-}
-
-PurplePlugin *
-purple_plugins_find_with_filename(const char *filename)
-{
-	PurplePlugin *plugin;
-	GList *l;
-
-	for (l = plugins; l != NULL; l = l->next) {
-		plugin = l->data;
-
-		if (purple_strequal(plugin->path, filename))
-			return plugin;
-	}
-
-	return NULL;
-}
+	g_type_class_add_private(klass, sizeof(PurplePluginPrivate));
 
-PurplePlugin *
-purple_plugins_find_with_basename(const char *basename)
-{
-#ifdef PURPLE_PLUGINS
-	PurplePlugin *plugin;
-	GList *l;
-	char *tmp;
-
-	g_return_val_if_fail(basename != NULL, NULL);
-
-	for (l = plugins; l != NULL; l = l->next)
-	{
-		plugin = (PurplePlugin *)l->data;
-
-		if (plugin->path != NULL) {
-			tmp = purple_plugin_get_basename(plugin->path);
-			if (purple_strequal(tmp, basename))
-			{
-				g_free(tmp);
-				return plugin;
-			}
-			g_free(tmp);
-		}
-	}
-
-#endif /* PURPLE_PLUGINS */
-
-	return NULL;
-}
-
-PurplePlugin *
-purple_plugins_find_with_id(const char *id)
-{
-	PurplePlugin *plugin;
-	GList *l;
-
-	g_return_val_if_fail(id != NULL, NULL);
-
-	for (l = plugins; l != NULL; l = l->next)
-	{
-		plugin = l->data;
-
-		if (purple_strequal(plugin->info->id, id))
-			return plugin;
-	}
-
-	return NULL;
-}
+	obj_class->dispose = purple_plugin_dispose;
+	obj_class->finalize = purple_plugin_finalize;
 
-GList *
-purple_plugins_get_loaded(void)
-{
-	return loaded_plugins;
-}
-
-GList *
-purple_plugins_get_protocols(void)
-{
-	return protocol_plugins;
-}
-
-GList *
-purple_plugins_get_all(void)
-{
-	return plugins;
-}
-
-
-PurplePluginAction *
-purple_plugin_action_new(const char* label, void (*callback)(PurplePluginAction *))
-{
-	PurplePluginAction *act = g_new0(PurplePluginAction, 1);
+	/* Setup properties */
+	obj_class->get_property = purple_plugin_get_property;
+	obj_class->set_property = purple_plugin_set_property;
 
-	act->label = g_strdup(label);
-	act->callback = callback;
-
-	return act;
-}
-
-void
-purple_plugin_action_free(PurplePluginAction *action)
-{
-	g_return_if_fail(action != NULL);
-
-	g_free(action->label);
-	g_free(action);
-}
-
-static PurplePlugin *
-purple_plugin_copy(PurplePlugin *plugin)
-{
-	PurplePlugin *plugin_copy;
-
-	g_return_val_if_fail(plugin != NULL, NULL);
-
-	plugin_copy = g_new(PurplePlugin, 1);
-	*plugin_copy = *plugin;
-
-	return plugin_copy;
+	g_object_class_install_property(obj_class, PROP_UNLOADABLE,
+			g_param_spec_boolean(PROP_UNLOADABLE_S, _("Unloadable"),
+				_("Whether the plugin can be unloaded or not."), TRUE,
+				G_PARAM_READWRITE)
+			);
 }
 
 GType
@@ -1616,11 +138,18 @@
 {
 	static GType type = 0;
 
-	if (type == 0) {
-		type = g_boxed_type_register_static("PurplePlugin",
-				(GBoxedCopyFunc)purple_plugin_copy,
-				(GBoxedFreeFunc)g_free);
+	if (G_UNLIKELY(type == 0)) {
+		static const GTypeInfo info = {
+			.class_size = sizeof(PurplePluginClass),
+			.class_init = (GClassInitFunc)purple_plugin_class_init,
+			.instance_size = sizeof(PurplePlugin),
+			.instance_init = (GInstanceInitFunc)purple_plugin_init,
+		};
+
+		type = g_type_register_static(GPLUGIN_TYPE_PLUGIN_IMPLEMENTATION,
+		                              "PurplePlugin", &info, 0);
 	}
 
 	return type;
 }
+
--- a/libpurple/plugin.h	Sat Jul 27 16:46:06 2013 +0530
+++ b/libpurple/plugin.h	Sun Jul 28 18:27:54 2013 +0530
@@ -1,9 +1,6 @@
 /**
  * @file plugin.h Plugin API
  * @ingroup core
- * @see @ref plugin-signals
- * @see @ref plugin-ids
- * @see @ref plugin-i18n
  */
 
 /* purple
@@ -29,99 +26,39 @@
 #ifndef _PURPLE_PLUGIN_H_
 #define _PURPLE_PLUGIN_H_
 
-#include <glib.h>
-#include <gmodule.h>
-#include "signals.h"
+#include <gplugin.h>
 
-/** Returns the GType for the PurplePlugin boxed structure */
-#define PURPLE_TYPE_PLUGIN  (purple_plugin_get_type())
+#define PURPLE_TYPE_PLUGIN             (purple_plugin_get_type())
+#define PURPLE_PLUGIN(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_PLUGIN, PurplePlugin))
+#define PURPLE_PLUGIN_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_PLUGIN, PurplePluginClass))
+#define PURPLE_IS_PLUGIN(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_PLUGIN))
+#define PURPLE_IS_PLUGIN_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_PLUGIN))
+#define PURPLE_PLUGIN_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_PLUGIN, PurplePluginClass))
 
 /** @copydoc _PurplePlugin */
-typedef struct _PurplePlugin           PurplePlugin;
-/** @copydoc _PurplePluginInfo */
-typedef struct _PurplePluginInfo       PurplePluginInfo;
-/** @copydoc _PurplePluginUiInfo */
-typedef struct _PurplePluginUiInfo     PurplePluginUiInfo;
-/** @copydoc _PurplePluginLoaderInfo */
-typedef struct _PurplePluginLoaderInfo PurplePluginLoaderInfo;
-
-/** @copydoc _PurplePluginAction */
-typedef struct _PurplePluginAction     PurplePluginAction;
-
-typedef int PurplePluginPriority; /**< Plugin priority. */
-
-#include "pluginpref.h"
-
-/**
- * Plugin types.
- */
-typedef enum
-{
-	PURPLE_PLUGIN_UNKNOWN  = -1,  /**< Unknown type.    */
-	PURPLE_PLUGIN_STANDARD = 0,   /**< Standard plugin. */
-	PURPLE_PLUGIN_LOADER,         /**< Loader plugin.   */
-	PURPLE_PLUGIN_PROTOCOL        /**< Protocol plugin. */
-
-} PurplePluginType;
-
-#define PURPLE_PRIORITY_DEFAULT     0
-#define PURPLE_PRIORITY_HIGHEST  9999
-#define PURPLE_PRIORITY_LOWEST  -9999
-
-#define PURPLE_PLUGIN_FLAG_INVISIBLE 0x01
-
-#define PURPLE_PLUGIN_MAGIC 5 /* once we hit 6.0.0 I think we can remove this */
+typedef struct _PurplePlugin PurplePlugin;
+/** @copydoc _PurplePluginClass */
+typedef struct _PurplePluginClass PurplePluginClass;
 
 /**
- * Detailed information about a plugin.
+ * Represents a plugin that can be loaded/unloaded by libpurple.
  *
- * This is used in the version 2.0 API and up.
+ * #PurplePlugin inherits #GPluginPluginImplementation, which holds the
+ * low-level details about the plugin in a #GPluginPlugin instance.
  */
-struct _PurplePluginInfo
-{
-	unsigned int magic;
-	unsigned int major_version;
-	unsigned int minor_version;
-	PurplePluginType type;
-	char *ui_requirement;
-	unsigned long flags;
-	GList *dependencies;
-	PurplePluginPriority priority;
-
-	const char *id;
-	const char *name;
-	const char *version;
-	const char *summary;
-	const char *description;
-	const char *author;
-	const char *homepage;
+struct _PurplePlugin {
+	/*< private >*/
+	GPluginPluginImplementation parent;
+};
 
-	/**
-	 * If a plugin defines a 'load' function, and it returns FALSE,
-	 * then the plugin will not be loaded.
-	 */
-	gboolean (*load)(PurplePlugin *plugin);
-	gboolean (*unload)(PurplePlugin *plugin);
-	void (*destroy)(PurplePlugin *plugin);
-
-	void *ui_info; /**< Used only by UI-specific plugins to build a preference screen with a custom UI */
-	void *extra_info;
-	PurplePluginUiInfo *prefs_info; /**< Used by any plugin to display preferences.  If #ui_info has been specified, this will be ignored. */
-
-	/**
-	 * This callback has a different use depending on whether this
-	 * plugin type is PURPLE_PLUGIN_STANDARD or PURPLE_PLUGIN_PROTOCOL.
-	 *
-	 * If PURPLE_PLUGIN_STANDARD then the list of actions will show up
-	 * in the Tools menu, under a submenu with the name of the plugin.
-	 * context will be NULL.
-	 *
-	 * If PURPLE_PLUGIN_PROTOCOL then the list of actions will show up
-	 * in the Accounts menu, under a submenu with the name of the
-	 * account.  context will be set to the PurpleConnection for that
-	 * account.  This callback will only be called for online accounts.
-	 */
-	GList *(*actions)(PurplePlugin *plugin, gpointer context);
+/**
+ * PurplePluginClass:
+ *
+ * The base class for all #PurplePlugin's.
+ */
+struct _PurplePluginClass {
+	/*< private >*/
+	GPluginPluginImplementationClass parent_class;
 
 	void (*_purple_reserved1)(void);
 	void (*_purple_reserved2)(void);
@@ -129,118 +66,6 @@
 	void (*_purple_reserved4)(void);
 };
 
-/**
- * Extra information for loader plugins.
- */
-struct _PurplePluginLoaderInfo
-{
-	GList *exts;
-
-	gboolean (*probe)(PurplePlugin *plugin);
-	gboolean (*load)(PurplePlugin *plugin);
-	gboolean (*unload)(PurplePlugin *plugin);
-	void     (*destroy)(PurplePlugin *plugin);
-
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-};
-
-/**
- * A plugin handle.
- */
-struct _PurplePlugin
-{
-	gboolean native_plugin;                /**< Native C plugin.          */
-	gboolean loaded;                       /**< The loaded state.         */
-	void *handle;                          /**< The module handle.        */
-	char *path;                            /**< The path to the plugin.   */
-	PurplePluginInfo *info;                  /**< The plugin information.   */
-	char *error;
-	void *ipc_data;                        /**< IPC data.                 */
-	void *extra;                           /**< Plugin-specific data.     */
-	gboolean unloadable;                   /**< Unloadable                */
-	GList *dependent_plugins;              /**< Plugins depending on this */
-
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-};
-
-#define PURPLE_PLUGIN_LOADER_INFO(plugin) \
-	((PurplePluginLoaderInfo *)(plugin)->info->extra_info)
-
-struct _PurplePluginUiInfo {
-	PurplePluginPrefFrame *(*get_plugin_pref_frame)(PurplePlugin *plugin);
-
-	int page_num;                                         /**< Reserved */
-	PurplePluginPrefFrame *frame;                           /**< Reserved */
-
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-};
-
-#define PURPLE_PLUGIN_HAS_PREF_FRAME(plugin) \
-	((plugin)->info != NULL && (plugin)->info->prefs_info != NULL)
-
-#define PURPLE_PLUGIN_UI_INFO(plugin) \
-	((PurplePluginUiInfo*)(plugin)->info->prefs_info)
-
-
-/**
- * The structure used in the actions member of PurplePluginInfo
- */
-struct _PurplePluginAction {
-	char *label;
-	void (*callback)(PurplePluginAction *);
-
-	/** set to the owning plugin */
-	PurplePlugin *plugin;
-
-	/** NULL for plugin actions menu, set to the PurpleConnection for
-	    account actions menu */
-	gpointer context;
-
-	gpointer user_data;
-};
-
-#define PURPLE_PLUGIN_HAS_ACTIONS(plugin) \
-	((plugin)->info != NULL && (plugin)->info->actions != NULL)
-
-#define PURPLE_PLUGIN_ACTIONS(plugin, context) \
-	(PURPLE_PLUGIN_HAS_ACTIONS(plugin)? \
-	(plugin)->info->actions(plugin, context): NULL)
-
-
-/**
- * Handles the initialization of modules.
- */
-#if !defined(PURPLE_PLUGINS) || defined(PURPLE_STATIC_PRPL)
-# define _FUNC_NAME(x) purple_init_##x##_plugin
-# define PURPLE_INIT_PLUGIN(pluginname, initfunc, plugininfo) \
-	gboolean _FUNC_NAME(pluginname)(void);\
-	gboolean _FUNC_NAME(pluginname)(void) { \
-		PurplePlugin *plugin = purple_plugin_new(TRUE, NULL); \
-		plugin->info = &(plugininfo); \
-		initfunc((plugin)); \
-		purple_plugin_load((plugin)); \
-		return purple_plugin_register(plugin); \
-	}
-#else /* PURPLE_PLUGINS  && !PURPLE_STATIC_PRPL */
-# define PURPLE_INIT_PLUGIN(pluginname, initfunc, plugininfo) \
-	G_MODULE_EXPORT gboolean purple_init_plugin(PurplePlugin *plugin); \
-	G_MODULE_EXPORT gboolean purple_init_plugin(PurplePlugin *plugin) { \
-		plugin->info = &(plugininfo); \
-		initfunc((plugin)); \
-		return purple_plugin_register(plugin); \
-	}
-#endif
-
-
 G_BEGIN_DECLS
 
 /**************************************************************************/
@@ -249,427 +74,12 @@
 /*@{*/
 
 /**
- * Returns the GType for the PurplePlugin boxed structure.
- * TODO Boxing of PurplePlugin is a temporary solution to having a GType for
- *      plugins. This should rather be a GObject instead of a GBoxed.
+ * Returns the GType for the PurplePlugin object.
  */
 GType purple_plugin_get_type(void);
 
-/**
- * Creates a new plugin structure.
- *
- * @param native Whether or not the plugin is native.
- * @param path   The path to the plugin, or @c NULL if statically compiled.
- *
- * @return A new PurplePlugin structure.
- */
-PurplePlugin *purple_plugin_new(gboolean native, const char *path);
-
-/**
- * Probes a plugin, retrieving the information on it and adding it to the
- * list of available plugins.
- *
- * @param filename The plugin's filename.
- *
- * @return The plugin handle.
- *
- * @see purple_plugin_load()
- * @see purple_plugin_destroy()
- */
-PurplePlugin *purple_plugin_probe(const char *filename);
-
-/**
- * Registers a plugin and prepares it for loading.
- *
- * This shouldn't be called by anything but the internal module code.
- * Plugins should use the PURPLE_INIT_PLUGIN() macro to register themselves
- * with the core.
- *
- * @param plugin The plugin to register.
- *
- * @return @c TRUE if the plugin was registered successfully.  Otherwise
- *         @c FALSE is returned (this happens if the plugin does not contain
- *         the necessary information).
- */
-gboolean purple_plugin_register(PurplePlugin *plugin);
-
-/**
- * Attempts to load a previously probed plugin.
- *
- * @param plugin The plugin to load.
- *
- * @return @c TRUE if successful, or @c FALSE otherwise.
- *
- * @see purple_plugin_reload()
- * @see purple_plugin_unload()
- */
-gboolean purple_plugin_load(PurplePlugin *plugin);
-
-/**
- * Unloads the specified plugin.
- *
- * @param plugin The plugin handle.
- *
- * @return @c TRUE if successful, or @c FALSE otherwise.
- *
- * @see purple_plugin_load()
- * @see purple_plugin_reload()
- */
-gboolean purple_plugin_unload(PurplePlugin *plugin);
-
-/**
- * Disable a plugin.
- *
- * This function adds the plugin to a list of plugins to "disable at the next
- * startup" by excluding said plugins from the list of plugins to save.  The
- * UI needs to call purple_plugins_save_loaded() after calling this for it
- * to have any effect.
- */
-void purple_plugin_disable(PurplePlugin *plugin);
-
-/**
- * Reloads a plugin.
- *
- * @param plugin The old plugin handle.
- *
- * @return @c TRUE if successful, or @c FALSE otherwise.
- *
- * @see purple_plugin_load()
- * @see purple_plugin_unload()
- */
-gboolean purple_plugin_reload(PurplePlugin *plugin);
-
-/**
- * Unloads a plugin and destroys the structure from memory.
- *
- * @param plugin The plugin handle.
- */
-void purple_plugin_destroy(PurplePlugin *plugin);
-
-/**
- * Returns whether or not a plugin is currently loaded.
- *
- * @param plugin The plugin.
- *
- * @return @c TRUE if loaded, or @c FALSE otherwise.
- */
-gboolean purple_plugin_is_loaded(const PurplePlugin *plugin);
-
-/**
- * Returns whether or not a plugin is unloadable.
- *
- * If this returns @c TRUE, the plugin is guaranteed to not
- * be loadable. However, a return value of @c FALSE does not
- * guarantee the plugin is loadable.
- *
- * @param plugin The plugin.
- *
- * @return @c TRUE if the plugin is known to be unloadable,\
- *         @c FALSE otherwise
- */
-gboolean purple_plugin_is_unloadable(const PurplePlugin *plugin);
-
-/**
- * Returns a plugin's id.
- *
- * @param plugin The plugin.
- *
- * @return The plugin's id.
- */
-const gchar *purple_plugin_get_id(const PurplePlugin *plugin);
-
-/**
- * Returns a plugin's name.
- *
- * @param plugin The plugin.
- *
- * @return THe name of the plugin, or @c NULL.
- */
-const gchar *purple_plugin_get_name(const PurplePlugin *plugin);
-
-/**
- * Returns a plugin's version.
- *
- * @param plugin The plugin.
- *
- * @return The plugin's version or @c NULL.
- */
-const gchar *purple_plugin_get_version(const PurplePlugin *plugin);
-
-/**
- * Returns a plugin's summary.
- *
- * @param plugin The plugin.
- *
- * @return The plugin's summary.
- */
-const gchar *purple_plugin_get_summary(const PurplePlugin *plugin);
-
-/**
- * Returns a plugin's description.
- *
- * @param plugin The plugin.
- *
- * @return The plugin's description.
- */
-const gchar *purple_plugin_get_description(const PurplePlugin *plugin);
-
-/**
- * Returns a plugin's author.
- *
- * @param plugin The plugin.
- *
- * @return The plugin's author.
- */
-const gchar *purple_plugin_get_author(const PurplePlugin *plugin);
-
-/**
- * Returns a plugin's homepage.
- *
- * @param plugin The plugin.
- *
- * @return The plugin's homepage.
- */
-const gchar *purple_plugin_get_homepage(const PurplePlugin *plugin);
-
 /*@}*/
 
-/**************************************************************************/
-/** @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_type   The return type.
- * @param num_params The number of parameters.
- * @param ...        The parameter types.
- *
- * @return TRUE if the function was registered successfully, or
- *         FALSE otherwise.
- */
-gboolean purple_plugin_ipc_register(PurplePlugin *plugin, const char *command,
-								  PurpleCallback func,
-								  PurpleSignalMarshalFunc marshal,
-								  GType ret_type, 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 purple_plugin_ipc_unregister(PurplePlugin *plugin, const char *command);
-
-/**
- * Unregisters all IPC commands in a plugin.
- *
- * @param plugin The plugin to unregister the commands from.
- */
-void purple_plugin_ipc_unregister_all(PurplePlugin *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_type    The returned return type.
- * @param num_params  The returned number of parameters.
- * @param param_types The returned list of parameter types.
- *
- * @return TRUE if the command was found, or FALSE otherwise.
- */
-gboolean purple_plugin_ipc_get_types(PurplePlugin *plugin, const char *command,
-									GType *ret_type, int *num_params,
-									GType **param_types);
-
-/**
- * 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 *purple_plugin_ipc_call(PurplePlugin *plugin, const char *command,
-						   gboolean *ok, ...);
-
-/*@}*/
-
-/**************************************************************************/
-/** @name Plugins API                                                     */
-/**************************************************************************/
-/*@{*/
-
-/**
- * Add a new directory to search for plugins
- *
- * @param path The new search path.
- */
-void purple_plugins_add_search_path(const char *path);
-
-/**
- * Returns a list of plugin search paths.
- *
- * @constreturn A list of searched paths.
- */
-GList *purple_plugins_get_search_paths(void);
-
-/**
- * Unloads all loaded plugins.
- */
-void purple_plugins_unload_all(void);
-
-/**
- * Unloads all plugins of a specific type.
- */
-void purple_plugins_unload(PurplePluginType type);
-
-/**
- * Destroys all registered plugins.
- */
-void purple_plugins_destroy_all(void);
-
-/**
- * Saves the list of loaded plugins to the specified preference key
- *
- * @param key The preference key to save the list of plugins to.
- */
-void purple_plugins_save_loaded(const char *key);
-
-/**
- * Attempts to load all the plugins in the specified preference key
- * that were loaded when purple last quit.
- *
- * @param key The preference key containing the list of plugins.
- */
-void purple_plugins_load_saved(const char *key);
-
-/**
- * Probes for plugins in the registered module paths.
- *
- * @param ext The extension type to probe for, or @c NULL for all.
- *
- * @see purple_plugin_set_probe_path()
- */
-void purple_plugins_probe(const char *ext);
-
-/**
- * Returns whether or not plugin support is enabled.
- *
- * @return TRUE if plugin support is enabled, or FALSE otherwise.
- */
-gboolean purple_plugins_enabled(void);
-
-/**
- * Finds a plugin with the specified name.
- *
- * @param name The plugin name.
- *
- * @return The plugin if found, or @c NULL if not found.
- */
-PurplePlugin *purple_plugins_find_with_name(const char *name);
-
-/**
- * Finds a plugin with the specified filename (filename with a path).
- *
- * @param filename The plugin filename.
- *
- * @return The plugin if found, or @c NULL if not found.
- */
-PurplePlugin *purple_plugins_find_with_filename(const char *filename);
-
-/**
- * Finds a plugin with the specified basename (filename without a path).
- *
- * @param basename The plugin basename.
- *
- * @return The plugin if found, or @c NULL if not found.
- */
-PurplePlugin *purple_plugins_find_with_basename(const char *basename);
-
-/**
- * Finds a plugin with the specified plugin ID.
- *
- * @param id The plugin ID.
- *
- * @return The plugin if found, or @c NULL if not found.
- */
-PurplePlugin *purple_plugins_find_with_id(const char *id);
-
-/**
- * Returns a list of all loaded plugins.
- *
- * @constreturn A list of all loaded plugins.
- */
-GList *purple_plugins_get_loaded(void);
-
-/**
- * Returns a list of all valid protocol plugins.  A protocol
- * plugin is considered invalid if it does not contain the call
- * to the PURPLE_INIT_PLUGIN() macro, or if it was compiled
- * against an incompatable API version.
- *
- * @constreturn A list of all protocol plugins.
- */
-GList *purple_plugins_get_protocols(void);
-
-/**
- * Returns a list of all plugins, whether loaded or not.
- *
- * @constreturn A list of all plugins.
- */
-GList *purple_plugins_get_all(void);
-
-/*@}*/
-
-/**************************************************************************/
-/** @name Plugins SubSytem API                                            */
-/**************************************************************************/
-/*@{*/
-
-/**
- * Returns the plugin subsystem handle.
- *
- * @return The plugin sybsystem handle.
- */
-void *purple_plugins_get_handle(void);
-
-/**
- * Initializes the plugin subsystem
- */
-void purple_plugins_init(void);
-
-/**
- * Uninitializes the plugin subsystem
- */
-void purple_plugins_uninit(void);
-
-/*@}*/
-
-/**
- * Allocates and returns a new PurplePluginAction.
- *
- * @param label    The description of the action to show to the user.
- * @param callback The callback to call when the user selects this action.
- */
-PurplePluginAction *purple_plugin_action_new(const char* label, void (*callback)(PurplePluginAction *));
-
-/**
- * Frees a PurplePluginAction
- *
- * @param action The PurplePluginAction to free.
- */
-void purple_plugin_action_free(PurplePluginAction *action);
-
 G_END_DECLS
 
 #endif /* _PURPLE_PLUGIN_H_ */

mercurial