changeset 21206:3301b2f813f0

propagate from branch 'im.pidgin.pidgin' (head b7ee9ed3d96546482462baf63c4127858553c275) to branch 'im.pidgin.pidgin.next.minor' (head c196e533236db46190d525411b485194c2d4f03d)
author Richard Laager <rlaager@wiktel.com>
date Wed, 10 Oct 2007 04:04:52 +0000
parents 63ce5e7f453d (current diff) ebbe7b5df08e (diff)
children d604027959a5
files ChangeLog.API
diffstat 11 files changed, 154 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Oct 10 04:04:07 2007 +0000
+++ b/ChangeLog	Wed Oct 10 04:04:52 2007 +0000
@@ -1,5 +1,24 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
+version 2.3.0:
+	http://developer.pidgin.im/query?status=closed&milestone=2.3.0
+
+	libpurple:
+	* We now honor a PURPLE_DISABLE_DEPRECATED define to allow plugins to
+	  catch deprecated functions earlier rather than later.
+
+	Pidgin:
+	* If a plugin says it can't be unloaded, we now display an error and
+	  remove the plugin from the list of saved plugins so it won't load
+	  at the next startup.  Previously, we were ignoring this case, which
+	  could lead to crashes.
+
+	Finch:
+	* If a plugin says it can't be unloaded, we now display an error and
+	  remove the plugin from the list of saved plugins so it won't load
+	  at the next startup.  Previously, we were ignoring this case, which
+	  could lead to crashes.
+
 version 2.2.2:
 	http://developer.pidgin.im/query?status=closed&milestone=2.2.2
 		NOTE: Due to 2.2.1 being a security fix release, some bugs
--- a/ChangeLog.API	Wed Oct 10 04:04:07 2007 +0000
+++ b/ChangeLog.API	Wed Oct 10 04:04:52 2007 +0000
@@ -1,5 +1,21 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
+version 2.3.0 (??/??/????):
+	libpurple:
+		Added:
+		* purple_plugin_disable(), which is intended to be called when
+		  a purple_plugin_unload()--which was called when a user tried
+		  to unload a plugin--fails.  This then prevents the plugin
+		  from being saved in the saved plugins list, so it'll won't
+		  be loaded at the next startup.
+
+		Changed:
+		* purple_plugin_unload() now honors the return value of a
+		  plugin's unload function and can actually return FALSE now.
+		* purple_plugin_unload() no longer does its own notifications
+		  when a dependent plugin fails to unload.  The UI should do
+		  something appropriate.
+
 version 2.2.2 (??/??/????):
 	libpurple:
 		Changed:
--- a/configure.ac	Wed Oct 10 04:04:07 2007 +0000
+++ b/configure.ac	Wed Oct 10 04:04:52 2007 +0000
@@ -45,8 +45,8 @@
 #
 m4_define([purple_lt_current], [2])
 m4_define([purple_major_version], [2])
-m4_define([purple_minor_version], [2])
-m4_define([purple_micro_version], [2])
+m4_define([purple_minor_version], [3])
+m4_define([purple_micro_version], [0])
 m4_define([purple_version_suffix], [])
 m4_define([purple_version],
           [purple_major_version.purple_minor_version.purple_micro_version])
--- a/finch/gntplugin.c	Wed Oct 10 04:04:07 2007 +0000
+++ b/finch/gntplugin.c	Wed Oct 10 04:04:52 2007 +0000
@@ -83,6 +83,7 @@
 
 		if (!purple_plugin_unload(plugin)) {
 			purple_notify_error(NULL, _("ERROR"), _("unloading plugin failed"), NULL);
+			purple_plugin_disable(plugin);
 			gnt_tree_set_choice(GNT_TREE(tree), plugin, TRUE);
 		}
 
--- a/libpurple/blist.h	Wed Oct 10 04:04:07 2007 +0000
+++ b/libpurple/blist.h	Wed Oct 10 04:04:52 2007 +0000
@@ -482,6 +482,7 @@
  */
 PurpleBuddy *purple_contact_get_priority_buddy(PurpleContact *contact);
 
+#ifndef PURPLE_DISABLE_DEPRECATED
 /**
  * Sets the alias for a contact.
  *
@@ -491,6 +492,7 @@
  * @deprecated Use purple_blist_alias_contact() instead.
  */
 void purple_contact_set_alias(PurpleContact *contact, const char *alias);
+#endif
 
 /**
  * Gets the alias for a contact.
--- a/libpurple/notify.h	Wed Oct 10 04:04:07 2007 +0000
+++ b/libpurple/notify.h	Wed Oct 10 04:04:52 2007 +0000
@@ -289,7 +289,7 @@
  */
 void purple_notify_searchresults_row_add(PurpleNotifySearchResults *results,
 									   GList *row);
-
+#ifndef PURPLE_DISABLE_DEPRECATED
 /**
  * Returns a number of the rows in the search results object.
  *
@@ -308,7 +308,9 @@
  * @return Number of the result rows.
  */
 guint purple_notify_searchresults_get_rows_count(PurpleNotifySearchResults *results);
+#endif
 
+#ifndef PURPLE_DISABLE_DEPRECATED
 /**
  * Returns a number of the columns in the search results object.
  *
@@ -327,7 +329,9 @@
  * @return Number of the columns.
  */
 guint purple_notify_searchresults_get_columns_count(PurpleNotifySearchResults *results);
+#endif
 
+#ifndef PURPLE_DISABLE_DEPRECATED
 /**
  * Returns a row of the results from the search results object.
  *
@@ -348,7 +352,9 @@
  */
 GList *purple_notify_searchresults_row_get(PurpleNotifySearchResults *results,
 										 unsigned int row_id);
+#endif
 
+#ifndef PURPLE_DISABLE_DEPRECATED
 /**
  * Returns a title of the search results object's column.
  *
@@ -367,6 +373,7 @@
  */
 char *purple_notify_searchresults_column_get_title(PurpleNotifySearchResults *results,
 												 unsigned int column_id);
+#endif
 
 /*@}*/
 
--- a/libpurple/plugin.c	Wed Oct 10 04:04:07 2007 +0000
+++ b/libpurple/plugin.c	Wed Oct 10 04:04:52 2007 +0000
@@ -58,13 +58,9 @@
 #ifdef PURPLE_PLUGINS
 static GList *load_queue       = NULL;
 static GList *plugin_loaders   = NULL;
+static GList *plugins_to_disable = NULL;
 #endif
 
-/*
- * TODO: I think the intention was to allow multiple load and unload
- *       callback functions.  Perhaps using a GList instead of a
- *       pointer to a single function.
- */
 static void (*probe_cb)(void *) = NULL;
 static void *probe_cb_data = NULL;
 static void (*load_cb)(PurplePlugin *, void *) = NULL;
@@ -254,7 +250,6 @@
 		 * plugins being added to the global name space.
 		 *
 		 * G_MODULE_BIND_LOCAL was added in glib 2.3.3.
-		 * TODO: I guess there's nothing we can do about that?
 		 */
 #if GLIB_CHECK_VERSION(2,3,3)
 		plugin->handle = g_module_open(filename, G_MODULE_BIND_LOCAL);
@@ -625,7 +620,6 @@
 
 	plugin->loaded = TRUE;
 
-	/* TODO */
 	if (load_cb != NULL)
 		load_cb(plugin, load_cb_data);
 
@@ -643,43 +637,37 @@
 {
 #ifdef PURPLE_PLUGINS
 	GList *l;
+	GList *ll;
 
 	g_return_val_if_fail(plugin != NULL, FALSE);
-
-	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);
-
 	g_return_val_if_fail(purple_plugin_is_loaded(plugin), FALSE);
 
 	purple_debug_info("plugins", "Unloading plugin %s\n", plugin->info->name);
 
-	/* cancel any pending dialogs the plugin has */
-	purple_request_close_with_handle(plugin);
-	purple_notify_close_with_handle(plugin);
-
-	plugin->loaded = FALSE;
-
 	/* Unload all plugins that depend on this plugin. */
-	while ((l = plugin->dependent_plugins) != NULL)
-	{
+	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))
 			{
-				char *tmp;
-
-				tmp = g_strdup_printf(_("The dependent plugin %s failed to unload."),
-				                      _(dep_plugin->info->name));
-
-				purple_notify_error(NULL, NULL,
-				                  _("There were errors unloading the plugin."), tmp);
-				g_free(tmp);
+				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
+			{
+				plugin->dependent_plugins = g_list_delete_link(plugin->dependent_plugins, l);
 			}
 		}
 	}
@@ -699,8 +687,8 @@
 	}
 
 	if (plugin->native_plugin) {
-		if (plugin->info->unload != NULL)
-			plugin->info->unload(plugin);
+		if (plugin->info->unload && !plugin->info->unload(plugin))
+			return FALSE;
 
 		if (plugin->info->type == PURPLE_PLUGIN_PROTOCOL) {
 			PurplePluginProtocolInfo *prpl_info;
@@ -724,8 +712,7 @@
 				prpl_info->protocol_options = NULL;
 			}
 		}
-	}
-	else {
+	} else {
 		PurplePlugin *loader;
 		PurplePluginLoaderInfo *loader_info;
 
@@ -736,14 +723,30 @@
 
 		loader_info = PURPLE_PLUGIN_LOADER_INFO(loader);
 
-		if (loader_info->unload != NULL)
-			loader_info->unload(plugin);
+		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);
 
-	/* TODO */
+	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;
+
 	if (unload_cb != NULL)
 		unload_cb(plugin, unload_cb_data);
 
@@ -757,6 +760,15 @@
 #endif /* PURPLE_PLUGINS */
 }
 
+void
+purple_plugin_disable(PurplePlugin *plugin)
+{
+	g_return_if_fail(plugin != NULL);
+
+	if (!g_list_find(plugins_to_disable, plugin))
+		plugins_to_disable = g_list_prepend(plugins_to_disable, plugin);
+}
+
 gboolean
 purple_plugin_reload(PurplePlugin *plugin)
 {
@@ -1222,14 +1234,14 @@
 #ifdef PURPLE_PLUGINS
 	GList *pl;
 	GList *files = NULL;
-	PurplePlugin *p;
 
 	for (pl = purple_plugins_get_loaded(); pl != NULL; pl = pl->next) {
-		p = pl->data;
+		PurplePlugin *plugin = pl->data;
 
-		if (p->info->type != PURPLE_PLUGIN_PROTOCOL &&
-			p->info->type != PURPLE_PLUGIN_LOADER) {
-				files = g_list_append(files, p->path);
+		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);
 		}
 	}
 
@@ -1391,6 +1403,7 @@
 
 	if (probe_cb != NULL)
 		probe_cb(probe_cb_data);
+
 #endif /* PURPLE_PLUGINS */
 }
 
@@ -1464,7 +1477,6 @@
 void
 purple_plugins_register_probe_notify_cb(void (*func)(void *), void *data)
 {
-	/* TODO */
 	probe_cb = func;
 	probe_cb_data = data;
 }
@@ -1472,7 +1484,6 @@
 void
 purple_plugins_unregister_probe_notify_cb(void (*func)(void *))
 {
-	/* TODO */
 	probe_cb = NULL;
 	probe_cb_data = NULL;
 }
@@ -1481,7 +1492,6 @@
 purple_plugins_register_load_notify_cb(void (*func)(PurplePlugin *, void *),
 									 void *data)
 {
-	/* TODO */
 	load_cb = func;
 	load_cb_data = data;
 }
@@ -1489,7 +1499,6 @@
 void
 purple_plugins_unregister_load_notify_cb(void (*func)(PurplePlugin *, void *))
 {
-	/* TODO */
 	load_cb = NULL;
 	load_cb_data = NULL;
 }
@@ -1498,7 +1507,6 @@
 purple_plugins_register_unload_notify_cb(void (*func)(PurplePlugin *, void *),
 									   void *data)
 {
-	/* TODO */
 	unload_cb = func;
 	unload_cb_data = data;
 }
@@ -1506,7 +1514,6 @@
 void
 purple_plugins_unregister_unload_notify_cb(void (*func)(PurplePlugin *, void *))
 {
-	/* TODO */
 	unload_cb = NULL;
 	unload_cb_data = NULL;
 }
--- a/libpurple/plugin.h	Wed Oct 10 04:04:07 2007 +0000
+++ b/libpurple/plugin.h	Wed Oct 10 04:04:52 2007 +0000
@@ -70,11 +70,6 @@
  *
  * This is used in the version 2.0 API and up.
  */
-/* TODO We need to figure out exactly what parts of this are required. The
- * dependent plugin unloading stuff was causing crashes with perl and tcl
- * plugins because they didn't set ids and the dependency code was requiring
- * them. Then we need to actually make sure that plugins have all the right
- * parts before loading them. */
 struct _PurplePluginInfo
 {
 	unsigned int magic;
@@ -296,6 +291,18 @@
 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.
+ *
+ * @since 2.3.0
+ */
+void purple_plugin_disable(PurplePlugin *plugin);
+
+/**
  * Reloads a plugin.
  *
  * @param plugin The old plugin handle.
@@ -525,53 +532,71 @@
  */
 gboolean purple_plugins_enabled(void);
 
+#ifndef PURPLE_DISABLE_DEPRECATED
 /**
  * Registers a function that will be called when probing is finished.
  *
  * @param func The callback function.
  * @param data Data to pass to the callback.
+ * @deprecated If you need this, ask for a plugin-probe signal to be added.
  */
 void purple_plugins_register_probe_notify_cb(void (*func)(void *), void *data);
+#endif
 
+#ifndef PURPLE_DISABLE_DEPRECATED
 /**
  * Unregisters a function that would be called when probing is finished.
  *
  * @param func The callback function.
+ * @deprecated If you need this, ask for a plugin-probe signal to be added.
  */
 void purple_plugins_unregister_probe_notify_cb(void (*func)(void *));
+#endif
 
+#ifndef PURPLE_DISABLE_DEPRECATED
 /**
  * Registers a function that will be called when a plugin is loaded.
  *
  * @param func The callback function.
  * @param data Data to pass to the callback.
+ * @deprecated Use the plugin-load signal instead.
  */
 void purple_plugins_register_load_notify_cb(void (*func)(PurplePlugin *, void *),
 										  void *data);
+#endif
 
+#ifndef PURPLE_DISABLE_DEPRECATED
 /**
  * Unregisters a function that would be called when a plugin is loaded.
  *
  * @param func The callback function.
+ * @deprecated Use the plugin-load signal instead.
  */
 void purple_plugins_unregister_load_notify_cb(void (*func)(PurplePlugin *, void *));
+#endif
 
+#ifndef PURPLE_DISABLE_DEPRECATED
 /**
  * Registers a function that will be called when a plugin is unloaded.
  *
  * @param func The callback function.
  * @param data Data to pass to the callback.
+ * @deprecated Use the plugin-unload signal instead.
  */
 void purple_plugins_register_unload_notify_cb(void (*func)(PurplePlugin *, void *),
 											void *data);
+#endif
 
+#ifndef PURPLE_DISABLE_DEPRECATED
 /**
  * Unregisters a function that would be called when a plugin is unloaded.
  *
  * @param func The callback function.
+ * @deprecated Use the plugin-unload signal instead.
  */
 void purple_plugins_unregister_unload_notify_cb(void (*func)(PurplePlugin *,
 														   void *));
+#endif
 
 /**
  * Finds a plugin with the specified name.
--- a/libpurple/sslconn.h	Wed Oct 10 04:04:07 2007 +0000
+++ b/libpurple/sslconn.h	Wed Oct 10 04:04:52 2007 +0000
@@ -185,6 +185,7 @@
 									PurpleSslErrorFunction error_func,
 									void *data);
 
+#ifndef PURPLE_DISABLE_DEPRECATED
 /**
  * Makes a SSL connection using an already open file descriptor.
  *
@@ -202,6 +203,7 @@
 									   PurpleSslInputFunction func,
 									   PurpleSslErrorFunction error_func,
  									   void *data);
+#endif
 
 /**
   * Makes a SSL connection using an already open file descriptor.
--- a/pidgin/gtknotify.c	Wed Oct 10 04:04:07 2007 +0000
+++ b/pidgin/gtknotify.c	Wed Oct 10 04:04:52 2007 +0000
@@ -270,8 +270,9 @@
 	primary_esc = g_markup_escape_text(primary, -1);
 	secondary_esc = (secondary != NULL) ? g_markup_escape_text(secondary, -1) : NULL;
 	g_snprintf(label_text, sizeof(label_text),
-			   "<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s",
-			   primary_esc, (secondary ? secondary_esc : ""));
+			   "<span weight=\"bold\" size=\"larger\">%s</span>%s%s",
+			   primary_esc, (secondary ? "\n\n" : ""),
+			   (secondary ? secondary_esc : ""));
 	g_free(primary_esc);
 	g_free(secondary_esc);
 
--- a/pidgin/gtkplugin.c	Wed Oct 10 04:04:07 2007 +0000
+++ b/pidgin/gtkplugin.c	Wed Oct 10 04:04:52 2007 +0000
@@ -303,7 +303,24 @@
 	{
 		pidgin_set_cursor(plugin_dialog, GDK_WATCH);
 
-		purple_plugin_unload(plug);
+		if (!purple_plugin_unload(plug))
+		{
+			const char *primary = _("Could not unload plugin");
+			const char *reload = _("The plugin could not be unloaded now, but will be disabled at the next startup.");
+
+			if (!plug->error)
+			{
+				purple_notify_warning(NULL, NULL, primary, reload);
+			}
+			else
+			{
+				char *tmp = g_strdup_printf("%s\n\n%s", reload, plug->error);
+				purple_notify_warning(NULL, NULL, primary, tmp);
+				g_free(tmp);
+			}
+
+			purple_plugin_disable(plug);
+		}
 
 		pidgin_clear_cursor(plugin_dialog);
 	}