Only in libpurple: Makefile.in
diff -ru extract/pidgin-2.10.11/libpurple/account.c libpurple/account.c
--- extract/pidgin-2.10.11/libpurple/account.c	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/account.c	2015-03-20 00:15:22.000000000 -0400
@@ -30,7 +30,6 @@
 #include "debug.h"
 #include "network.h"
 #include "notify.h"
-#include "pounce.h"
 #include "prefs.h"
 #include "privacy.h"
 #include "prpl.h"
@@ -41,6 +40,8 @@
 #include "util.h"
 #include "xmlnode.h"
 
+#define schedule_accounts_save()
+
 typedef struct
 {
 	PurpleConnectionErrorInfo *current_error;
@@ -103,6 +104,7 @@
 static gboolean
 _purple_account_is_password_encrypted(PurpleAccount *account);
 
+#if 0
 /*********************************************************************
  * Writing to disk                                                   *
  *********************************************************************/
@@ -1015,6 +1017,7 @@
 
 	return ret;
 }
+#endif
 
 static void
 load_accounts(void)
@@ -1023,6 +1026,7 @@
 
 	accounts_loaded = TRUE;
 
+#if 0
 	node = purple_util_read_xml_from_file("accounts.xml", _("accounts"));
 
 	if (node == NULL)
@@ -1039,6 +1043,7 @@
 	xmlnode_free(node);
 
 	_purple_buddy_icons_account_loaded_cb();
+#endif
 }
 
 
@@ -1151,8 +1156,10 @@
 
 	purple_presence_destroy(account->presence);
 
+#if 0
 	if(account->system_log)
 		purple_log_free(account->system_log);
+#endif
 
 	while (account->deny) {
 		g_free(account->deny->data);
@@ -1341,8 +1348,13 @@
 
 	gc = purple_account_get_connection(account);
 	_purple_connection_destroy(gc);
+
+	/* 
+	XXXFlo: disable this until the UI for requesting a password
+	        from the user works in Instantbird
 	if (!purple_account_get_remember_password(account))
 		purple_account_set_password(account, NULL);
+	*/
 	purple_account_set_connection(account, NULL);
 
 	account->disconnecting = FALSE;
@@ -2036,6 +2048,7 @@
 purple_account_set_int(PurpleAccount *account, const char *name, int value)
 {
 	PurpleAccountSetting *setting;
+	PurpleAccountUiOps *ui_ops;
 
 	g_return_if_fail(account != NULL);
 	g_return_if_fail(name    != NULL);
@@ -2047,6 +2060,11 @@
 
 	g_hash_table_insert(account->settings, g_strdup(name), setting);
 
+	ui_ops = purple_accounts_get_ui_ops();
+
+	if (ui_ops != NULL && ui_ops->set_int != NULL)
+		ui_ops->set_int(account, name, value);
+
 	schedule_accounts_save();
 }
 
@@ -2055,6 +2073,7 @@
 						const char *value)
 {
 	PurpleAccountSetting *setting;
+	PurpleAccountUiOps *ui_ops;
 
 	g_return_if_fail(account != NULL);
 	g_return_if_fail(name    != NULL);
@@ -2066,6 +2085,11 @@
 
 	g_hash_table_insert(account->settings, g_strdup(name), setting);
 
+	ui_ops = purple_accounts_get_ui_ops();
+
+	if (ui_ops != NULL && ui_ops->set_string != NULL)
+		ui_ops->set_string(account, name, value);
+
 	schedule_accounts_save();
 }
 
@@ -2073,6 +2097,7 @@
 purple_account_set_bool(PurpleAccount *account, const char *name, gboolean value)
 {
 	PurpleAccountSetting *setting;
+	PurpleAccountUiOps *ui_ops;
 
 	g_return_if_fail(account != NULL);
 	g_return_if_fail(name    != NULL);
@@ -2084,6 +2109,11 @@
 
 	g_hash_table_insert(account->settings, g_strdup(name), setting);
 
+	ui_ops = purple_accounts_get_ui_ops();
+
+	if (ui_ops != NULL && ui_ops->set_bool != NULL)
+		ui_ops->set_bool(account, name, value);
+
 	schedule_accounts_save();
 }
 
@@ -2263,7 +2293,7 @@
 
 	p = purple_find_prpl(purple_account_get_protocol_id(account));
 
-	return ((p && p->info->name) ? _(p->info->name) : _("Unknown"));
+	return ((p && p->info->name) ? p->info->name : _("Unknown"));
 }
 
 PurpleConnection *
@@ -2455,6 +2485,7 @@
 						const char *default_value)
 {
 	PurpleAccountSetting *setting;
+	const char *value;
 
 	g_return_val_if_fail(account != NULL, default_value);
 	g_return_val_if_fail(name    != NULL, default_value);
@@ -2466,7 +2497,11 @@
 
 	g_return_val_if_fail(setting->type == PURPLE_PREF_STRING, default_value);
 
-	return setting->value.string;
+	value = setting->value.string;
+	if (value == NULL || !*value)
+		return default_value;
+
+	return value;
 }
 
 gboolean
@@ -2554,6 +2589,7 @@
 	return setting->value.boolean;
 }
 
+#if 0
 PurpleLog *
 purple_account_get_log(PurpleAccount *account, gboolean create)
 {
@@ -2584,6 +2620,7 @@
 		account->system_log = NULL;
 	}
 }
+#endif
 
 void
 purple_account_add_buddy(PurpleAccount *account, PurpleBuddy *buddy)
@@ -3022,9 +3059,6 @@
 			purple_conversation_destroy(conv);
 	}
 
-	/* Remove this account's pounces */
-	purple_pounce_destroy_all_by_account(account);
-
 	/* This will cause the deletion of an old buddy icon. */
 	purple_buddy_icons_set_account_icon(account, NULL, 0);
 
@@ -3207,6 +3241,15 @@
 						 purple_marshal_VOID__POINTER, NULL, 1,
 						 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT));
 
+	purple_signal_register(handle, "account-status-changing",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_STATUS),
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_STATUS));
+
 	purple_signal_register(handle, "account-status-changed",
 						 purple_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
 						 purple_value_new(PURPLE_TYPE_SUBTYPE,
@@ -3292,13 +3335,14 @@
 purple_accounts_uninit(void)
 {
 	gpointer handle = purple_accounts_get_handle();
+#if 0
 	if (save_timer != 0)
 	{
 		purple_timeout_remove(save_timer);
 		save_timer = 0;
 		sync_accounts();
 	}
-
+#endif
 	for (; accounts; accounts = g_list_delete_link(accounts, accounts))
 		purple_account_destroy(accounts->data);
 
diff -ru extract/pidgin-2.10.11/libpurple/account.h libpurple/account.h
--- extract/pidgin-2.10.11/libpurple/account.h	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/account.h	2015-03-19 23:21:15.000000000 -0400
@@ -115,6 +115,10 @@
 	 */
 	void (*close_account_request)(void *ui_handle);
 
+	void (*set_int)(PurpleAccount *account, const char *name, int value);
+	void (*set_string)(PurpleAccount *account, const char *name, const char *value);
+	void (*set_bool)(PurpleAccount *account, const char *name, gboolean value);
+
 	void (*_purple_reserved1)(void);
 	void (*_purple_reserved2)(void);
 	void (*_purple_reserved3)(void);
@@ -944,14 +948,14 @@
  *       if the log has already been closed, which not all loggers deal
  *       with appropriately.
  */
-PurpleLog *purple_account_get_log(PurpleAccount *account, gboolean create);
+/* PurpleLog *purple_account_get_log(PurpleAccount *account, gboolean create); */
 
 /**
  * Frees the system log of an account
  *
  * @param account The account.
  */
-void purple_account_destroy_log(PurpleAccount *account);
+/* void purple_account_destroy_log(PurpleAccount *account); */
 
 /**
  * Adds a buddy to the server-side buddy list for the specified account.
diff -ru extract/pidgin-2.10.11/libpurple/blist.c libpurple/blist.c
--- extract/pidgin-2.10.11/libpurple/blist.c	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/blist.c	2015-03-20 00:15:22.000000000 -0400
@@ -28,7 +28,6 @@
 #include "dbus-maybe.h"
 #include "debug.h"
 #include "notify.h"
-#include "pounce.h"
 #include "prefs.h"
 #include "privacy.h"
 #include "prpl.h"
@@ -126,6 +125,7 @@
 }
 
 
+#if 0
 /*********************************************************************
  * Writing to disk                                                   *
  *********************************************************************/
@@ -601,15 +601,19 @@
 			parse_chat(group, cnode);
 	}
 }
+#endif
 
 /* TODO: Make static and rename to load_blist */
 void
 purple_blist_load()
 {
+#if 0
 	xmlnode *purple, *blist, *privacy;
+#endif
 
 	blist_loaded = TRUE;
 
+#if 0
 	purple = purple_util_read_xml_from_file("blist.xml", _("buddy list"));
 
 	if (purple == NULL)
@@ -671,6 +675,7 @@
 
 	/* This tells the buddy icon code to do its thing. */
 	_purple_buddy_icons_blist_loaded_cb();
+#endif
 }
 
 
@@ -1624,8 +1629,10 @@
 		((PurpleContact*)bnode->parent)->totalsize--;
 		/* the group totalsize will be taken care of by remove_contact below */
 
-		if (bnode->parent->parent != (PurpleBlistNode*)g)
+		if (bnode->parent->parent != (PurpleBlistNode*)g) {
+			purple_signal_emit(purple_blist_get_handle(), "buddy-removed-from-group", buddy);
 			serv_move_buddy(buddy, (PurpleGroup *)bnode->parent->parent, g);
+		}
 
 		if (bnode->next)
 			bnode->next->prev = bnode->prev;
@@ -2186,9 +2193,6 @@
 	if (ops && ops->remove_node)
 		ops->remove_node(node);
 
-	/* Remove this buddy's pounces */
-	purple_pounce_destroy_all_by_buddy(buddy);
-
 	/* Signal that the buddy has been removed before freeing the memory for it */
 	purple_signal_emit(purple_blist_get_handle(), "buddy-removed", buddy);
 
@@ -3092,7 +3096,7 @@
 
 	if (!ops)
 		return;
-
+#if 0
 	if (!ops->save_node) {
 		ops->save_node = purple_blist_save_node;
 		overrode = TRUE;
@@ -3112,6 +3116,7 @@
 		purple_debug_warning("blist", "Only some of the blist saving UI ops "
 				"were overridden. This probably is not what you want!\n");
 	}
+#endif
 }
 
 PurpleBlistUiOps *
@@ -3193,6 +3198,11 @@
 						 purple_value_new(PURPLE_TYPE_SUBTYPE,
 										PURPLE_SUBTYPE_BLIST_BUDDY));
 
+	purple_signal_register(handle, "buddy-removed-from-group",
+						 purple_marshal_VOID__POINTER, NULL, 1,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_BLIST_BUDDY));
+
 	purple_signal_register(handle, "buddy-icon-changed",
 						 purple_marshal_VOID__POINTER, NULL, 1,
 						 purple_value_new(PURPLE_TYPE_SUBTYPE,
@@ -3239,11 +3249,13 @@
 	if (purplebuddylist == NULL)
 		return;
 
+#if 0
 	if (save_timer != 0) {
 		purple_timeout_remove(save_timer);
 		save_timer = 0;
 		purple_blist_sync();
 	}
+#endif
 
 	purple_blist_destroy();
 
diff -ru extract/pidgin-2.10.11/libpurple/blist.h libpurple/blist.h
--- extract/pidgin-2.10.11/libpurple/blist.h	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/blist.h	2015-03-19 23:21:15.000000000 -0400
@@ -106,9 +106,35 @@
  */
 #define PURPLE_CHAT(obj) ((PurpleChat *)(obj))
 
+#if 0
+#include "media.h"
+#else
+/** extracted from media.h */
+/** Media caps */
+typedef enum {
+	PURPLE_MEDIA_CAPS_NONE = 0,
+	PURPLE_MEDIA_CAPS_AUDIO = 1,
+	PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION = 1 << 1,
+	PURPLE_MEDIA_CAPS_VIDEO = 1 << 2,
+	PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION = 1 << 3,
+	PURPLE_MEDIA_CAPS_AUDIO_VIDEO = 1 << 4,
+	PURPLE_MEDIA_CAPS_MODIFY_SESSION = 1 << 5,
+	PURPLE_MEDIA_CAPS_CHANGE_DIRECTION = 1 << 6
+} PurpleMediaCaps;
+
+/** Media session types */
+typedef enum {
+	PURPLE_MEDIA_NONE	= 0,
+	PURPLE_MEDIA_RECV_AUDIO = 1 << 0,
+	PURPLE_MEDIA_SEND_AUDIO = 1 << 1,
+	PURPLE_MEDIA_RECV_VIDEO = 1 << 2,
+	PURPLE_MEDIA_SEND_VIDEO = 1 << 3,
+	PURPLE_MEDIA_AUDIO = PURPLE_MEDIA_RECV_AUDIO | PURPLE_MEDIA_SEND_AUDIO,
+	PURPLE_MEDIA_VIDEO = PURPLE_MEDIA_RECV_VIDEO | PURPLE_MEDIA_SEND_VIDEO
+} PurpleMediaSessionType;
+#endif
 #include "account.h"
 #include "buddyicon.h"
-#include "media.h"
 #include "status.h"
 
 /**************************************************************************/
@@ -1088,7 +1114,7 @@
  * the buddy list is saved automatically, so you should not need to
  * call this.
  */
-void purple_blist_schedule_save(void);
+/* void purple_blist_schedule_save(void); */
 
 /**
  * Requests from the user information needed to add a buddy to the
diff -ru extract/pidgin-2.10.11/libpurple/buddyicon.c libpurple/buddyicon.c
--- extract/pidgin-2.10.11/libpurple/buddyicon.c	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/buddyicon.c	2015-03-19 23:21:15.000000000 -0400
@@ -187,6 +187,9 @@
 
 	g_return_if_fail(filename != NULL);
 
+	if (!purple_buddy_icons_is_caching())
+		return;
+
 	/* It's possible that there are other references to this icon
 	 * cache file that are not currently loaded into memory. */
 	if (GPOINTER_TO_INT(g_hash_table_lookup(icon_file_cache, filename)))
@@ -1123,31 +1126,34 @@
 }
 
 void
-_purple_buddy_icons_account_loaded_cb()
+purple_buddy_icons_account_loaded(PurpleAccount *account)
 {
-	const char *dirname = purple_buddy_icons_get_cache_dir();
-	GList *cur;
+	const char *account_icon_file = purple_account_get_string(account, "buddy_icon", NULL);
 
-	for (cur = purple_accounts_get_all(); cur != NULL; cur = cur->next)
+	if (account_icon_file != NULL)
 	{
-		PurpleAccount *account = cur->data;
-		const char *account_icon_file = purple_account_get_string(account, "buddy_icon", NULL);
-
-		if (account_icon_file != NULL)
+		const char *dirname = purple_buddy_icons_get_cache_dir();
+		char *path = g_build_filename(dirname, account_icon_file, NULL);
+		if (!g_file_test(path, G_FILE_TEST_EXISTS))
 		{
-			char *path = g_build_filename(dirname, account_icon_file, NULL);
-			if (!g_file_test(path, G_FILE_TEST_EXISTS))
-			{
-				purple_account_set_string(account, "buddy_icon", NULL);
-			} else {
-				ref_filename(account_icon_file);
-			}
-			g_free(path);
+			purple_account_set_string(account, "buddy_icon", NULL);
+		} else {
+			ref_filename(account_icon_file);
 		}
+		g_free(path);
 	}
 }
 
 void
+_purple_buddy_icons_account_loaded_cb()
+{
+	GList *cur;
+
+	for (cur = purple_accounts_get_all(); cur != NULL; cur = cur->next)
+		purple_buddy_icons_account_loaded(cur->data);
+}
+
+void
 _purple_buddy_icons_blist_loaded_cb()
 {
 	PurpleBlistNode *node = purple_blist_get_root();
diff -ru extract/pidgin-2.10.11/libpurple/buddyicon.h libpurple/buddyicon.h
--- extract/pidgin-2.10.11/libpurple/buddyicon.h	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/buddyicon.h	2015-03-19 23:21:15.000000000 -0400
@@ -270,6 +270,17 @@
 purple_buddy_icons_get_account_icon_timestamp(PurpleAccount *account);
 
 /**
+ * References the current icon of the loaded account.
+ *
+ * UIs should call this after loading an account, if the accounts
+ * aren't stored in the accounts.xml libpurple file.
+ *
+ * @param account The account
+ */
+void
+purple_buddy_icons_account_loaded(PurpleAccount *account);
+
+/**
  * Returns a boolean indicating if a given blist node has a custom buddy icon.
  *
  * @param node The blist node.
diff -ru extract/pidgin-2.10.11/libpurple/cmds.c libpurple/cmds.c
--- extract/pidgin-2.10.11/libpurple/cmds.c	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/cmds.c	2015-03-19 23:21:15.000000000 -0400
@@ -27,10 +27,11 @@
 #include "util.h"
 #include "cmds.h"
 
+static PurpleCommandsUiOps *cmds_ui_ops = NULL;
 static GList *cmds = NULL;
 static guint next_id = 1;
 
-typedef struct _PurpleCmd {
+struct _PurpleCmd {
 	PurpleCmdId id;
 	gchar *cmd;
 	gchar *args;
@@ -40,7 +41,7 @@
 	PurpleCmdFunc func;
 	gchar *help;
 	void *data;
-} PurpleCmd;
+};
 
 
 static gint cmds_compare_func(const PurpleCmd *a, const PurpleCmd *b)
@@ -59,6 +60,7 @@
 {
 	PurpleCmdId id;
 	PurpleCmd *c;
+	PurpleCommandsUiOps *ops;
 
 	g_return_val_if_fail(cmd != NULL && *cmd != '\0', 0);
 	g_return_val_if_fail(args != NULL, 0);
@@ -79,6 +81,10 @@
 
 	cmds = g_list_insert_sorted(cmds, c, (GCompareFunc)cmds_compare_func);
 
+	ops = purple_cmds_get_ui_ops();
+	if (ops && ops->register_command)
+		ops->register_command(cmd, p, f, prpl_id, helpstr, c);
+
 	purple_signal_emit(purple_cmds_get_handle(), "cmd-added", cmd, p, f);
 
 	return id;
@@ -102,6 +108,10 @@
 		c = l->data;
 
 		if (c->id == id) {
+			PurpleCommandsUiOps *ops = purple_cmds_get_ui_ops();
+			if (ops && ops->unregister_command)
+				ops->unregister_command(c->cmd, c->prpl_id);
+
 			cmds = g_list_remove(cmds, c);
 			purple_signal_emit(purple_cmds_get_handle(), "cmd-removed", c->cmd);
 			purple_cmd_free(c);
@@ -301,6 +311,39 @@
 
 }
 
+gboolean purple_cmd_execute(PurpleCmd *c, PurpleConversation *conv,
+			    const gchar *cmdline)
+{
+	gchar *err = NULL;
+	gchar **args = NULL;
+	PurpleCmdRet ret = PURPLE_CMD_RET_CONTINUE;
+
+	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
+		if (!(c->flags & PURPLE_CMD_FLAG_IM))
+			return FALSE;
+	}
+	else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
+		if (!(c->flags & PURPLE_CMD_FLAG_CHAT))
+			return FALSE;
+	}
+	else
+		return FALSE;
+
+	/* XXX: Don't worry much about the markup version of the command
+	   line, there's not a single use case... */
+	/* this checks the allow bad args flag for us */
+	if (!purple_cmd_parse_args(c, cmdline, cmdline, &args)) {
+		g_strfreev(args);
+		return FALSE;
+	}
+
+	ret = c->func(conv, c->cmd, args, &err, c->data);
+
+	g_free(err);
+	g_strfreev(args);
+
+	return ret == PURPLE_CMD_RET_OK;
+}
 
 GList *purple_cmd_list(PurpleConversation *conv)
 {
@@ -368,6 +411,21 @@
 	return &handle;
 }
 
+void
+purple_cmds_set_ui_ops(PurpleCommandsUiOps *ops)
+{
+	cmds_ui_ops = ops;
+}
+
+PurpleCommandsUiOps *
+purple_cmds_get_ui_ops(void)
+{
+	/* It is perfectly acceptable for cmds_ui_ops to be NULL; this just
+	 * means that the default libpurple implementation will be used.
+	 */
+	return cmds_ui_ops;
+}
+
 void purple_cmds_init(void)
 {
 	gpointer handle = purple_cmds_get_handle();
diff -ru extract/pidgin-2.10.11/libpurple/cmds.h libpurple/cmds.h
--- extract/pidgin-2.10.11/libpurple/cmds.h	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/cmds.h	2015-03-19 23:21:15.000000000 -0400
@@ -31,6 +31,8 @@
 /**************************************************************************/
 /*@{*/
 
+typedef struct _PurpleCmd PurpleCmd;
+
 /** The possible results of running a command with purple_cmd_do_command(). */
 typedef enum _PurpleCmdStatus {
 	PURPLE_CMD_STATUS_OK,
@@ -96,6 +98,31 @@
 	PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS = 0x08
 } PurpleCmdFlag;
 
+/**
+ * Command UI operations;  UIs should implement this if they want to handle
+ * commands themselves, rather than relying on the core.
+ *
+ * @see @ref ui-ops
+ */
+typedef struct
+{
+	/** If implemented, the UI is responsible for handling commands. */
+	/* @see purple_cmd_register for the argument values. */
+	void (*register_command)(const gchar *name, PurpleCmdPriority p,
+				 PurpleCmdFlag f, const gchar *prpl_id,
+				 const gchar *helpstr, PurpleCmd *cmd);
+
+	/** Should be implemented if register_command is implemented.
+	 *  name and prpl_id should have the same value that were used
+	 *  for the register_command call.
+	 */
+	void (*unregister_command)(const gchar *name, const gchar *prpl_id);
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+} PurpleCommandsUiOps;
 
 /*@}*/
 
@@ -194,6 +221,23 @@
                                   const gchar *markup, gchar **errormsg);
 
 /**
+ * Execute a specific command.
+ *
+ * The UI calls this to execute a command, after parsing the
+ * command name.
+ *
+ * @param c The command to execute.
+ * @param conv The conversation the command was typed in.
+ * @param cmdline The command the user typed (only the arguments).
+ *            The caller should remove the prefix and the command name.
+ *            It should not contain any formatting, and should be
+ *            in plain text (no html entities).
+ * @return TRUE if the command handled the cmdline, FALSE otherwise.
+ */
+gboolean purple_cmd_execute(PurpleCmd *c, PurpleConversation *conv,
+			    const gchar *cmdline);
+
+/**
  * List registered commands.
  *
  * Returns a <tt>GList</tt> (which must be freed by the caller) of all commands
@@ -230,6 +274,23 @@
 gpointer purple_cmds_get_handle(void);
 
 /**
+ * Sets the UI operations structure to be used when registering and
+ * unregistering commands.  The UI operations need only be set if the
+ * UI wants to handle the commands itself; otherwise, leave it as NULL.
+ *
+ * @param ops The UI operations structure.
+ */
+void purple_cmds_set_ui_ops(PurpleCommandsUiOps *ops);
+
+/**
+ * Returns the UI operations structure to be used when registering and
+ * unregistering commands.
+ *
+ * @return The UI operations structure.
+ */
+PurpleCommandsUiOps *purple_cmds_get_ui_ops(void);
+
+/**
  * Initialize the commands subsystem.
  * @since 2.5.0
  */
Only in libpurple: config.h
diff -ru extract/pidgin-2.10.11/libpurple/connection.c libpurple/connection.c
--- extract/pidgin-2.10.11/libpurple/connection.c	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/connection.c	2015-03-19 23:21:15.000000000 -0400
@@ -350,6 +350,7 @@
 		/* Set the time the account came online */
 		purple_presence_set_login_time(presence, time(NULL));
 
+#if 0
 		if (purple_prefs_get_bool("/purple/logging/log_system"))
 		{
 			PurpleLog *log = purple_account_get_log(account, TRUE);
@@ -365,6 +366,7 @@
 				g_free(msg);
 			}
 		}
+#endif
 
 		if (ops != NULL && ops->connected != NULL)
 			ops->connected(gc);
@@ -381,6 +383,7 @@
 	else if (gc->state == PURPLE_DISCONNECTED) {
 		PurpleAccount *account = purple_connection_get_account(gc);
 
+#if 0
 		if (purple_prefs_get_bool("/purple/logging/log_system"))
 		{
 			PurpleLog *log = purple_account_get_log(account, FALSE);
@@ -397,6 +400,7 @@
 		}
 
 		purple_account_destroy_log(account);
+#endif
 
 		if (ops != NULL && ops->disconnected != NULL)
 			ops->disconnected(gc);
diff -ru extract/pidgin-2.10.11/libpurple/conversation.c libpurple/conversation.c
--- extract/pidgin-2.10.11/libpurple/conversation.c	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/conversation.c	2015-03-19 23:21:15.000000000 -0400
@@ -153,6 +153,7 @@
 
 	type = purple_conversation_get_type(conv);
 
+#if 0
 	/* Always linkfy the text for display, unless we're
 	 * explicitly asked to do otheriwse*/
 	if (!(msgflags & PURPLE_MESSAGE_INVISIBLE)) {
@@ -167,6 +168,12 @@
 		sent = g_strdup(displayed);
 	} else
 		sent = g_strdup(message);
+#else
+	/* send and display as is, linkification has already been
+	   handled by the conversation binding */
+	displayed = g_strdup(message);
+	sent = g_strdup(message);
+#endif
 
 	msgflags |= PURPLE_MESSAGE_SEND;
 
@@ -238,6 +245,7 @@
 	g_free(sent);
 }
 
+#if 0
 static void
 open_log(PurpleConversation *conv)
 {
@@ -245,6 +253,7 @@
 							   PURPLE_LOG_IM, conv->name, conv->account,
 							   conv, time(NULL), NULL));
 }
+#endif
 
 /* Functions that deal with PurpleConvMessage */
 
@@ -307,8 +316,10 @@
 
 	account = purple_conversation_get_account(conv);
 
+#if 0
 	purple_conversation_close_logs(conv);
 	open_log(conv);
+#endif
 
 	gc = purple_account_get_connection(account);
 
@@ -398,11 +409,13 @@
 			purple_buddy_icon_unref(icon);
 		}
 
+#if 0
 		if (purple_prefs_get_bool("/purple/logging/log_ims"))
 		{
 			purple_conversation_set_logging(conv, TRUE);
 			open_log(conv);
 		}
+#endif
 	}
 	else if (type == PURPLE_CONV_TYPE_CHAT)
 	{
@@ -422,11 +435,13 @@
 			purple_conv_chat_set_nick(conv->u.chat,
 									purple_account_get_username(account));
 
+#if 0
 		if (purple_prefs_get_bool("/purple/logging/log_chats"))
 		{
 			purple_conversation_set_logging(conv, TRUE);
 			open_log(conv);
 		}
+#endif
 	}
 
 	conversations = g_list_prepend(conversations, conv);
@@ -598,7 +613,9 @@
 		ops->destroy_conversation(conv);
 	conv->ui_data = NULL;
 
+#if 0
 	purple_conversation_close_logs(conv);
+#endif
 
 	purple_conversation_clear_message_history(conv);
 
@@ -800,6 +817,7 @@
 	return conv->name;
 }
 
+#if 0
 void
 purple_conversation_set_logging(PurpleConversation *conv, gboolean log)
 {
@@ -829,6 +847,7 @@
 	g_list_free(conv->logs);
 	conv->logs = NULL;
 }
+#endif
 
 PurpleConvIm *
 purple_conversation_get_im_data(const PurpleConversation *conv)
@@ -1008,6 +1027,7 @@
 		}
 	}
 
+#if 0
 	if (!(flags & PURPLE_MESSAGE_NO_LOG) && purple_conversation_is_logging(conv)) {
 		GList *log;
 
@@ -1020,6 +1040,7 @@
 			log = log->next;
 		}
 	}
+#endif
 
 	if (ops && ops->write_conv)
 		ops->write_conv(conv, who, alias, displayed, flags, mtime);
@@ -1242,6 +1263,7 @@
 
 	if ((flags & PURPLE_MESSAGE_RECV) == PURPLE_MESSAGE_RECV) {
 		purple_conv_im_set_typing_state(im, PURPLE_NOT_TYPING);
+		purple_conv_im_update_typing(im);
 	}
 
 	/* Pass this on to either the ops structure or the default write func. */
diff -ru extract/pidgin-2.10.11/libpurple/conversation.h libpurple/conversation.h
--- extract/pidgin-2.10.11/libpurple/conversation.h	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/conversation.h	2015-03-19 23:21:15.000000000 -0400
@@ -568,7 +568,7 @@
  * @param conv The conversation.
  * @param log  @c TRUE if logging should be enabled, or @c FALSE otherwise.
  */
-void purple_conversation_set_logging(PurpleConversation *conv, gboolean log);
+/* void purple_conversation_set_logging(PurpleConversation *conv, gboolean log); */
 
 /**
  * Returns whether or not logging is enabled for this conversation.
@@ -577,7 +577,7 @@
  *
  * @return @c TRUE if logging is enabled, or @c FALSE otherwise.
  */
-gboolean purple_conversation_is_logging(const PurpleConversation *conv);
+/* gboolean purple_conversation_is_logging(const PurpleConversation *conv); */
 
 /**
  * Closes any open logs for this conversation.
@@ -588,7 +588,7 @@
  *
  * @param conv The conversation.
  */
-void purple_conversation_close_logs(PurpleConversation *conv);
+/* void purple_conversation_close_logs(PurpleConversation *conv); */
 
 /**
  * Returns the specified conversation's IM-specific data.
diff -ru extract/pidgin-2.10.11/libpurple/core.c libpurple/core.c
--- extract/pidgin-2.10.11/libpurple/core.c	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/core.c	2015-03-20 00:15:22.000000000 -0400
@@ -25,7 +25,6 @@
  */
 #include "internal.h"
 #include "cipher.h"
-#include "certificate.h"
 #include "cmds.h"
 #include "connection.h"
 #include "conversation.h"
@@ -38,19 +37,14 @@
 #include "network.h"
 #include "notify.h"
 #include "plugin.h"
-#include "pounce.h"
 #include "prefs.h"
 #include "privacy.h"
 #include "proxy.h"
-#include "savedstatuses.h"
 #include "signals.h"
 #include "smiley.h"
-#include "sound.h"
-#include "sound-theme-loader.h"
 #include "sslconn.h"
 #include "status.h"
 #include "stun.h"
-#include "theme-manager.h"
 #include "util.h"
 
 #ifdef HAVE_DBUS
@@ -63,6 +57,8 @@
 #  include "dbus-bindings.h"
 #endif
 
+#include <libxml/parser.h>
+
 struct PurpleCore
 {
 	char *ui;
@@ -73,7 +69,9 @@
 static PurpleCoreUiOps *_ops  = NULL;
 static PurpleCore      *_core = NULL;
 
+#ifdef STATIC_PROTO_INIT
 STATIC_PROTO_INIT
+#endif
 
 gboolean
 purple_core_init(const char *ui)
@@ -120,8 +118,6 @@
 	 * for protocol prefs to work. */
 	purple_prefs_init();
 
-	purple_debug_init();
-
 	if (ops != NULL)
 	{
 		if (ops->ui_prefs_init != NULL)
@@ -143,12 +139,15 @@
 	 */
 	purple_plugins_init();
 
+#ifdef STATIC_PROTO_INIT
 	/* Initialize all static protocols. */
 	static_proto_init();
+#endif
 
-	purple_plugins_probe(G_MODULE_SUFFIX);
+	if (ops != NULL && ops->register_plugins != NULL)
+		ops->register_plugins();
 
-	purple_theme_manager_init();
+	purple_plugins_probe(G_MODULE_SUFFIX);
 
 	/* The buddy icon code uses the imgstore, so init it early. */
 	purple_imgstore_init();
@@ -161,18 +160,14 @@
 	purple_connections_init();
 
 	purple_accounts_init();
-	purple_savedstatuses_init();
 	purple_notify_init();
-	purple_certificate_init();
 	purple_conversations_init();
 	purple_blist_init();
 	purple_log_init();
 	purple_network_init();
 	purple_privacy_init();
-	purple_pounces_init();
 	purple_proxy_init();
 	purple_dnsquery_init();
-	purple_sound_init();
 	purple_ssl_init();
 	purple_stun_init();
 	purple_xfers_init();
@@ -187,9 +182,6 @@
 	if (ops != NULL && ops->ui_init != NULL)
 		ops->ui_init();
 
-	/* The UI may have registered some theme types, so refresh them */
-	purple_theme_manager_refresh();
-
 	return TRUE;
 }
 
@@ -207,6 +199,7 @@
 	/* Transmission ends */
 	purple_connections_disconnect_all();
 
+#if 0
 	/*
 	 * Certificates must be destroyed before the SSL plugins, because
 	 * PurpleCertificates contain pointers to PurpleCertificateSchemes,
@@ -214,6 +207,7 @@
 	 * SSL plugin is uninit.
 	 */
 	purple_certificate_uninit();
+#endif
 
 	/* The SSL plugins must be uninit before they're unloaded */
 	purple_ssl_uninit();
@@ -226,18 +220,14 @@
 	/* Save .xml files, remove signals, etc. */
 	purple_smileys_uninit();
 	purple_idle_uninit();
-	purple_pounces_uninit();
 	purple_blist_uninit();
 	purple_ciphers_uninit();
 	purple_notify_uninit();
 	purple_conversations_uninit();
 	purple_connections_uninit();
 	purple_buddy_icons_uninit();
-	purple_savedstatuses_uninit();
 	purple_status_uninit();
 	purple_accounts_uninit();
-	purple_sound_uninit();
-	purple_theme_manager_uninit();
 	purple_xfers_uninit();
 	purple_proxy_uninit();
 	purple_dnsquery_uninit();
@@ -274,6 +264,8 @@
 	wpurple_cleanup();
 #endif
 
+        xmlCleanupParser();
+
 	_core = NULL;
 }
 
@@ -406,6 +398,7 @@
 	return TRUE;
 }
 
+#if 0
 gboolean
 purple_core_migrate(void)
 {
@@ -753,6 +746,7 @@
 	g_free(status_file);
 	return TRUE;
 }
+#endif
 
 GHashTable* purple_core_get_ui_info() {
 	PurpleCoreUiOps *ops = purple_core_get_ui_ops();
diff -ru extract/pidgin-2.10.11/libpurple/core.h libpurple/core.h
--- extract/pidgin-2.10.11/libpurple/core.h	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/core.h	2015-03-19 23:21:15.000000000 -0400
@@ -71,6 +71,11 @@
 	 */
 	GHashTable* (*get_ui_info)(void);
 
+	/** Called during the initialization of the core to give the
+	 *  UI a chance to register static plugins.
+	 */
+	void (*register_plugins)(void);
+
 	void (*_purple_reserved1)(void);
 	void (*_purple_reserved2)(void);
 	void (*_purple_reserved3)(void);
@@ -164,7 +169,7 @@
  * @return A boolean indicating success or migration failure. On failure,
  *         the application must display an error to the user and then exit.
  */
-gboolean purple_core_migrate(void);
+/* gboolean purple_core_migrate(void); */
 
 /**
  * Ensures that only one instance is running.  If libpurple is built with D-Bus
Only in extract/pidgin-2.10.11/libpurple: data
diff -ru extract/pidgin-2.10.11/libpurple/debug.c libpurple/debug.c
--- extract/pidgin-2.10.11/libpurple/debug.c	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/debug.c	2015-03-19 23:21:15.000000000 -0400
@@ -31,18 +31,6 @@
 static PurpleDebugUiOps *debug_ui_ops = NULL;
 
 /*
- * This determines whether debug info should be written to the
- * console or not.
- *
- * It doesn't make sense to make this a normal Purple preference
- * because it's a command line option.  This will always be FALSE,
- * unless the user explicitly started the UI with the -d flag.
- * It doesn't matter what this value was the last time Purple was
- * started, so it doesn't make sense to save it in prefs.
- */
-static gboolean debug_enabled = FALSE;
-
-/*
  * These determine whether verbose or unsafe debugging are desired.  I
  * don't want to make these purple preferences because their values should
  * not be remembered across instances of the UI.
@@ -50,10 +38,12 @@
 static gboolean debug_verbose = FALSE;
 static gboolean debug_unsafe = FALSE;
 
-static void
-purple_debug_vargs(PurpleDebugLevel level, const char *category,
-				 const char *format, va_list args)
+void
+purple_debug_with_location(PurpleDebugLevel level, const char *category,
+			   const char *file, int line, const char *function,
+			   const char *format, ...)
 {
+	va_list args;
 	PurpleDebugUiOps *ops;
 	char *arg_s = NULL;
 
@@ -61,121 +51,88 @@
 	g_return_if_fail(format != NULL);
 
 	ops = purple_debug_get_ui_ops();
-
-	if (!debug_enabled && ((ops == NULL) || (ops->print == NULL) ||
-			(ops->is_enabled && !ops->is_enabled(level, category))))
+	if ((ops == NULL) ||
+	    (ops->print_with_location == NULL && ops->print == NULL) ||
+	    (ops->is_enabled && !ops->is_enabled(level, category)))
 		return;
 
-	arg_s = g_strdup_vprintf(format, args);
-
-	if (debug_enabled) {
-		gchar *ts_s;
-		const char *mdate;
-		time_t mtime = time(NULL);
-
-
-		mdate = purple_utf8_strftime("%H:%M:%S", localtime(&mtime));
-		ts_s = g_strdup_printf("(%s) ", mdate);
-
-		if (category == NULL)
-			g_print("%s%s", ts_s, arg_s);
-		else
-			g_print("%s%s: %s", ts_s, category, arg_s);
-
-		g_free(ts_s);
-	}
+	va_start(args, format);
 
-	if (ops != NULL && ops->print != NULL)
+	arg_s = g_strdup_vprintf(format, args);
+	if (ops->print_with_location != NULL)
+		ops->print_with_location(level, category, file, line, function, arg_s);
+	else
 		ops->print(level, category, arg_s);
-
 	g_free(arg_s);
-}
-
-void
-purple_debug(PurpleDebugLevel level, const char *category,
-		   const char *format, ...)
-{
-	va_list args;
-
-	g_return_if_fail(level != PURPLE_DEBUG_ALL);
-	g_return_if_fail(format != NULL);
-
-	va_start(args, format);
-	purple_debug_vargs(level, category, format, args);
-	va_end(args);
-}
 
-void
-purple_debug_misc(const char *category, const char *format, ...)
-{
-	va_list args;
-
-	g_return_if_fail(format != NULL);
-
-	va_start(args, format);
-	purple_debug_vargs(PURPLE_DEBUG_MISC, category, format, args);
 	va_end(args);
 }
 
-void
-purple_debug_info(const char *category, const char *format, ...)
-{
-	va_list args;
+/* This is kept for ABI compatibility only. Should be removed once we
+ * change the version number and thus can safely assume that all old
+ * plugins will be disabled.
+ * New code uses purple_debug_with_location. */
+#undef purple_debug
+#undef purple_debug_misc
+#undef purple_debug_info
+#undef purple_debug_warning
+#undef purple_debug_error
+#undef purple_debug_fatal
 
-	g_return_if_fail(format != NULL);
-
-	va_start(args, format);
-	purple_debug_vargs(PURPLE_DEBUG_INFO, category, format, args);
-	va_end(args);
-}
-
-void
-purple_debug_warning(const char *category, const char *format, ...)
+static void
+purple_debug_vargs(PurpleDebugLevel level, const char *category,
+				 const char *format, va_list args)
 {
-	va_list args;
+	PurpleDebugUiOps *ops;
+	char *arg_s = NULL;
 
+	g_return_if_fail(level != PURPLE_DEBUG_ALL);
 	g_return_if_fail(format != NULL);
 
-	va_start(args, format);
-	purple_debug_vargs(PURPLE_DEBUG_WARNING, category, format, args);
-	va_end(args);
-}
-
-void
-purple_debug_error(const char *category, const char *format, ...)
-{
-	va_list args;
+	ops = purple_debug_get_ui_ops();
 
-	g_return_if_fail(format != NULL);
+	if ((ops == NULL) || (ops->print == NULL) ||
+	    (ops->is_enabled && !ops->is_enabled(level, category)))
+		return;
 
-	va_start(args, format);
-	purple_debug_vargs(PURPLE_DEBUG_ERROR, category, format, args);
-	va_end(args);
+	arg_s = g_strdup_vprintf(format, args);
+	ops->print(level, category, arg_s);
+	g_free(arg_s);
 }
 
 void
-purple_debug_fatal(const char *category, const char *format, ...)
+purple_debug(PurpleDebugLevel level, const char *category,
+		   const char *format, ...)
 {
 	va_list args;
 
+	g_return_if_fail(level != PURPLE_DEBUG_ALL);
 	g_return_if_fail(format != NULL);
 
 	va_start(args, format);
-	purple_debug_vargs(PURPLE_DEBUG_FATAL, category, format, args);
+	purple_debug_vargs(level, category, format, args);
 	va_end(args);
 }
 
-void
-purple_debug_set_enabled(gboolean enabled)
-{
-	debug_enabled = enabled;
-}
-
-gboolean
-purple_debug_is_enabled()
-{
-	return debug_enabled;
-}
+#define PURPLE_IMPL_DEBUG_HELPER(name, NAME)				  \
+ void									  \
+ purple_debug_##name(const char *category, const char *format, ...)	  \
+ {									  \
+	 va_list args;							  \
+									  \
+	 g_return_if_fail(format != NULL);				  \
+									  \
+	 va_start(args, format);					  \
+	 purple_debug_vargs(PURPLE_DEBUG_##NAME, category, format, args); \
+	 va_end(args);							  \
+ }
+
+PURPLE_IMPL_DEBUG_HELPER(misc, MISC)
+PURPLE_IMPL_DEBUG_HELPER(info, INFO)
+PURPLE_IMPL_DEBUG_HELPER(warning, WARNING)
+PURPLE_IMPL_DEBUG_HELPER(error, ERROR)
+PURPLE_IMPL_DEBUG_HELPER(fatal, FATAL)
+/* End of the code kept for ABI compatibility */
 
 void
 purple_debug_set_ui_ops(PurpleDebugUiOps *ops)
@@ -212,24 +169,3 @@
 {
 	return debug_ui_ops;
 }
-
-void
-purple_debug_init(void)
-{
-	/* Read environment variables once per init */
-	if(g_getenv("PURPLE_UNSAFE_DEBUG"))
-		purple_debug_set_unsafe(TRUE);
-
-	if(g_getenv("PURPLE_VERBOSE_DEBUG"))
-		purple_debug_set_verbose(TRUE);
-
-	purple_prefs_add_none("/purple/debug");
-
-	/*
-	 * This pref is obsolete and no longer referenced anywhere. It only
-	 * survives here because it would be an API break if we removed it.
-	 * Remove this when we get to 3.0.0 :)
-	 */
-	purple_prefs_add_bool("/purple/debug/timestamps", TRUE);
-}
-
diff -ru extract/pidgin-2.10.11/libpurple/debug.h libpurple/debug.h
--- extract/pidgin-2.10.11/libpurple/debug.h	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/debug.h	2015-03-19 23:21:15.000000000 -0400
@@ -50,6 +50,9 @@
 {
 	void (*print)(PurpleDebugLevel level, const char *category,
 				  const char *arg_s);
+	void (*print_with_location)(PurpleDebugLevel level, const char *category,
+				    const char *file, int line,
+				    const char *function, const char *arg_s);
 	gboolean (*is_enabled)(PurpleDebugLevel level,
 			const char *category);
 
@@ -66,15 +69,43 @@
 /**************************************************************************/
 /** @name Debug API                                                       */
 /**************************************************************************/
+
 /**
  * Outputs debug information.
  *
  * @param level    The debug level.
  * @param category The category (or @c NULL).
+ * @param file     The file containing the calling code.
+ * @param line     The line number.
+ * @param function The calling function.
  * @param format   The format string.
  */
+void purple_debug_with_location(PurpleDebugLevel level, const char *category,
+				const char *file, int line,
+				const char *function, const char *format, ...);
+
+#ifndef _MSC_VER
+/* The use of __VA_ARGS__ will cause gcc to annoyingly output this warning:
+ *  warning: anonymous variadic macros were introduced in C99
+ * Tell it to shut up...
+ */
+#pragma GCC system_header
+#endif
+
+/**
+ * Outputs debug information.
+ *
+ * @param level    The debug level.
+ * @param category The category (or @c NULL).
+ * @param format   The format string.
+ */
+/*
 void purple_debug(PurpleDebugLevel level, const char *category,
 				const char *format, ...) G_GNUC_PRINTF(3, 4);
+*/
+#define purple_debug(level, category, ...)				\
+	purple_debug_with_location(level, category, __FILE__, __LINE__, \
+	                           __FUNCTION__, __VA_ARGS__)
 
 /**
  * Outputs misc. level debug information.
@@ -87,7 +118,11 @@
  *
  * @see purple_debug()
  */
+/*
 void purple_debug_misc(const char *category, const char *format, ...) G_GNUC_PRINTF(2, 3);
+*/
+#define purple_debug_misc(category, ...) \
+	purple_debug(PURPLE_DEBUG_MISC, category, __VA_ARGS__)
 
 /**
  * Outputs info level debug information.
@@ -100,7 +135,11 @@
  *
  * @see purple_debug()
  */
+/*
 void purple_debug_info(const char *category, const char *format, ...) G_GNUC_PRINTF(2, 3);
+*/
+#define purple_debug_info(category, ...) \
+	purple_debug(PURPLE_DEBUG_INFO, category, __VA_ARGS__)
 
 /**
  * Outputs warning level debug information.
@@ -113,7 +152,11 @@
  *
  * @see purple_debug()
  */
+/*
 void purple_debug_warning(const char *category, const char *format, ...) G_GNUC_PRINTF(2, 3);
+*/
+#define purple_debug_warning(category, ...) \
+	purple_debug(PURPLE_DEBUG_WARNING, category, __VA_ARGS__)
 
 /**
  * Outputs error level debug information.
@@ -126,12 +169,16 @@
  *
  * @see purple_debug()
  */
+/*
 void purple_debug_error(const char *category, const char *format, ...) G_GNUC_PRINTF(2, 3);
+*/
+#define purple_debug_error(category, ...) \
+	purple_debug(PURPLE_DEBUG_ERROR, category, __VA_ARGS__)
 
 /**
  * Outputs fatal error level debug information.
  *
- * This is a wrapper for purple_debug(), and uses PURPLE_DEBUG_ERROR as
+ * This is a wrapper for purple_debug(), and uses PURPLE_DEBUG_FATAL as
  * the level.
  *
  * @param category The category (or @c NULL).
@@ -139,21 +186,11 @@
  *
  * @see purple_debug()
  */
+/*
 void purple_debug_fatal(const char *category, const char *format, ...) G_GNUC_PRINTF(2, 3);
-
-/**
- * Enable or disable printing debug output to the console.
- *
- * @param enabled TRUE to enable debug output or FALSE to disable it.
- */
-void purple_debug_set_enabled(gboolean enabled);
-
-/**
- * Check if console debug output is enabled.
- *
- * @return TRUE if debugging is enabled, FALSE if it is not.
- */
-gboolean purple_debug_is_enabled(void);
+*/
+#define purple_debug_fatal(category, ...) \
+	purple_debug(PURPLE_DEBUG_FATAL, category, __VA_ARGS__)
 
 /**
  * Enable or disable verbose debugging.  This ordinarily should only be called
@@ -224,18 +261,6 @@
 
 /*@}*/
 
-/**************************************************************************/
-/** @name Debug Subsystem                                                 */
-/**************************************************************************/
-/*@{*/
-
-/**
- * Initializes the debug subsystem.
- */
-void purple_debug_init(void);
-
-/*@}*/
-
 #ifdef __cplusplus
 }
 #endif
diff -ru extract/pidgin-2.10.11/libpurple/dnsquery.c libpurple/dnsquery.c
--- extract/pidgin-2.10.11/libpurple/dnsquery.c	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/dnsquery.c	2015-03-20 00:15:22.000000000 -0400
@@ -40,9 +40,6 @@
 
 #define MAX_ADDR_RESPONSE_LEN 1048576
 
-#if (defined(__APPLE__) || defined (__unix__)) && !defined(__osf__)
-#define PURPLE_DNSQUERY_USE_FORK
-#endif
 /**************************************************************************
  * DNS query API
  **************************************************************************/
@@ -902,12 +899,8 @@
 		return FALSE;
 	}
 
-	if (purple_dnsquery_ui_resolve(query_data))
-		/* The UI is handling the resolve; we're done */
-		return FALSE;
-
-	resolve_host(query_data);
-
+	g_return_val_if_fail(purple_dnsquery_ui_resolve(query_data), FALSE);
+	/* The UI is handling the resolve; we're done */
 	return FALSE;
 }
 
diff -ru extract/pidgin-2.10.11/libpurple/eventloop.c libpurple/eventloop.c
--- extract/pidgin-2.10.11/libpurple/eventloop.c	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/eventloop.c	2015-03-19 23:21:15.000000000 -0400
@@ -25,6 +25,7 @@
  */
 #include "internal.h"
 #include "eventloop.h"
+#include "debug.h"
 
 static PurpleEventLoopUiOps *eventloop_ui_ops = NULL;
 
@@ -56,18 +57,30 @@
 }
 
 guint
-purple_input_add(int source, PurpleInputCondition condition, PurpleInputFunction func, gpointer user_data)
+purple_input_add_with_location(int source, PurpleInputCondition condition,
+			       PurpleInputFunction func, gpointer user_data,
+			       const char *file, int line, const char *function)
 {
 	PurpleEventLoopUiOps *ops = purple_eventloop_get_ui_ops();
 
+	purple_debug_with_location(PURPLE_DEBUG_MISC, "eventloop",
+				   file, line, function,
+				   "purple_input_add, fd = %i", source);
 	return ops->input_add(source, condition, func, user_data);
 }
 
+
+
 gboolean
-purple_input_remove(guint tag)
+purple_input_remove_with_location(guint tag, const char *file, int line,
+				  const char *function)
 {
 	PurpleEventLoopUiOps *ops = purple_eventloop_get_ui_ops();
 
+	purple_debug_with_location(PURPLE_DEBUG_MISC, "eventloop",
+				   file, line, function,
+				   "purple_input_remove, handle = %i", tag);
+
 	return ops->input_remove(tag);
 }
 
diff -ru extract/pidgin-2.10.11/libpurple/eventloop.h libpurple/eventloop.h
--- extract/pidgin-2.10.11/libpurple/eventloop.h	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/eventloop.h	2015-03-19 23:21:15.000000000 -0400
@@ -217,8 +217,17 @@
  * @return The resulting handle (will be greater than 0).
  * @see g_io_add_watch_full
  */
-guint purple_input_add(int fd, PurpleInputCondition cond,
-                       PurpleInputFunction func, gpointer user_data);
+/* guint purple_input_add(int fd, PurpleInputCondition cond,
+                       PurpleInputFunction func, gpointer user_data); */
+guint purple_input_add_with_location(int fd, PurpleInputCondition cond,
+				     PurpleInputFunction func,
+				     gpointer user_data,
+				     const char *file, int line,
+				     const char *function);
+
+#define purple_input_add(fd, cond, func, user_data)		      \
+  purple_input_add_with_location(fd, cond, func, user_data, __FILE__, \
+				 __LINE__, __FUNCTION__)
 
 /**
  * Removes an input handler.
@@ -226,7 +235,12 @@
  * @param handle The handle of the input handler. Note that this is the return
  *               value from purple_input_add(), <i>not</i> the file descriptor.
  */
-gboolean purple_input_remove(guint handle);
+/* gboolean purple_input_remove(guint handle); */
+gboolean purple_input_remove_with_location(guint handle, const char *file,
+					   int line, const char *function);
+
+#define purple_input_remove(handle)					     \
+  purple_input_remove_with_location(handle, __FILE__, __LINE__, __FUNCTION__)
 
 /**
  * Get the current error status for an input.
diff -ru extract/pidgin-2.10.11/libpurple/ft.c libpurple/ft.c
--- extract/pidgin-2.10.11/libpurple/ft.c	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/ft.c	2015-03-20 00:15:22.000000000 -0400
@@ -279,7 +279,7 @@
 	const char *message, gboolean is_error, gboolean print_thumbnail)
 {
 	PurpleConversation *conv = NULL;
-	PurpleMessageFlags flags = PURPLE_MESSAGE_SYSTEM;
+	PurpleMessageFlags flags = PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LINKIFY;
 	char *escaped;
 	gconstpointer thumbnail_data;
 	gsize size;
Only in libpurple: gettext.c
Only in libpurple: gettext.h
diff -ru extract/pidgin-2.10.11/libpurple/idle.c libpurple/idle.c
--- extract/pidgin-2.10.11/libpurple/idle.c	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/idle.c	2015-03-19 23:21:15.000000000 -0400
@@ -24,23 +24,9 @@
 
 #include "connection.h"
 #include "debug.h"
-#include "eventloop.h"
 #include "idle.h"
-#include "log.h"
-#include "prefs.h"
-#include "savedstatuses.h"
 #include "signals.h"
 
-typedef enum
-{
-	PURPLE_IDLE_NOT_AWAY = 0,
-	PURPLE_IDLE_AUTO_AWAY,
-	PURPLE_IDLE_AWAY_BUT_NOT_AUTO_AWAY
-
-} PurpleAutoAwayState;
-
-static PurpleIdleUiOps *idle_ui_ops = NULL;
-
 /**
  * This is needed for the I'dle Mak'er plugin to work correctly.  We
  * use it to determine if we're the ones who set our accounts idle
@@ -51,10 +37,6 @@
  */
 static GList *idled_accts = NULL;
 
-static guint idle_timer = 0;
-
-static time_t last_active_time = 0;
-
 static void
 set_account_idle(PurpleAccount *account, int time_idle)
 {
@@ -90,112 +72,11 @@
 	purple_presence_set_idle(presence, FALSE, 0);
 }
 
-
-static gboolean no_away = FALSE;
-static gint time_until_next_idle_event;
-/*
- * This function should be called when you think your idle state
- * may have changed.  Maybe you're over the 10-minute mark and
- * Purple should start reporting idle time to the server.  Maybe
- * you've returned from being idle.  Maybe your auto-away message
- * should be set.
- *
- * There is no harm to calling this many many times, other than
- * it will be kinda slow.  This is called by a timer set when
- * Purple starts.  It is also called when you send an IM, a chat, etc.
- *
- * This function has 3 sections.
- * 1. Get your idle time.  It will query XScreenSaver or Windows
- *    or use the Purple idle time.  Whatever.
- * 2. Set or unset your auto-away message.
- * 3. Report your current idle time to the IM server.
- */
-
-static void
-check_idleness(void)
+static time_t global_time_idle = 0;
+void
+purple_idle_set(time_t time_idle)
 {
-	time_t time_idle;
-	gboolean auto_away;
-	const gchar *idle_reporting;
-	gboolean report_idle = TRUE;
-	gint away_seconds = 0;
-	gint idle_recheck_interval = 0;
-	gint idle_poll_seconds = purple_prefs_get_int("/purple/away/mins_before_away") * 60;
-	purple_signal_emit(purple_blist_get_handle(), "update-idle");
-
-	idle_reporting = purple_prefs_get_string("/purple/away/idle_reporting");
-	auto_away = purple_prefs_get_bool("/purple/away/away_when_idle");
-
-	if (purple_strequal(idle_reporting, "system") &&
-		(idle_ui_ops != NULL) && (idle_ui_ops->get_time_idle != NULL))
-	{
-		/* Use system idle time (mouse or keyboard movement, etc.) */
-		time_idle = idle_ui_ops->get_time_idle();
-		idle_recheck_interval = 1;
-	}
-	else if (purple_strequal(idle_reporting, "purple"))
-	{
-		/* Use 'Purple idle' */
-		time_idle = time(NULL) - last_active_time;
-		idle_recheck_interval = 0;
-	}
-	else
-	{
-		/* Don't report idle time */
-		time_idle = 0;
-		report_idle = FALSE;
-
-		/* If we're not reporting idle, we can still do auto-away.
-		 * First try "system" and if that isn't possible, use "purple" */
-		if (auto_away)
-		{
-			if ((idle_ui_ops != NULL) && (idle_ui_ops->get_time_idle != NULL))
-			{
-				time_idle = idle_ui_ops->get_time_idle();
-				idle_recheck_interval = 1;
-			}
-			else
-			{
-				time_idle = time(NULL) - last_active_time;
-				idle_recheck_interval = 0;
-			}
-		}
-		else
-		{
-			if (!no_away)
-			{
-				no_away = TRUE;
-				purple_savedstatus_set_idleaway(FALSE);
-			}
-			time_until_next_idle_event = 0;
-			return;
-		}
-	}
-
-	time_until_next_idle_event = idle_poll_seconds - time_idle;
-	if (time_until_next_idle_event < 0)
-	{
-		/* If we're already idle, check again as appropriate. */
-		time_until_next_idle_event = idle_recheck_interval;
-	}
-
-	if (auto_away || !no_away)
-		away_seconds = 60 * purple_prefs_get_int("/purple/away/mins_before_away");
-
-	if (auto_away && time_idle > away_seconds)
-	{
-		purple_savedstatus_set_idleaway(TRUE);
-		no_away = FALSE;
-	}
-	else if (purple_savedstatus_is_idleaway() && time_idle < away_seconds)
-	{
-		purple_savedstatus_set_idleaway(FALSE);
-		if (time_until_next_idle_event == 0 || (away_seconds - time_idle) < time_until_next_idle_event)
-			time_until_next_idle_event = away_seconds - time_idle;
-	}
-
-	/* Idle reporting stuff */
-	if (report_idle && (time_idle >= idle_poll_seconds))
+	if (time_idle)
 	{
 		GList *l;
 		for (l = purple_connections_get_all(); l != NULL; l = l->next)
@@ -204,94 +85,27 @@
 			set_account_idle(purple_connection_get_account(gc), time_idle);
 		}
 	}
-	else if (!report_idle || (time_idle < idle_poll_seconds ))
+	else
 	{
 		while (idled_accts != NULL)
 			set_account_unidle(idled_accts->data);
 	}
+	global_time_idle = time_idle;
 }
 
 
-/*
- * Check idle and set the timer to fire at the next idle-worth event
- */
-static gboolean
-check_idleness_timer(void)
-{
-	check_idleness();
-	if (time_until_next_idle_event == 0)
-		idle_timer = 0;
-	else
-	{
-		/* +1 for the boundary,
-		 * +1 more for g_timeout_add_seconds rounding. */
-		idle_timer = purple_timeout_add_seconds(time_until_next_idle_event + 2, (GSourceFunc)check_idleness_timer, NULL);
-	}
-	return FALSE;
-}
-
-static void
-im_msg_sent_cb(PurpleAccount *account, const char *receiver,
-			   const char *message, void *data)
-{
-	/* Check our idle time after an IM is sent */
-	check_idleness();
-}
-
 static void
 signing_on_cb(PurpleConnection *gc, void *data)
 {
 	/* When signing on a new account, check if the account should be idle */
-	check_idleness();
+	if (global_time_idle)
+		set_account_idle(purple_connection_get_account(gc), global_time_idle);
 }
 
 static void
 signing_off_cb(PurpleConnection *gc, void *data)
 {
-	PurpleAccount *account;
-
-	account = purple_connection_get_account(gc);
-	set_account_unidle(account);
-}
-
-static void
-idle_reporting_cb(const char *name, PurplePrefType type, gconstpointer val, gpointer data)
-{
-	if (idle_timer)
-		purple_timeout_remove(idle_timer);
-	idle_timer = 0;
-	check_idleness_timer();
-}
-
-void
-purple_idle_touch()
-{
-	time(&last_active_time);
-	if (!no_away)
-	{
-		if (idle_timer)
-			purple_timeout_remove(idle_timer);
-		idle_timer = 0;
-		check_idleness_timer();
-	}
-}
-
-void
-purple_idle_set(time_t time)
-{
-	last_active_time = time;
-}
-
-void
-purple_idle_set_ui_ops(PurpleIdleUiOps *ops)
-{
-	idle_ui_ops = ops;
-}
-
-PurpleIdleUiOps *
-purple_idle_get_ui_ops(void)
-{
-	return idle_ui_ops;
+	set_account_unidle(purple_connection_get_account(gc));
 }
 
 static void *
@@ -302,49 +116,19 @@
 	return &handle;
 }
 
-static gboolean _do_purple_idle_touch_cb(gpointer data)
-{
-	int idle_poll_minutes = purple_prefs_get_int("/purple/away/mins_before_away");
-
-	 /* +1 more for g_timeout_add_seconds rounding. */
-	idle_timer = purple_timeout_add_seconds((idle_poll_minutes * 60) + 2, (GSourceFunc)check_idleness_timer, NULL);
-
-	purple_idle_touch();
-
-	return FALSE;
-}
-
-
 void
 purple_idle_init()
 {
-	purple_signal_connect(purple_conversations_get_handle(), "sent-im-msg",
-						purple_idle_get_handle(),
-						PURPLE_CALLBACK(im_msg_sent_cb), NULL);
 	purple_signal_connect(purple_connections_get_handle(), "signing-on",
 						purple_idle_get_handle(),
 						PURPLE_CALLBACK(signing_on_cb), NULL);
 	purple_signal_connect(purple_connections_get_handle(), "signing-off",
 						purple_idle_get_handle(),
 						PURPLE_CALLBACK(signing_off_cb), NULL);
-
-	purple_prefs_connect_callback(purple_idle_get_handle(), "/purple/away/idle_reporting",
-	                              idle_reporting_cb, NULL);
-
-	/* Initialize the idleness asynchronously so it doesn't check idleness,
-	 * and potentially try to change the status before the UI is initialized */
-	purple_timeout_add(0, _do_purple_idle_touch_cb, NULL);
-
 }
 
 void
 purple_idle_uninit()
 {
 	purple_signals_disconnect_by_handle(purple_idle_get_handle());
-	purple_prefs_disconnect_by_handle(purple_idle_get_handle());
-
-	/* Remove the idle timer */
-	if (idle_timer > 0)
-		purple_timeout_remove(idle_timer);
-	idle_timer = 0;
 }
diff -ru extract/pidgin-2.10.11/libpurple/idle.h libpurple/idle.h
--- extract/pidgin-2.10.11/libpurple/idle.h	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/idle.h	2015-03-19 23:21:15.000000000 -0400
@@ -28,19 +28,6 @@
 
 #include <time.h>
 
-/**
- * Idle UI operations.
- */
-typedef struct
-{
-	time_t (*get_time_idle)(void);
-
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-} PurpleIdleUiOps;
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -51,16 +38,8 @@
 /*@{*/
 
 /**
- * Touch our idle tracker.  This signifies that the user is
- * 'active'.  The conversation code calls this when the
- * user sends an IM, for example.
- */
-void purple_idle_touch(void);
-
-/**
- * Fake our idle time by setting the time at which our
- * accounts purportedly became idle.  This is used by
- * the I'dle Mak'er plugin.
+ * Set as idle (if the timestamp is provided) or as unidle if the
+ * timestamp is 0.
  */
 void purple_idle_set(time_t time);
 
@@ -72,20 +51,6 @@
 /*@{*/
 
 /**
- * Sets the UI operations structure to be used for idle reporting.
- *
- * @param ops The UI operations structure.
- */
-void purple_idle_set_ui_ops(PurpleIdleUiOps *ops);
-
-/**
- * Returns the UI operations structure used for idle reporting.
- *
- * @return The UI operations structure in use.
- */
-PurpleIdleUiOps *purple_idle_get_ui_ops(void);
-
-/**
  * Initializes the idle system.
  */
 void purple_idle_init(void);
diff -ru extract/pidgin-2.10.11/libpurple/internal.h libpurple/internal.h
--- extract/pidgin-2.10.11/libpurple/internal.h	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/internal.h	2015-03-20 00:15:22.000000000 -0400
@@ -45,26 +45,21 @@
  * taken from an email to the texinfo mailing list by Manuel Guerrero.
  * Thank you Manuel, and thank you Alex's good friend Google.
  */
+
+#include <locale.h>
+#include "gettext.h"
+
+#define _(String) (purple_get_text(PACKAGE, String))
+#define N_(String) (String)
+#define ngettext(Singular, Plural, Number) dngettext(PACKAGE, Singular, Plural, Number)
+#define dngettext(Domain, Singular, Plural, Number) (purple_get_plural_text(Domain, Singular, Plural, Number))
+
 #ifdef ENABLE_NLS
-#  include <locale.h>
-#  ifndef __APPLE_CC__
-#    define __APPLE_CC__ 0
-#  endif
 #  include <libintl.h>
-#  define _(String) ((const char *)dgettext(PACKAGE, String))
 #  ifdef gettext_noop
+#    undef N_
 #    define N_(String) gettext_noop (String)
-#  else
-#    define N_(String) (String)
 #  endif
-#else
-#  include <locale.h>
-#  define N_(String) (String)
-#  ifndef _
-#    define _(String) ((const char *)String)
-#  endif
-#  define ngettext(Singular, Plural, Number) ((Number == 1) ? ((const char *)Singular) : ((const char *)Plural))
-#  define dngettext(Domain, Singular, Plural, Number) ((Number == 1) ? ((const char *)Singular) : ((const char *)Plural))
 #endif
 
 #ifdef HAVE_ENDIAN_H
@@ -102,9 +97,8 @@
 #include <langinfo.h>
 #endif
 
-#include <gmodule.h>
-
 #ifdef PURPLE_PLUGINS
+# include <gmodule.h>
 # ifdef HAVE_DLFCN_H
 #  include <dlfcn.h>
 # endif
@@ -142,7 +136,7 @@
 #include "win32dep.h"
 #endif
 
-#ifdef HAVE_CONFIG_H
+#ifdef SIZEOF_TIME_T
 #if SIZEOF_TIME_T == 4
 #	define PURPLE_TIME_T_MODIFIER "lu"
 #elif SIZEOF_TIME_T == 8
Only in libpurple: log.h
Only in extract/pidgin-2.10.11/libpurple: media
Only in libpurple: moz.build
diff -ru extract/pidgin-2.10.11/libpurple/network.c libpurple/network.c
--- extract/pidgin-2.10.11/libpurple/network.c	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/network.c	2015-03-20 00:15:22.000000000 -0400
@@ -24,6 +24,12 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
+#ifdef _WIN32
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#define INCL_WINSOCK_API_TYPEDEFS 1
+#endif
+
 #include "internal.h"
 
 #ifndef _WIN32
@@ -35,7 +41,7 @@
 #ifdef HAVE_GETIFADDRS
 #include <ifaddrs.h>
 #endif
-#else
+#elif 0
 #include <nspapi.h>
 #endif
 
@@ -81,17 +87,16 @@
 static NMState nm_state = NM_STATE_UNKNOWN;
 static gboolean have_nm_state = FALSE;
 
-#elif defined _WIN32
+#elif 0
 static int current_network_count;
 
 /* Mutex for the other global vars */
 static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
 static gboolean network_initialized = FALSE;
 static HANDLE network_change_handle = NULL;
-static int (WSAAPI *MyWSANSPIoctl) (
-		HANDLE hLookup, DWORD dwControlCode, LPVOID lpvInBuffer,
-		DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer,
-		LPDWORD lpcbBytesReturned, LPWSACOMPLETION lpCompletion) = NULL;
+static LPFN_WSANSPIOCTL MyWSANSPIoctl = NULL;
+#else
+static network_available_callback available_callback = NULL;
 #endif
 
 struct _PurpleNetworkListenData {
@@ -606,7 +611,7 @@
 	return ntohs(addr.sin_port);
 }
 
-#ifdef _WIN32
+#if 0
 #ifndef NS_NLA
 #define NS_NLA 15
 #endif
@@ -845,9 +850,12 @@
 
 	return FALSE;
 
-#elif defined _WIN32
+#elif 0
 	return (current_network_count > 0 || force_online);
 #else
+	if (available_callback)
+		return (available_callback());
+
 	return TRUE;
 #endif
 }
@@ -1162,7 +1170,7 @@
 #ifdef HAVE_NETWORKMANAGER
 	GError *error = NULL;
 #endif
-#ifdef _WIN32
+#if 0
 	GError *err = NULL;
 	gint cnt = wpurple_get_connected_network_count();
 
@@ -1183,7 +1191,6 @@
 	purple_prefs_add_string("/purple/network/stun_server", "");
 	purple_prefs_add_string("/purple/network/turn_server", "");
 	purple_prefs_add_int   ("/purple/network/turn_port", 3478);
-	purple_prefs_add_int	 ("/purple/network/turn_port_tcp", 3478);
 	purple_prefs_add_string("/purple/network/turn_username", "");
 	purple_prefs_add_string("/purple/network/turn_password", "");
 	purple_prefs_add_bool  ("/purple/network/auto_ip", TRUE);
@@ -1258,7 +1265,7 @@
 		dbus_g_connection_unref(nm_conn);
 #endif
 
-#ifdef _WIN32
+#if 0
 	g_static_mutex_lock(&mutex);
 	network_initialized = FALSE;
 	if (network_change_handle != NULL) {
@@ -1291,3 +1298,15 @@
 	/* TODO: clean up remaining port mappings, note calling
 	 purple_upnp_remove_port_mapping from here doesn't quite work... */
 }
+
+void
+purple_network_configuration_changed(void)
+{
+	purple_signal_emit(purple_network_get_handle(), "network-configuration-changed", NULL);
+}
+
+void
+purple_network_set_available_callback(network_available_callback cb)
+{
+	available_callback = cb;
+}
diff -ru extract/pidgin-2.10.11/libpurple/network.h libpurple/network.h
--- extract/pidgin-2.10.11/libpurple/network.h	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/network.h	2015-03-19 23:21:15.000000000 -0400
@@ -350,6 +350,24 @@
  */
 void purple_network_uninit(void);
 
+/**
+ * Emits the network-configuration-changed signal
+ */
+void
+purple_network_configuration_changed(void);
+
+/**
+ * Function pointer to a function indicating if network is available
+ */
+typedef gboolean (*network_available_callback)(void);
+
+/**
+ * Sets the callback function to be used to query the UI about the
+ * availability of the network.
+ */
+void
+purple_network_set_available_callback(network_available_callback cb);
+
 /*@}*/
 
 #ifdef __cplusplus
diff -ru extract/pidgin-2.10.11/libpurple/notify.c libpurple/notify.c
--- extract/pidgin-2.10.11/libpurple/notify.c	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/notify.c	2015-03-19 23:21:15.000000000 -0400
@@ -28,6 +28,7 @@
 #include "internal.h"
 #include "dbus-maybe.h"
 #include "notify.h"
+#include "debug.h"
 
 static PurpleNotifyUiOps *notify_ui_ops = NULL;
 static GList *handles = NULL;
@@ -85,6 +86,18 @@
 		}
 
 	}
+	else {
+		int level;
+		if (type == PURPLE_NOTIFY_MSG_ERROR)
+			level = PURPLE_DEBUG_ERROR;
+		else if (type == PURPLE_NOTIFY_MSG_WARNING)
+			level = PURPLE_DEBUG_WARNING;
+		else
+			level = PURPLE_DEBUG_INFO;
+		purple_debug(level, "notify", "Notification: %s (%s)",
+			     title ? title : "(null)",
+			     primary ? primary : "(null)");
+	}
 
 	if (cb != NULL)
 		cb(user_data);
diff -ru extract/pidgin-2.10.11/libpurple/plugin.c libpurple/plugin.c
--- extract/pidgin-2.10.11/libpurple/plugin.c	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/plugin.c	2015-03-19 23:21:15.000000000 -0400
@@ -33,7 +33,6 @@
 #include "request.h"
 #include "signals.h"
 #include "util.h"
-#include "valgrind.h"
 #include "version.h"
 
 typedef struct
@@ -73,6 +72,8 @@
 
 #ifdef PURPLE_PLUGINS
 
+#define RUNNING_ON_VALGRIND 0
+
 static gboolean
 has_file_extension(const char *filename, const char *ext)
 {
@@ -283,8 +284,9 @@
 				purple_debug_error("plugins", "%s is not loadable: %s\n",
 						 plugin->path, plugin->error);
 			}
+#if 0
 			plugin->handle = g_module_open(filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
-
+#endif
 			if (plugin->handle == NULL)
 			{
 #ifdef _WIN32
@@ -788,9 +790,9 @@
 void
 purple_plugin_destroy(PurplePlugin *plugin)
 {
-#ifdef PURPLE_PLUGINS
 	g_return_if_fail(plugin != NULL);
 
+#ifdef PURPLE_PLUGINS
 	if (purple_plugin_is_loaded(plugin))
 		purple_plugin_unload(plugin);
 
@@ -886,6 +888,17 @@
 				loader_info->destroy(plugin);
 		}
 	}
+#else
+	if (plugin->info != NULL) {
+		if (PURPLE_IS_PROTOCOL_PLUGIN(plugin))
+			protocol_plugins = g_list_remove(protocol_plugins, plugin);
+
+		if (plugin->info->unload)
+			plugin->info->unload(plugin);
+	}
+
+	plugins = g_list_remove(plugins, plugin);
+#endif /* !PURPLE_PLUGINS */
 
 	g_free(plugin->path);
 	g_free(plugin->error);
@@ -893,7 +906,6 @@
 	PURPLE_DBUS_UNREGISTER_POINTER(plugin);
 
 	g_free(plugin);
-#endif /* !PURPLE_PLUGINS */
 }
 
 gboolean
@@ -1179,7 +1191,9 @@
 purple_plugins_init(void) {
 	void *handle = purple_plugins_get_handle();
 
+#ifdef LIBDIR
 	purple_plugins_add_search_path(LIBDIR);
+#endif
 
 	purple_signal_register(handle, "plugin-load",
 						 purple_marshal_VOID__POINTER,
@@ -1256,14 +1270,11 @@
 void
 purple_plugins_destroy_all(void)
 {
-#ifdef PURPLE_PLUGINS
-
 	while (plugins != NULL)
 		purple_plugin_destroy(plugins->data);
-
-#endif /* PURPLE_PLUGINS */
 }
 
+#if 0
 void
 purple_plugins_save_loaded(const char *key)
 {
@@ -1345,6 +1356,7 @@
 	g_list_free(files);
 #endif /* PURPLE_PLUGINS */
 }
+#endif
 
 
 void
diff -ru extract/pidgin-2.10.11/libpurple/plugin.h libpurple/plugin.h
--- extract/pidgin-2.10.11/libpurple/plugin.h	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/plugin.h	2015-03-19 23:21:15.000000000 -0400
@@ -30,7 +30,9 @@
 #define _PURPLE_PLUGIN_H_
 
 #include <glib.h>
-#include <gmodule.h>
+#ifdef PURPLE_PLUGINS
+# include <gmodule.h>
+#endif
 #include "signals.h"
 #include "value.h"
 
@@ -217,6 +219,7 @@
 /**
  * Handles the initialization of modules.
  */
+#if 0
 #if !defined(PURPLE_PLUGINS) || defined(PURPLE_STATIC_PRPL)
 # define _FUNC_NAME(x) purple_init_##x##_plugin
 # define PURPLE_INIT_PLUGIN(pluginname, initfunc, plugininfo) \
@@ -237,7 +240,21 @@
 		return purple_plugin_register(plugin); \
 	}
 #endif
+#endif
 
+#ifdef PURPLE_STATIC_PRPL
+# define _FUNC_NAME(x) purple_init_##x##_plugin
+#else
+# define _FUNC_NAME(x) purple_plugin_register_self
+#endif
+
+#define PURPLE_INIT_PLUGIN(pluginname, initfunc, plugininfo) \
+	gboolean _FUNC_NAME(pluginname)(void) { \
+		PurplePlugin *plugin = purple_plugin_new(TRUE, NULL); \
+		plugin->info = &(plugininfo); \
+		initfunc((plugin)); \
+		return purple_plugin_register(plugin); \
+	}
 
 #ifdef __cplusplus
 extern "C" {
@@ -536,21 +553,6 @@
 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.
diff -ru extract/pidgin-2.10.11/libpurple/prefs.c libpurple/prefs.c
--- extract/pidgin-2.10.11/libpurple/prefs.c	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/prefs.c	2015-03-19 23:21:15.000000000 -0400
@@ -40,1342 +40,261 @@
 #include "win32dep.h"
 #endif
 
+static PurplePrefsUiOps *prefs_ui_ops = NULL;
+
 struct pref_cb {
 	PurplePrefCallback func;
 	gpointer data;
 	guint id;
 	void *handle;
-};
-
-/* TODO: This should use PurpleValues? */
-struct purple_pref {
-	PurplePrefType type;
+	void *observer;
 	char *name;
-	union {
-		gpointer generic;
-		gboolean boolean;
-		int integer;
-		char *string;
-		GList *stringlist;
-	} value;
-	GSList *callbacks;
-	struct purple_pref *parent;
-	struct purple_pref *sibling;
-	struct purple_pref *first_child;
-};
-
-
-static struct purple_pref prefs = {
-	PURPLE_PREF_NONE,
-	NULL,
-	{ NULL },
-	NULL,
-	NULL,
-	NULL,
-	NULL
 };
 
-static GHashTable *prefs_hash = NULL;
 static guint       save_timer = 0;
 static gboolean    prefs_loaded = FALSE;
-
-
-/*********************************************************************
- * Private utility functions                                         *
- *********************************************************************/
-
-static struct
-purple_pref *find_pref(const char *name)
-{
-	g_return_val_if_fail(name != NULL && name[0] == '/', NULL);
-
-	if (name[1] == '\0')
-		return &prefs;
-	else
-	{
-		/* When we're initializing, the debug system is
-		 * initialized before the prefs system, but debug
-		 * calls will end up calling prefs functions, so we
-		 * need to deal cleanly here. */
-		if (prefs_hash)
-			return g_hash_table_lookup(prefs_hash, name);
-		else
-			return NULL;
-	}
-}
-
-
-/*********************************************************************
- * Writing to disk                                                   *
- *********************************************************************/
-
-/*
- * This function recursively creates the xmlnode tree from the prefs
- * tree structure.  Yay recursion!
- */
-static void
-pref_to_xmlnode(xmlnode *parent, struct purple_pref *pref)
-{
-	xmlnode *node, *childnode;
-	struct purple_pref *child;
-	char buf[21];
-	GList *cur;
-
-	/* Create a new node */
-	node = xmlnode_new_child(parent, "pref");
-	xmlnode_set_attrib(node, "name", pref->name);
-
-	/* Set the type of this node (if type == PURPLE_PREF_NONE then do nothing) */
-	if (pref->type == PURPLE_PREF_INT) {
-		xmlnode_set_attrib(node, "type", "int");
-		g_snprintf(buf, sizeof(buf), "%d", pref->value.integer);
-		xmlnode_set_attrib(node, "value", buf);
-	}
-	else if (pref->type == PURPLE_PREF_STRING) {
-		xmlnode_set_attrib(node, "type", "string");
-		xmlnode_set_attrib(node, "value", pref->value.string ? pref->value.string : "");
-	}
-	else if (pref->type == PURPLE_PREF_STRING_LIST) {
-		xmlnode_set_attrib(node, "type", "stringlist");
-		for (cur = pref->value.stringlist; cur != NULL; cur = cur->next)
-		{
-			childnode = xmlnode_new_child(node, "item");
-			xmlnode_set_attrib(childnode, "value", cur->data ? cur->data : "");
-		}
-	}
-	else if (pref->type == PURPLE_PREF_PATH) {
-		char *encoded = g_filename_to_utf8(pref->value.string ? pref->value.string : "", -1, NULL, NULL, NULL);
-		xmlnode_set_attrib(node, "type", "path");
-		xmlnode_set_attrib(node, "value", encoded);
-		g_free(encoded);
-	}
-	else if (pref->type == PURPLE_PREF_PATH_LIST) {
-		xmlnode_set_attrib(node, "type", "pathlist");
-		for (cur = pref->value.stringlist; cur != NULL; cur = cur->next)
-		{
-			char *encoded = g_filename_to_utf8(cur->data ? cur->data : "", -1, NULL, NULL, NULL);
-			childnode = xmlnode_new_child(node, "item");
-			xmlnode_set_attrib(childnode, "value", encoded);
-			g_free(encoded);
-		}
-	}
-	else if (pref->type == PURPLE_PREF_BOOLEAN) {
-		xmlnode_set_attrib(node, "type", "bool");
-		g_snprintf(buf, sizeof(buf), "%d", pref->value.boolean);
-		xmlnode_set_attrib(node, "value", buf);
-	}
-
-	/* All My Children */
-	for (child = pref->first_child; child != NULL; child = child->sibling)
-		pref_to_xmlnode(node, child);
-}
-
-static xmlnode *
-prefs_to_xmlnode(void)
-{
-	xmlnode *node;
-	struct purple_pref *pref, *child;
-
-	pref = &prefs;
-
-	/* Create the root preference node */
-	node = xmlnode_new("pref");
-	xmlnode_set_attrib(node, "version", "1");
-	xmlnode_set_attrib(node, "name", "/");
-
-	/* All My Children */
-	for (child = pref->first_child; child != NULL; child = child->sibling)
-		pref_to_xmlnode(node, child);
-
-	return node;
-}
-
-static void
-sync_prefs(void)
-{
-	xmlnode *node;
-	char *data;
-
-	if (!prefs_loaded)
-	{
-		/*
-		 * TODO: Call schedule_prefs_save()?  Ideally we wouldn't need to.
-		 * (prefs.xml should be loaded when purple_prefs_init is called)
-		 */
-		purple_debug_error("prefs", "Attempted to save prefs before "
-						 "they were read!\n");
-		return;
-	}
-
-	node = prefs_to_xmlnode();
-	data = xmlnode_to_formatted_str(node, NULL);
-	purple_util_write_data_to_file("prefs.xml", data, -1);
-	g_free(data);
-	xmlnode_free(node);
-}
+static GSList     *callbacks = NULL;
 
 static gboolean
 save_cb(gpointer data)
 {
-	sync_prefs();
+	PurplePrefsUiOps *uiop = purple_prefs_get_ui_ops();
+	g_return_val_if_fail(uiop, FALSE);
+	uiop->save();
+
 	save_timer = 0;
 	return FALSE;
 }
 
-static void
-schedule_prefs_save(void)
-{
-	if (save_timer == 0)
-		save_timer = purple_timeout_add_seconds(5, save_cb, NULL);
-}
-
-
 /*********************************************************************
  * Reading from disk                                                 *
  *********************************************************************/
 
-static GList *prefs_stack = NULL;
-
-static void
-prefs_start_element_handler (GMarkupParseContext *context,
-		const gchar *element_name,
-		const gchar **attribute_names,
-		const gchar **attribute_values,
-		gpointer user_data,
-		GError **error)
-{
-	PurplePrefType pref_type = PURPLE_PREF_NONE;
-	int i;
-	const char *pref_name = NULL, *pref_value = NULL;
-	GString *pref_name_full;
-	GList *tmp;
-
-	if(!purple_strequal(element_name, "pref") &&
-	   !purple_strequal(element_name, "item"))
-		return;
-
-	for(i = 0; attribute_names[i]; i++) {
-		if(purple_strequal(attribute_names[i], "name")) {
-			pref_name = attribute_values[i];
-		} else if(purple_strequal(attribute_names[i], "type")) {
-			if(purple_strequal(attribute_values[i], "bool"))
-				pref_type = PURPLE_PREF_BOOLEAN;
-			else if(purple_strequal(attribute_values[i], "int"))
-				pref_type = PURPLE_PREF_INT;
-			else if(purple_strequal(attribute_values[i], "string"))
-				pref_type = PURPLE_PREF_STRING;
-			else if(purple_strequal(attribute_values[i], "stringlist"))
-				pref_type = PURPLE_PREF_STRING_LIST;
-			else if(purple_strequal(attribute_values[i], "path"))
-				pref_type = PURPLE_PREF_PATH;
-			else if(purple_strequal(attribute_values[i], "pathlist"))
-				pref_type = PURPLE_PREF_PATH_LIST;
-			else
-				return;
-		} else if(purple_strequal(attribute_names[i], "value")) {
-			pref_value = attribute_values[i];
-		}
-	}
-
-	if ((pref_type == PURPLE_PREF_BOOLEAN || pref_type == PURPLE_PREF_INT) &&
-			pref_value == NULL) {
-		/* Missing a value attribute */
-		return;
-	}
-
-	if(purple_strequal(element_name, "item")) {
-		struct purple_pref *pref;
-
-		pref_name_full = g_string_new("");
-
-		for(tmp = prefs_stack; tmp; tmp = tmp->next) {
-			pref_name_full = g_string_prepend(pref_name_full, tmp->data);
-			pref_name_full = g_string_prepend_c(pref_name_full, '/');
-		}
-
-		pref = find_pref(pref_name_full->str);
-
-		if(pref) {
-			if(pref->type == PURPLE_PREF_STRING_LIST) {
-				pref->value.stringlist = g_list_append(pref->value.stringlist,
-						g_strdup(pref_value));
-			} else if(pref->type == PURPLE_PREF_PATH_LIST) {
-				pref->value.stringlist = g_list_append(pref->value.stringlist,
-						g_filename_from_utf8(pref_value, -1, NULL, NULL, NULL));
-			}
-		}
-		g_string_free(pref_name_full, TRUE);
-	} else {
-		char *decoded;
-
-		if(!pref_name || purple_strequal(pref_name, "/"))
-			return;
-
-		pref_name_full = g_string_new(pref_name);
-
-		for(tmp = prefs_stack; tmp; tmp = tmp->next) {
-			pref_name_full = g_string_prepend_c(pref_name_full, '/');
-			pref_name_full = g_string_prepend(pref_name_full, tmp->data);
-		}
-
-		pref_name_full = g_string_prepend_c(pref_name_full, '/');
-
-		switch(pref_type) {
-			case PURPLE_PREF_NONE:
-				purple_prefs_add_none(pref_name_full->str);
-				break;
-			case PURPLE_PREF_BOOLEAN:
-				purple_prefs_set_bool(pref_name_full->str, atoi(pref_value));
-				break;
-			case PURPLE_PREF_INT:
-				purple_prefs_set_int(pref_name_full->str, atoi(pref_value));
-				break;
-			case PURPLE_PREF_STRING:
-				purple_prefs_set_string(pref_name_full->str, pref_value);
-				break;
-			case PURPLE_PREF_STRING_LIST:
-				purple_prefs_set_string_list(pref_name_full->str, NULL);
-				break;
-			case PURPLE_PREF_PATH:
-				if (pref_value) {
-					decoded = g_filename_from_utf8(pref_value, -1, NULL, NULL, NULL);
-					purple_prefs_set_path(pref_name_full->str, decoded);
-					g_free(decoded);
-				} else {
-					purple_prefs_set_path(pref_name_full->str, NULL);
-				}
-				break;
-			case PURPLE_PREF_PATH_LIST:
-				purple_prefs_set_path_list(pref_name_full->str, NULL);
-				break;
-		}
-		prefs_stack = g_list_prepend(prefs_stack, g_strdup(pref_name));
-		g_string_free(pref_name_full, TRUE);
-	}
-}
-
-static void
-prefs_end_element_handler(GMarkupParseContext *context,
-						  const gchar *element_name,
-						  gpointer user_data, GError **error)
-{
-	if(prefs_stack && purple_strequal(element_name, "pref")) {
-		g_free(prefs_stack->data);
-		prefs_stack = g_list_delete_link(prefs_stack, prefs_stack);
-	}
-}
-
-static GMarkupParser prefs_parser = {
-	prefs_start_element_handler,
-	prefs_end_element_handler,
-	NULL,
-	NULL,
-	NULL
-};
-
 gboolean
 purple_prefs_load()
 {
-	gchar *filename = g_build_filename(purple_user_dir(), "prefs.xml", NULL);
-	gchar *contents = NULL;
-	gsize length;
-	GMarkupParseContext *context;
-	GError *error = NULL;
-
-	if (!filename) {
-		prefs_loaded = TRUE;
-		return FALSE;
-	}
-
-	purple_debug_info("prefs", "Reading %s\n", filename);
-
-	if(!g_file_get_contents(filename, &contents, &length, &error)) {
-#ifdef _WIN32
-		gchar *common_appdata = wpurple_get_special_folder(CSIDL_COMMON_APPDATA);
-#endif
-		g_free(filename);
-		g_error_free(error);
-
-		error = NULL;
-
-#ifdef _WIN32
-		filename = g_build_filename(common_appdata ? common_appdata : "", "purple", "prefs.xml", NULL);
-		g_free(common_appdata);
-#else
-		filename = g_build_filename(SYSCONFDIR, "purple", "prefs.xml", NULL);
-#endif
-
-		purple_debug_info("prefs", "Reading %s\n", filename);
-
-		if (!g_file_get_contents(filename, &contents, &length, &error)) {
-			purple_debug_error("prefs", "Error reading prefs: %s\n",
-					error->message);
-			g_error_free(error);
-			g_free(filename);
-			prefs_loaded = TRUE;
-
-			return FALSE;
-		}
-	}
-
-	context = g_markup_parse_context_new(&prefs_parser, 0, NULL, NULL);
-
-	if(!g_markup_parse_context_parse(context, contents, length, NULL)) {
-		g_markup_parse_context_free(context);
-		g_free(contents);
-		g_free(filename);
-		prefs_loaded = TRUE;
-
-		return FALSE;
-	}
-
-	if(!g_markup_parse_context_end_parse(context, NULL)) {
-		purple_debug_error("prefs", "Error parsing %s\n", filename);
-		g_markup_parse_context_free(context);
-		g_free(contents);
-		g_free(filename);
-		prefs_loaded = TRUE;
-
-		return FALSE;
-	}
-
-	purple_debug_info("prefs", "Finished reading %s\n", filename);
-	g_markup_parse_context_free(context);
-	g_free(contents);
-	g_free(filename);
 	prefs_loaded = TRUE;
 
 	return TRUE;
 }
 
-
-
 static void
 prefs_save_cb(const char *name, PurplePrefType type, gconstpointer val,
 			  gpointer user_data)
 {
-
-	if(!prefs_loaded)
+	if (!prefs_loaded)
 		return;
 
 	purple_debug_misc("prefs", "%s changed, scheduling save.\n", name);
 
-	schedule_prefs_save();
-}
-
-static char *
-get_path_dirname(const char *name)
-{
-	char *c, *str;
-
-	str = g_strdup(name);
-
-	if ((c = strrchr(str, '/')) != NULL) {
-		*c = '\0';
-
-		if (*str == '\0') {
-			g_free(str);
-
-			str = g_strdup("/");
-		}
-	}
-	else {
-		g_free(str);
-
-		str = g_strdup(".");
-	}
-
-	return str;
-}
-
-static char *
-get_path_basename(const char *name)
-{
-	const char *c;
-
-	if ((c = strrchr(name, '/')) != NULL)
-		return g_strdup(c + 1);
-
-	return g_strdup(name);
-}
-
-static char *
-pref_full_name(struct purple_pref *pref)
-{
-	GString *name;
-	struct purple_pref *parent;
-
-	if(!pref)
-		return NULL;
-
-	if(pref == &prefs)
-		return g_strdup("/");
-
-	name = g_string_new(pref->name);
-
-	for(parent = pref->parent; parent && parent->name; parent = parent->parent) {
-		name = g_string_prepend_c(name, '/');
-		name = g_string_prepend(name, parent->name);
-	}
-	name = g_string_prepend_c(name, '/');
-	return g_string_free(name, FALSE);
-}
-
-static struct purple_pref *
-find_pref_parent(const char *name)
-{
-	char *parent_name = get_path_dirname(name);
-	struct purple_pref *ret = &prefs;
-
-	if(!purple_strequal(parent_name, "/")) {
-		ret = find_pref(parent_name);
-	}
-
-	g_free(parent_name);
-	return ret;
-}
-
-static void
-free_pref_value(struct purple_pref *pref)
-{
-	switch(pref->type) {
-		case PURPLE_PREF_BOOLEAN:
-			pref->value.boolean = FALSE;
-			break;
-		case PURPLE_PREF_INT:
-			pref->value.integer = 0;
-			break;
-		case PURPLE_PREF_STRING:
-		case PURPLE_PREF_PATH:
-			g_free(pref->value.string);
-			pref->value.string = NULL;
-			break;
-		case PURPLE_PREF_STRING_LIST:
-		case PURPLE_PREF_PATH_LIST:
-			{
-				g_list_foreach(pref->value.stringlist, (GFunc)g_free, NULL);
-				g_list_free(pref->value.stringlist);
-			} break;
-		case PURPLE_PREF_NONE:
-			break;
-	}
+	if (save_timer == 0)
+		save_timer = purple_timeout_add_seconds(6, save_cb, NULL);
 }
 
-static struct purple_pref *
-add_pref(PurplePrefType type, const char *name)
-{
-	struct purple_pref *parent;
-	struct purple_pref *me;
-	struct purple_pref *sibling;
-	char *my_name;
-
-	parent = find_pref_parent(name);
-
-	if(!parent)
-		return NULL;
-
-	my_name = get_path_basename(name);
-
-	for(sibling = parent->first_child; sibling; sibling = sibling->sibling) {
-		if(purple_strequal(sibling->name, my_name)) {
-			g_free(my_name);
-			return NULL;
-		}
-	}
-
-	me = g_new0(struct purple_pref, 1);
-	me->type = type;
-	me->name = my_name;
-
-	me->parent = parent;
-	if(parent->first_child) {
-		/* blatant abuse of a for loop */
-		for(sibling = parent->first_child; sibling->sibling;
-				sibling = sibling->sibling);
-		sibling->sibling = me;
-	} else {
-		parent->first_child = me;
+#define UIOP(aCall)						    \
+	{							    \
+		PurplePrefsUiOps *uiop = purple_prefs_get_ui_ops(); \
+		g_return_if_fail(uiop);				    \
+								    \
+		uiop->aCall;					    \
+	}
+
+#define UIOP_return(aCall, aDefault)				    \
+	{							    \
+		PurplePrefsUiOps *uiop = purple_prefs_get_ui_ops(); \
+		g_return_val_if_fail(uiop, aDefault);		    \
+								    \
+		return uiop->aCall;				    \
 	}
 
-	g_hash_table_insert(prefs_hash, g_strdup(name), (gpointer)me);
-
-	return me;
-}
-
 void
 purple_prefs_add_none(const char *name)
-{
-	add_pref(PURPLE_PREF_NONE, name);
-}
+	UIOP(add_none(name))
 
 void
 purple_prefs_add_bool(const char *name, gboolean value)
-{
-	struct purple_pref *pref = add_pref(PURPLE_PREF_BOOLEAN, name);
-
-	if(!pref)
-		return;
-
-	pref->value.boolean = value;
-}
+	UIOP(add_bool(name, value))
 
 void
 purple_prefs_add_int(const char *name, int value)
-{
-	struct purple_pref *pref = add_pref(PURPLE_PREF_INT, name);
-
-	if(!pref)
-		return;
-
-	pref->value.integer = value;
-}
+	UIOP(add_int(name, value))
 
 void
 purple_prefs_add_string(const char *name, const char *value)
-{
-	struct purple_pref *pref;
-
-	if(value != NULL && !g_utf8_validate(value, -1, NULL)) {
-		purple_debug_error("prefs", "purple_prefs_add_string: Cannot store invalid UTF8 for string pref %s\n", name);
-		return;
-	}
-
-	pref = add_pref(PURPLE_PREF_STRING, name);
-
-	if(!pref)
-		return;
-
-	pref->value.string = g_strdup(value);
-}
-
-void
-purple_prefs_add_string_list(const char *name, GList *value)
-{
-	struct purple_pref *pref = add_pref(PURPLE_PREF_STRING_LIST, name);
-	GList *tmp;
-
-	if(!pref)
-		return;
-
-	for(tmp = value; tmp; tmp = tmp->next) {
-		if(tmp->data != NULL && !g_utf8_validate(tmp->data, -1, NULL)) {
-			purple_debug_error("prefs", "purple_prefs_add_string_list: Skipping invalid UTF8 for string list pref %s\n", name);
-			continue;
-		}
-		pref->value.stringlist = g_list_append(pref->value.stringlist,
-				g_strdup(tmp->data));
-	}
-}
-
-void
-purple_prefs_add_path(const char *name, const char *value)
-{
-	struct purple_pref *pref = add_pref(PURPLE_PREF_PATH, name);
-
-	if(!pref)
-		return;
-
-	pref->value.string = g_strdup(value);
-}
-
-void
-purple_prefs_add_path_list(const char *name, GList *value)
-{
-	struct purple_pref *pref = add_pref(PURPLE_PREF_PATH_LIST, name);
-	GList *tmp;
-
-	if(!pref)
-		return;
-
-	for(tmp = value; tmp; tmp = tmp->next)
-		pref->value.stringlist = g_list_append(pref->value.stringlist,
-				g_strdup(tmp->data));
-}
-
-
-static void
-remove_pref(struct purple_pref *pref)
-{
-	char *name;
-	GSList *l;
-
-	if(!pref)
-		return;
-
-	while(pref->first_child)
-		remove_pref(pref->first_child);
-
-	if(pref == &prefs)
-		return;
-
-	if(pref->parent->first_child == pref) {
-		pref->parent->first_child = pref->sibling;
-	} else {
-		struct purple_pref *sib = pref->parent->first_child;
-		while(sib && sib->sibling != pref)
-			sib = sib->sibling;
-		if(sib)
-			sib->sibling = pref->sibling;
-	}
-
-	name = pref_full_name(pref);
-
-	if (prefs_loaded)
-		purple_debug_info("prefs", "removing pref %s\n", name);
-
-	g_hash_table_remove(prefs_hash, name);
-	g_free(name);
-
-	free_pref_value(pref);
-
-	while((l = pref->callbacks) != NULL) {
-		pref->callbacks = pref->callbacks->next;
-		g_free(l->data);
-		g_slist_free_1(l);
-	}
-	g_free(pref->name);
-	g_free(pref);
-}
+	UIOP(add_string(name, value))
 
 void
 purple_prefs_remove(const char *name)
-{
-	struct purple_pref *pref = find_pref(name);
-
-	if(!pref)
-		return;
-
-	remove_pref(pref);
-}
-
-void
-purple_prefs_destroy()
-{
-	purple_prefs_remove("/");
-}
-
-static void
-do_callbacks(const char* name, struct purple_pref *pref)
-{
-	GSList *cbs;
-	struct purple_pref *cb_pref;
-	for(cb_pref = pref; cb_pref; cb_pref = cb_pref->parent) {
-		for(cbs = cb_pref->callbacks; cbs; cbs = cbs->next) {
-			struct pref_cb *cb = cbs->data;
-			cb->func(name, pref->type, pref->value.generic, cb->data);
-		}
-	}
-}
+	UIOP(remove(name))
 
 void
 purple_prefs_trigger_callback(const char *name)
 {
-	struct purple_pref *pref = find_pref(name);
-
-	if(!pref) {
-		purple_debug_error("prefs",
-				"purple_prefs_trigger_callback: Unknown pref %s\n", name);
-		return;
-	}
-
-	do_callbacks(name, pref);
-}
+	GSList *cbs;
 
-void
-purple_prefs_set_generic(const char *name, gpointer value)
-{
-	struct purple_pref *pref = find_pref(name);
+	purple_debug_misc("prefs", "trigger callback %s\n", name);
 
-	if(!pref) {
-		purple_debug_error("prefs",
-				"purple_prefs_set_generic: Unknown pref %s\n", name);
-		return;
+	for (cbs = callbacks; cbs; cbs = cbs->next) {
+		const char *cb_name = ((struct pref_cb *)cbs->data)->name;
+		size_t len = strlen(cb_name);
+		if (!strncmp(cb_name, name, len) &&
+		    (name[len] == 0 || name[len] == '/' ||
+		     (len && name[len - 1] == '/'))) {
+			/* This test should behave like this:
+			 * name    = /toto/tata
+			 * cb_name = /toto/tata --> true
+			 * cb_name = /toto/tatatiti --> false
+			 * cb_name = / --> true
+			 * cb_name = /toto --> true
+			 * cb_name = /toto/ --> true
+			 */
+			purple_prefs_observe(cbs->data);
+		}
 	}
-
-	pref->value.generic = value;
-	do_callbacks(name, pref);
 }
 
 void
 purple_prefs_set_bool(const char *name, gboolean value)
-{
-	struct purple_pref *pref = find_pref(name);
-
-	if(pref) {
-		if(pref->type != PURPLE_PREF_BOOLEAN) {
-			purple_debug_error("prefs",
-					"purple_prefs_set_bool: %s not a boolean pref\n", name);
-			return;
-		}
-
-		if(pref->value.boolean != value) {
-			pref->value.boolean = value;
-			do_callbacks(name, pref);
-		}
-	} else {
-		purple_prefs_add_bool(name, value);
-	}
-}
+	UIOP(set_bool(name, value))
 
 void
 purple_prefs_set_int(const char *name, int value)
-{
-	struct purple_pref *pref = find_pref(name);
-
-	if(pref) {
-		if(pref->type != PURPLE_PREF_INT) {
-			purple_debug_error("prefs",
-					"purple_prefs_set_int: %s not an integer pref\n", name);
-			return;
-		}
-
-		if(pref->value.integer != value) {
-			pref->value.integer = value;
-			do_callbacks(name, pref);
-		}
-	} else {
-		purple_prefs_add_int(name, value);
-	}
-}
+	UIOP(set_int(name, value))
 
 void
 purple_prefs_set_string(const char *name, const char *value)
-{
-	struct purple_pref *pref = find_pref(name);
-
-	if(value != NULL && !g_utf8_validate(value, -1, NULL)) {
-		purple_debug_error("prefs", "purple_prefs_set_string: Cannot store invalid UTF8 for string pref %s\n", name);
-		return;
-	}
-
-	if(pref) {
-		if(pref->type != PURPLE_PREF_STRING && pref->type != PURPLE_PREF_PATH) {
-			purple_debug_error("prefs",
-					"purple_prefs_set_string: %s not a string pref\n", name);
-			return;
-		}
-
-		if (!purple_strequal(pref->value.string, value)) {
-			g_free(pref->value.string);
-			pref->value.string = g_strdup(value);
-			do_callbacks(name, pref);
-		}
-	} else {
-		purple_prefs_add_string(name, value);
-	}
-}
-
-void
-purple_prefs_set_string_list(const char *name, GList *value)
-{
-	struct purple_pref *pref = find_pref(name);
-	if(pref) {
-		GList *tmp;
-
-		if(pref->type != PURPLE_PREF_STRING_LIST) {
-			purple_debug_error("prefs",
-					"purple_prefs_set_string_list: %s not a string list pref\n",
-					name);
-			return;
-		}
-
-		g_list_foreach(pref->value.stringlist, (GFunc)g_free, NULL);
-		g_list_free(pref->value.stringlist);
-		pref->value.stringlist = NULL;
-
-		for(tmp = value; tmp; tmp = tmp->next) {
-			if(tmp->data != NULL && !g_utf8_validate(tmp->data, -1, NULL)) {
-				purple_debug_error("prefs", "purple_prefs_set_string_list: Skipping invalid UTF8 for string list pref %s\n", name);
-				continue;
-			}
-			pref->value.stringlist = g_list_prepend(pref->value.stringlist,
-					g_strdup(tmp->data));
-		}
-		pref->value.stringlist = g_list_reverse(pref->value.stringlist);
-
-		do_callbacks(name, pref);
-
-	} else {
-		purple_prefs_add_string_list(name, value);
-	}
-}
-
-void
-purple_prefs_set_path(const char *name, const char *value)
-{
-	struct purple_pref *pref = find_pref(name);
-
-	if(pref) {
-		if(pref->type != PURPLE_PREF_PATH) {
-			purple_debug_error("prefs",
-					"purple_prefs_set_path: %s not a path pref\n", name);
-			return;
-		}
-
-		if (!purple_strequal(pref->value.string, value)) {
-			g_free(pref->value.string);
-			pref->value.string = g_strdup(value);
-			do_callbacks(name, pref);
-		}
-	} else {
-		purple_prefs_add_path(name, value);
-	}
-}
-
-void
-purple_prefs_set_path_list(const char *name, GList *value)
-{
-	struct purple_pref *pref = find_pref(name);
-	if(pref) {
-		GList *tmp;
-
-		if(pref->type != PURPLE_PREF_PATH_LIST) {
-			purple_debug_error("prefs",
-					"purple_prefs_set_path_list: %s not a path list pref\n",
-					name);
-			return;
-		}
-
-		g_list_foreach(pref->value.stringlist, (GFunc)g_free, NULL);
-		g_list_free(pref->value.stringlist);
-		pref->value.stringlist = NULL;
-
-		for(tmp = value; tmp; tmp = tmp->next)
-			pref->value.stringlist = g_list_prepend(pref->value.stringlist,
-					g_strdup(tmp->data));
-		pref->value.stringlist = g_list_reverse(pref->value.stringlist);
-
-		do_callbacks(name, pref);
-
-	} else {
-		purple_prefs_add_path_list(name, value);
-	}
-}
-
+	UIOP(set_string(name, value))
 
 gboolean
 purple_prefs_exists(const char *name)
-{
-	struct purple_pref *pref = find_pref(name);
-
-	if (pref != NULL)
-		return TRUE;
-
-	return FALSE;
-}
+	UIOP_return(exists(name), FALSE)
 
 PurplePrefType
 purple_prefs_get_type(const char *name)
-{
-	struct purple_pref *pref = find_pref(name);
-
-	if (pref == NULL)
-		return PURPLE_PREF_NONE;
-
-	return (pref->type);
-}
+	UIOP_return(get_type(name), PURPLE_PREF_NONE)
 
 gboolean
 purple_prefs_get_bool(const char *name)
-{
-	struct purple_pref *pref = find_pref(name);
-
-	if(!pref) {
-		purple_debug_error("prefs",
-				"purple_prefs_get_bool: Unknown pref %s\n", name);
-		return FALSE;
-	} else if(pref->type != PURPLE_PREF_BOOLEAN) {
-		purple_debug_error("prefs",
-				"purple_prefs_get_bool: %s not a boolean pref\n", name);
-		return FALSE;
-	}
-
-	return pref->value.boolean;
-}
+	UIOP_return(get_bool(name), FALSE)
 
 int
 purple_prefs_get_int(const char *name)
-{
-	struct purple_pref *pref = find_pref(name);
-
-	if(!pref) {
-		purple_debug_error("prefs",
-				"purple_prefs_get_int: Unknown pref %s\n", name);
-		return 0;
-	} else if(pref->type != PURPLE_PREF_INT) {
-		purple_debug_error("prefs",
-				"purple_prefs_get_int: %s not an integer pref\n", name);
-		return 0;
-	}
-
-	return pref->value.integer;
-}
+	UIOP_return(get_int(name), 0)
 
 const char *
 purple_prefs_get_string(const char *name)
-{
-	struct purple_pref *pref = find_pref(name);
-
-	if(!pref) {
-		purple_debug_error("prefs",
-				"purple_prefs_get_string: Unknown pref %s\n", name);
-		return NULL;
-	} else if(pref->type != PURPLE_PREF_STRING) {
-		purple_debug_error("prefs",
-				"purple_prefs_get_string: %s not a string pref\n", name);
-		return NULL;
-	}
+	UIOP_return(get_string(name), NULL)
 
-	return pref->value.string;
-}
-
-GList *
-purple_prefs_get_string_list(const char *name)
+guint
+purple_prefs_connect_callback(void *handle, const char *name, PurplePrefCallback func, gpointer data)
 {
-	struct purple_pref *pref = find_pref(name);
-	GList *ret = NULL, *tmp;
-
-	if(!pref) {
-		purple_debug_error("prefs",
-				"purple_prefs_get_string_list: Unknown pref %s\n", name);
-		return NULL;
-	} else if(pref->type != PURPLE_PREF_STRING_LIST) {
-		purple_debug_error("prefs",
-				"purple_prefs_get_string_list: %s not a string list pref\n", name);
-		return NULL;
-	}
-
-	for(tmp = pref->value.stringlist; tmp; tmp = tmp->next)
-		ret = g_list_prepend(ret, g_strdup(tmp->data));
-	ret = g_list_reverse(ret);
+	struct pref_cb *cb;
+	static guint cb_id = 0;
+	PurplePrefsUiOps *uiop = NULL;
 
-	return ret;
-}
+	g_return_val_if_fail(name != NULL, 0);
+	g_return_val_if_fail(func != NULL, 0);
 
-const char *
-purple_prefs_get_path(const char *name)
-{
-	struct purple_pref *pref = find_pref(name);
+	uiop = purple_prefs_get_ui_ops();
+	g_return_val_if_fail(uiop, 0);
 
-	if(!pref) {
-		purple_debug_error("prefs",
-				"purple_prefs_get_path: Unknown pref %s\n", name);
-		return NULL;
-	} else if(pref->type != PURPLE_PREF_PATH) {
-		purple_debug_error("prefs",
-				"purple_prefs_get_path: %s not a path pref\n", name);
-		return NULL;
-	}
+	cb = g_new0(struct pref_cb, 1);
 
-	return pref->value.string;
-}
+	cb->func = func;
+	cb->data = data;
+	cb->id = ++cb_id;
+	cb->handle = handle;
+	cb->name = g_strdup(name);
 
-GList *
-purple_prefs_get_path_list(const char *name)
-{
-	struct purple_pref *pref = find_pref(name);
-	GList *ret = NULL, *tmp;
+	cb->observer = uiop->add_observer(name, cb);
 
-	if(!pref) {
-		purple_debug_error("prefs",
-				"purple_prefs_get_path_list: Unknown pref %s\n", name);
-		return NULL;
-	} else if(pref->type != PURPLE_PREF_PATH_LIST) {
-		purple_debug_error("prefs",
-				"purple_prefs_get_path_list: %s not a path list pref\n", name);
-		return NULL;
+	if (cb->observer == NULL) {
+		purple_debug_error("prefs", "purple_prefs_connect_callback: add observer failed for %s\n", name);
+		g_free(cb->name);
+		g_free(cb);
+		return 0;
 	}
 
-	for(tmp = pref->value.stringlist; tmp; tmp = tmp->next)
-		ret = g_list_prepend(ret, g_strdup(tmp->data));
-	ret = g_list_reverse(ret);
-
-	return ret;
+	callbacks = g_slist_append(callbacks, cb);
+	return cb->id;
 }
 
-static void
-purple_prefs_rename_node(struct purple_pref *oldpref, struct purple_pref *newpref)
+void purple_prefs_observe(gpointer data)
 {
-	struct purple_pref *child, *next;
-	char *oldname, *newname;
+	struct pref_cb *cb = data;
+	PurplePrefsUiOps *uiop = purple_prefs_get_ui_ops();
+	gconstpointer value = NULL;
+	PurplePrefType type = PURPLE_PREF_NONE;
+	type = uiop->get_type(cb->name);
 
-	/* if we're a parent, rename the kids first */
-	for(child = oldpref->first_child; child != NULL; child = next)
-	{
-		struct purple_pref *newchild;
-		next = child->sibling;
-		for(newchild = newpref->first_child; newchild != NULL; newchild = newchild->sibling)
-		{
-			if(purple_strequal(child->name, newchild->name))
-			{
-				purple_prefs_rename_node(child, newchild);
-				break;
-			}
-		}
-		if(newchild == NULL) {
-			/* no rename happened, we weren't able to find the new pref */
-			char *tmpname = pref_full_name(child);
-			purple_debug_error("prefs", "Unable to find rename pref for %s\n", tmpname);
-			g_free(tmpname);
-		}
-	}
-
-	oldname = pref_full_name(oldpref);
-	newname = pref_full_name(newpref);
-
-	if (oldpref->type != newpref->type)
-	{
-		purple_debug_error("prefs", "Unable to rename %s to %s: differing types\n", oldname, newname);
-		g_free(oldname);
-		g_free(newname);
-		return;
-	}
+	purple_debug_misc("prefs", "observe name = %s\n", cb->name);
 
-	purple_debug_info("prefs", "Renaming %s to %s\n", oldname, newname);
-	g_free(oldname);
-
-	switch(oldpref->type) {
-		case PURPLE_PREF_NONE:
+	switch (type) {
+		case PURPLE_PREF_INT:
+			value = GINT_TO_POINTER(uiop->get_int(cb->name));
 			break;
 		case PURPLE_PREF_BOOLEAN:
-			purple_prefs_set_bool(newname, oldpref->value.boolean);
-			break;
-		case PURPLE_PREF_INT:
-			purple_prefs_set_int(newname, oldpref->value.integer);
+			value = GINT_TO_POINTER(uiop->get_bool(cb->name));
 			break;
 		case PURPLE_PREF_STRING:
-			purple_prefs_set_string(newname, oldpref->value.string);
-			break;
-		case PURPLE_PREF_STRING_LIST:
-			purple_prefs_set_string_list(newname, oldpref->value.stringlist);
+			value = uiop->get_string(cb->name);
 			break;
-		case PURPLE_PREF_PATH:
-			purple_prefs_set_path(newname, oldpref->value.string);
-			break;
-		case PURPLE_PREF_PATH_LIST:
-			purple_prefs_set_path_list(newname, oldpref->value.stringlist);
+		case PURPLE_PREF_NONE:
 			break;
+		default:
+			purple_debug_error("prefs", "Unexpected type = %i\n", type);
 	}
-	g_free(newname);
-
-	remove_pref(oldpref);
+	cb->func(cb->name, type, value, cb->data);
 }
 
 void
-purple_prefs_rename(const char *oldname, const char *newname)
-{
-	struct purple_pref *oldpref, *newpref;
-
-	oldpref = find_pref(oldname);
-
-	/* it's already been renamed, call off the dogs */
-	if(!oldpref)
-		return;
-
-	newpref = find_pref(newname);
-
-	if (newpref == NULL)
-	{
-		purple_debug_error("prefs", "Unable to rename %s to %s: new pref not created\n", oldname, newname);
-		return;
-	}
-
-	purple_prefs_rename_node(oldpref, newpref);
-}
-
-void
-purple_prefs_rename_boolean_toggle(const char *oldname, const char *newname)
-{
-		struct purple_pref *oldpref, *newpref;
-
-		oldpref = find_pref(oldname);
-
-		/* it's already been renamed, call off the cats */
-		if(!oldpref)
-			return;
-
-		if (oldpref->type != PURPLE_PREF_BOOLEAN)
-		{
-			purple_debug_error("prefs", "Unable to rename %s to %s: old pref not a boolean\n", oldname, newname);
-			return;
-		}
-
-		if (oldpref->first_child != NULL) /* can't rename parents */
-		{
-			purple_debug_error("prefs", "Unable to rename %s to %s: can't rename parents\n", oldname, newname);
-			return;
-		}
-
-
-		newpref = find_pref(newname);
-
-		if (newpref == NULL)
-		{
-			purple_debug_error("prefs", "Unable to rename %s to %s: new pref not created\n", oldname, newname);
-			return;
-		}
-
-		if (oldpref->type != newpref->type)
-		{
-			purple_debug_error("prefs", "Unable to rename %s to %s: differing types\n", oldname, newname);
-			return;
-		}
-
-		purple_debug_info("prefs", "Renaming and toggling %s to %s\n", oldname, newname);
-		purple_prefs_set_bool(newname, !(oldpref->value.boolean));
-
-		remove_pref(oldpref);
-}
-
-guint
-purple_prefs_connect_callback(void *handle, const char *name, PurplePrefCallback func, gpointer data)
-{
-	struct purple_pref *pref;
-	struct pref_cb *cb;
-	static guint cb_id = 0;
-
-	g_return_val_if_fail(name != NULL, 0);
-	g_return_val_if_fail(func != NULL, 0);
-
-	pref = find_pref(name);
-	if (pref == NULL) {
-		purple_debug_error("prefs", "purple_prefs_connect_callback: Unknown pref %s\n", name);
-		return 0;
-	}
-
-	cb = g_new0(struct pref_cb, 1);
-
-	cb->func = func;
-	cb->data = data;
-	cb->id = ++cb_id;
-	cb->handle = handle;
-
-	pref->callbacks = g_slist_append(pref->callbacks, cb);
-
-	return cb->id;
-}
-
-static gboolean
-disco_callback_helper(struct purple_pref *pref, guint callback_id)
+purple_prefs_disconnect_callback(guint callback_id)
 {
 	GSList *cbs;
-	struct purple_pref *child;
-
-	if(!pref)
-		return FALSE;
 
-	for(cbs = pref->callbacks; cbs; cbs = cbs->next) {
+	for (cbs = callbacks; cbs; cbs = cbs->next) {
 		struct pref_cb *cb = cbs->data;
-		if(cb->id == callback_id) {
-			pref->callbacks = g_slist_delete_link(pref->callbacks, cbs);
+		if (cb->id == callback_id) {
+			PurplePrefsUiOps *uiop = purple_prefs_get_ui_ops();
+			uiop->remove_observer(cb->name, cb->observer);
+
+			callbacks = g_slist_delete_link(callbacks, cbs);
+			g_free(cb->name);
 			g_free(cb);
-			return TRUE;
+			return;
 		}
 	}
-
-	for(child = pref->first_child; child; child = child->sibling) {
-		if(disco_callback_helper(child, callback_id))
-			return TRUE;
-	}
-
-	return FALSE;
 }
 
 void
-purple_prefs_disconnect_callback(guint callback_id)
-{
-	disco_callback_helper(&prefs, callback_id);
-}
-
-static void
-disco_callback_helper_handle(struct purple_pref *pref, void *handle)
+purple_prefs_disconnect_by_handle(void *handle)
 {
 	GSList *cbs;
-	struct purple_pref *child;
 
-	if(!pref)
-		return;
+	g_return_if_fail(handle != NULL);
 
-	cbs = pref->callbacks;
+	cbs = callbacks;
 	while (cbs != NULL) {
+		PurplePrefsUiOps *uiop;
 		struct pref_cb *cb = cbs->data;
-		if(cb->handle == handle) {
-			pref->callbacks = g_slist_delete_link(pref->callbacks, cbs);
-			g_free(cb);
-			cbs = pref->callbacks;
-		} else
+		if (cb->handle != handle) {
 			cbs = cbs->next;
-	}
-
-	for(child = pref->first_child; child; child = child->sibling)
-		disco_callback_helper_handle(child, handle);
-}
+			continue;
+		}
 
-void
-purple_prefs_disconnect_by_handle(void *handle)
-{
-	g_return_if_fail(handle != NULL);
+		uiop = purple_prefs_get_ui_ops();
+		uiop->remove_observer(cb->name, cb->observer);
 
-	disco_callback_helper_handle(&prefs, handle);
+		callbacks = g_slist_delete_link(callbacks, cbs);
+		g_free(cb->name);
+		g_free(cb);
+		cbs = callbacks;
+	}
 }
 
 GList *
 purple_prefs_get_children_names(const char *name)
-{
-	GList * list = NULL;
-	struct purple_pref *pref = find_pref(name), *child;
-	char sep[2] = "\0\0";;
-
-	if (pref == NULL)
-		return NULL;
-
-	if (name[strlen(name) - 1] != '/')
-		sep[0] = '/';
-	for (child = pref->first_child; child; child = child->sibling) {
-		list = g_list_append(list, g_strdup_printf("%s%s%s", name, sep, child->name));
-	}
-	return list;
-}
-
-void
-purple_prefs_update_old()
-{
-	purple_prefs_rename("/core", "/purple");
-
-	/* Remove some no-longer-used prefs */
-	purple_prefs_remove("/purple/away/auto_response/enabled");
-	purple_prefs_remove("/purple/away/auto_response/idle_only");
-	purple_prefs_remove("/purple/away/auto_response/in_active_conv");
-	purple_prefs_remove("/purple/away/auto_response/sec_before_resend");
-	purple_prefs_remove("/purple/away/auto_response");
-	purple_prefs_remove("/purple/away/default_message");
-	purple_prefs_remove("/purple/buddies/use_server_alias");
-	purple_prefs_remove("/purple/conversations/away_back_on_send");
-	purple_prefs_remove("/purple/conversations/send_urls_as_links");
-	purple_prefs_remove("/purple/conversations/im/show_login");
-	purple_prefs_remove("/purple/conversations/chat/show_join");
-	purple_prefs_remove("/purple/conversations/chat/show_leave");
-	purple_prefs_remove("/purple/conversations/combine_chat_im");
-	purple_prefs_remove("/purple/conversations/use_alias_for_title");
-	purple_prefs_remove("/purple/logging/log_signon_signoff");
-	purple_prefs_remove("/purple/logging/log_idle_state");
-	purple_prefs_remove("/purple/logging/log_away_state");
-	purple_prefs_remove("/purple/logging/log_own_states");
-	purple_prefs_remove("/purple/status/scores/hidden");
-	purple_prefs_remove("/plugins/core/autorecon/hide_connected_error");
-	purple_prefs_remove("/plugins/core/autorecon/hide_connecting_error");
-	purple_prefs_remove("/plugins/core/autorecon/hide_reconnecting_dialog");
-	purple_prefs_remove("/plugins/core/autorecon/restore_state");
-	purple_prefs_remove("/plugins/core/autorecon");
-
-	/* Convert old sounds while_away pref to new 3-way pref. */
-	if (purple_prefs_exists("/purple/sound/while_away") &&
-	    purple_prefs_get_bool("/purple/sound/while_away"))
-	{
-		purple_prefs_set_int("/purple/sound/while_status", 3);
-	}
-	purple_prefs_remove("/purple/sound/while_away");
-}
+	UIOP_return(get_children_names(name), NULL)
 
 void *
 purple_prefs_get_handle(void)
@@ -1390,8 +309,6 @@
 {
 	void *handle = purple_prefs_get_handle();
 
-	prefs_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
-
 	purple_prefs_connect_callback(handle, "/", prefs_save_cb, NULL);
 
 	purple_prefs_add_none("/purple");
@@ -1402,34 +319,7 @@
 
 	/* Away */
 	purple_prefs_add_none("/purple/away");
-	purple_prefs_add_string("/purple/away/idle_reporting", "system");
-	purple_prefs_add_bool("/purple/away/away_when_idle", TRUE);
-	purple_prefs_add_int("/purple/away/mins_before_away", 5);
-
-	/* Away -> Auto-Reply */
-	if (!purple_prefs_exists("/purple/away/auto_response/enabled") ||
-	    !purple_prefs_exists("/purple/away/auto_response/idle_only"))
-	{
-		purple_prefs_add_string("/purple/away/auto_reply", "awayidle");
-	}
-	else
-	{
-		if (!purple_prefs_get_bool("/purple/away/auto_response/enabled"))
-		{
-			purple_prefs_add_string("/purple/away/auto_reply", "never");
-		}
-		else
-		{
-			if (purple_prefs_get_bool("/purple/away/auto_response/idle_only"))
-			{
-				purple_prefs_add_string("/purple/away/auto_reply", "awayidle");
-			}
-			else
-			{
-				purple_prefs_add_string("/purple/away/auto_reply", "away");
-			}
-		}
-	}
+	purple_prefs_add_string("/purple/away/auto_reply", "awayidle");
 
 	/* Buddies */
 	purple_prefs_add_none("/purple/buddies");
@@ -1442,7 +332,6 @@
 	purple_prefs_remove("/purple/contact/idle_score");
 
 	purple_prefs_load();
-	purple_prefs_update_old();
 }
 
 void
@@ -1451,15 +340,22 @@
 	if (save_timer != 0)
 	{
 		purple_timeout_remove(save_timer);
-		save_timer = 0;
-		sync_prefs();
+		save_cb(NULL);
 	}
 
 	purple_prefs_disconnect_by_handle(purple_prefs_get_handle());
 
 	prefs_loaded = FALSE;
-	purple_prefs_destroy();
-	g_hash_table_destroy(prefs_hash);
-	prefs_hash = NULL;
+}
 
+void
+purple_prefs_set_ui_ops(PurplePrefsUiOps *ops)
+{
+	prefs_ui_ops = ops;
+}
+
+PurplePrefsUiOps *
+purple_prefs_get_ui_ops(void)
+{
+	return prefs_ui_ops;
 }
diff -ru extract/pidgin-2.10.11/libpurple/prefs.h libpurple/prefs.h
--- extract/pidgin-2.10.11/libpurple/prefs.h	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/prefs.h	2015-03-19 23:21:15.000000000 -0400
@@ -38,6 +38,8 @@
 	PURPLE_PREF_BOOLEAN,     /**< Boolean.         */
 	PURPLE_PREF_INT,         /**< Integer.         */
 	PURPLE_PREF_STRING,      /**< String.          */
+	/* The 3 following types are unused in libpurple,
+	   and not implemented in Instantbird */
 	PURPLE_PREF_STRING_LIST, /**< List of strings. */
 	PURPLE_PREF_PATH,        /**< Path.            */
 	PURPLE_PREF_PATH_LIST    /**< List of paths.   */
@@ -62,11 +64,71 @@
 typedef void (*PurplePrefCallback) (const char *name, PurplePrefType type,
 		gconstpointer val, gpointer data);
 
+
+/** @copydoc _PurplePrefsUiOps */
+typedef struct _PurplePrefsUiOps PurplePrefsUiOps;
+
+
+/**  Prefs UI operations
+ */
+struct _PurplePrefsUiOps
+{
+	void (*add_none)(const char *name);
+	void (*add_bool)(const char *name, gboolean value);
+	void (*add_int)(const char *name, int value);
+	void (*add_string)(const char *name, const char *value);
+
+	void (*set_bool)(const char *name, gboolean value);
+	void (*set_int)(const char *name, int value);
+	void (*set_string)(const char *name, const char *value);
+
+	gboolean (*get_bool)(const char *name);
+	int (*get_int)(const char *name);
+	const char *(*get_string)(const char *name);
+
+	PurplePrefType (*get_type)(const char *name);
+	GList *(*get_children_names)(const char *name);
+
+	gboolean (*exists)(const char *name);
+	void (*remove)(const char *name);
+
+	void (*save)(void);
+
+	void *(*add_observer)(const char *name, gpointer data);
+	void (*remove_observer)(const char *name, void *observer);
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /**************************************************************************/
+/** @name UI Registration Functions                                       */
+/**************************************************************************/
+/*@{*/
+/**
+ * Sets the UI operations structure to be used for preferences.
+ *
+ * @param ops The UI operations structure.
+ */
+void purple_prefs_set_ui_ops(PurplePrefsUiOps *ops);
+
+/**
+ * Returns the UI operations structure used for preferences.
+ *
+ * @return The UI operations structure in use.
+ */
+PurplePrefsUiOps *purple_prefs_get_ui_ops(void);
+
+/*@}*/
+
+/**************************************************************************/
 /** @name Prefs API
     Preferences are named according to a directory-like structure.
     Example: "/plugins/core/potato/is_from_idaho" (probably a boolean)    */
@@ -122,37 +184,6 @@
 void purple_prefs_add_string(const char *name, const char *value);
 
 /**
- * Add a new string list pref.
- *
- * @param name  The name of the pref
- * @param value The initial value to set
- * @note This function takes a copy of the strings in the value list. The list
- *       itself and original copies of the strings are up to the caller to
- *       free.
- */
-void purple_prefs_add_string_list(const char *name, GList *value);
-
-/**
- * Add a new path pref.
- *
- * @param name  The name of the pref
- * @param value The initial value to set
- */
-void purple_prefs_add_path(const char *name, const char *value);
-
-/**
- * Add a new path list pref.
- *
- * @param name  The name of the pref
- * @param value The initial value to set
- * @note This function takes a copy of the strings in the value list. The list
- *       itself and original copies of the strings are up to the caller to
- *       free.
- */
-void purple_prefs_add_path_list(const char *name, GList *value);
-
-
-/**
  * Remove a pref.
  *
  * @param name The name of the pref
@@ -160,44 +191,6 @@
 void purple_prefs_remove(const char *name);
 
 /**
- * Rename a pref
- *
- * @param oldname The old name of the pref
- * @param newname The new name for the pref
- */
-void purple_prefs_rename(const char *oldname, const char *newname);
-
-/**
- * Rename a boolean pref, toggling it's value
- *
- * @param oldname The old name of the pref
- * @param newname The new name for the pref
- */
-void purple_prefs_rename_boolean_toggle(const char *oldname, const char *newname);
-
-/**
- * Remove all prefs.
- */
-void purple_prefs_destroy(void);
-
-/**
- * Set raw pref value
- *
- * @param name  The name of the pref
- * @param value The value to set
- *
- * @deprecated We're not really sure what purpose this function serves, so it
- *             will be removed in 3.0.0.  Preferences values set using this
- *             function aren't serialized to prefs.xml, which could be
- *             misleading.  There is also no purple_prefs_get_generic, which
- *             means that if you can't really get the value (other in a
- *             connected callback).  If you think you have a use for this then
- *             please let us know.
- */
-/* TODO: When this is removed, also remove struct purple_pref->value.generic */
-void purple_prefs_set_generic(const char *name, gpointer value);
-
-/**
  * Set boolean pref value
  *
  * @param name  The name of the pref
@@ -221,30 +214,6 @@
  */
 void purple_prefs_set_string(const char *name, const char *value);
 
-/**
- * Set string list pref value
- *
- * @param name  The name of the pref
- * @param value The value to set
- */
-void purple_prefs_set_string_list(const char *name, GList *value);
-
-/**
- * Set path pref value
- *
- * @param name  The name of the pref
- * @param value The value to set
- */
-void purple_prefs_set_path(const char *name, const char *value);
-
-/**
- * Set path list pref value
- *
- * @param name  The name of the pref
- * @param value The value to set
- */
-void purple_prefs_set_path_list(const char *name, GList *value);
-
 
 /**
  * Check if a pref exists
@@ -287,30 +256,6 @@
 const char *purple_prefs_get_string(const char *name);
 
 /**
- * Get string list pref value
- *
- * @param name The name of the pref
- * @return The value of the pref
- */
-GList *purple_prefs_get_string_list(const char *name);
-
-/**
- * Get path pref value
- *
- * @param name The name of the pref
- * @return The value of the pref
- */
-const char *purple_prefs_get_path(const char *name);
-
-/**
- * Get path list pref value
- *
- * @param name The name of the pref
- * @return The value of the pref
- */
-GList *purple_prefs_get_path_list(const char *name);
-
-/**
  * Returns a list of children for a pref
  *
  * @param name The parent pref
@@ -338,6 +283,11 @@
 		gpointer data);
 
 /**
+ * Call the callback of the observer
+ */
+void purple_prefs_observe(gpointer data);
+
+/**
  * Remove a callback to a pref
  */
 void purple_prefs_disconnect_callback(guint callback_id);
@@ -357,11 +307,6 @@
  */
 gboolean purple_prefs_load(void);
 
-/**
- * Rename legacy prefs and delete some that no longer exist.
- */
-void purple_prefs_update_old(void);
-
 /*@}*/
 
 #ifdef __cplusplus
Only in libpurple/protocols/bonjour: Makefile.in
Only in libpurple/protocols/bonjour: moz.build
Only in libpurple/protocols/bonjour: win32
Only in libpurple/protocols: create-cid.sh
Only in libpurple/protocols/gg: Makefile.in
Only in libpurple/protocols/gg: moz.build
Only in libpurple/protocols/jabber: Makefile.in
Only in extract/pidgin-2.10.11/libpurple/protocols/jabber: auth_cyrus.c
diff -ru extract/pidgin-2.10.11/libpurple/protocols/jabber/buddy.c libpurple/protocols/jabber/buddy.c
--- extract/pidgin-2.10.11/libpurple/protocols/jabber/buddy.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/jabber/buddy.c	2015-03-19 23:21:15.000000000 -0400
@@ -131,9 +131,6 @@
 	const JabberBuddyResource *jbrb = b;
 	JabberBuddyState state_a, state_b;
 
-	if (jbra->priority != jbrb->priority)
-		return jbra->priority > jbrb->priority ? -1 : 1;
-
 	/* Fold the states for easier comparison */
 	/* TODO: Differentiate online/chat and away/dnd? */
 	switch (jbra->state) {
@@ -177,6 +174,9 @@
 	}
 
 	if (state_a == state_b) {
+		if (jbra->priority != jbrb->priority)
+			return jbra->priority > jbrb->priority ? -1 : 1;
+
 		if (jbra->idle == jbrb->idle)
 			return 0;
 		else if ((jbra->idle && !jbrb->idle) ||
diff -ru extract/pidgin-2.10.11/libpurple/protocols/jabber/disco.c libpurple/protocols/jabber/disco.c
--- extract/pidgin-2.10.11/libpurple/protocols/jabber/disco.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/jabber/disco.c	2015-03-19 23:21:15.000000000 -0400
@@ -35,7 +35,9 @@
 #include "google/jingleinfo.h"
 #include "iq.h"
 #include "jabber.h"
+#ifdef USE_JINGLE
 #include "jingle/jingle.h"
+#endif
 #include "pep.h"
 #include "presence.h"
 #include "roster.h"
diff -ru extract/pidgin-2.10.11/libpurple/protocols/jabber/google/google_session.c libpurple/protocols/jabber/google/google_session.c
--- extract/pidgin-2.10.11/libpurple/protocols/jabber/google/google_session.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/jabber/google/google_session.c	2015-03-19 23:21:15.000000000 -0400
@@ -23,10 +23,10 @@
 #include "google_session.h"
 #include "relay.h"
 
-#include "jingle/jingle.h"
-
 #ifdef USE_VV
 
+#include "jingle/jingle.h"
+
 typedef struct {
 	PurpleMedia *media;
 	gboolean video;
diff -ru extract/pidgin-2.10.11/libpurple/protocols/jabber/iq.c libpurple/protocols/jabber/iq.c
--- extract/pidgin-2.10.11/libpurple/protocols/jabber/iq.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/jabber/iq.c	2015-03-20 00:15:22.000000000 -0400
@@ -33,7 +33,9 @@
 #include "google/jingleinfo.h"
 #include "google/google_session.h"
 #include "iq.h"
+#ifdef USE_JINGLE
 #include "jingle/jingle.h"
+#endif
 #include "oob.h"
 #include "roster.h"
 #include "si.h"
@@ -43,7 +45,7 @@
 #include "ibb.h"
 
 #ifdef _WIN32
-#include "utsname.h"
+#include "win32/utsname.h"
 #endif
 
 static GHashTable *iq_handlers = NULL;
@@ -560,7 +562,9 @@
 	iq_handlers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
 	signal_iq_handlers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
 
+#ifdef USE_JINGLE
 	jabber_iq_register_handler("jingle", JINGLE, jingle_parse);
+#endif
 	jabber_iq_register_handler("mailbox", NS_GOOGLE_MAIL_NOTIFY,
 			jabber_gmail_poke);
 	jabber_iq_register_handler("new-mail", NS_GOOGLE_MAIL_NOTIFY,
diff -ru extract/pidgin-2.10.11/libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/jabber.c
--- extract/pidgin-2.10.11/libpurple/protocols/jabber/jabber.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/jabber/jabber.c	2015-03-20 00:15:22.000000000 -0400
@@ -69,8 +69,10 @@
 #include "pep.h"
 #include "adhoccommands.h"
 
+#ifdef USE_JINGLE
 #include "jingle/jingle.h"
 #include "jingle/rtp.h"
+#endif
 
 #define PING_TIMEOUT 60
 /* Send a whitespace keepalive to the server if we haven't sent
@@ -1597,8 +1599,10 @@
 {
 	JabberStream *js = purple_connection_get_protocol_data(gc);
 
+#ifdef USE_JINGLE
 	/* Close all of the open Jingle sessions on this stream */
 	jingle_terminate_sessions(js);
+#endif
 
 	if (js->bosh)
 		jabber_bosh_connection_close(js->bosh);
@@ -3874,8 +3878,10 @@
 	/* Bits Of Binary */
 	jabber_add_feature(NS_BOB, 0);
 
+#ifdef USE_JINGLE
 	/* Jingle features! */
 	jabber_add_feature(JINGLE, 0);
+#endif
 
 #ifdef USE_VV
 	jabber_add_feature(NS_GOOGLE_PROTOCOL_SESSION, jabber_audio_enabled);
diff -ru extract/pidgin-2.10.11/libpurple/protocols/jabber/jabber.h libpurple/protocols/jabber/jabber.h
--- extract/pidgin-2.10.11/libpurple/protocols/jabber/jabber.h	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/jabber/jabber.h	2015-03-20 00:15:22.000000000 -0400
@@ -62,8 +62,10 @@
 #include "connection.h"
 #include "dnsquery.h"
 #include "dnssrv.h"
+#ifdef USE_VV
 #include "media.h"
 #include "mediamanager.h"
+#endif
 #include "roomlist.h"
 #include "sslconn.h"
 
diff -ru extract/pidgin-2.10.11/libpurple/protocols/jabber/libxmpp.c libpurple/protocols/jabber/libxmpp.c
--- extract/pidgin-2.10.11/libpurple/protocols/jabber/libxmpp.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/jabber/libxmpp.c	2015-03-19 23:21:15.000000000 -0400
@@ -258,11 +258,11 @@
 	GList *encryption_values = NULL;
 
 	/* Translators: 'domain' is used here in the context of Internet domains, e.g. pidgin.im */
-	split = purple_account_user_split_new(_("Domain"), NULL, '@');
+	split = purple_account_user_split_new(_("Domain"), "jabber.org", '@');
 	purple_account_user_split_set_reverse(split, FALSE);
 	prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
 
-	split = purple_account_user_split_new(_("Resource"), "", '/');
+	split = purple_account_user_split_new(_("Resource"), "Instantbird", '/');
 	purple_account_user_split_set_reverse(split, FALSE);
 	prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
 
@@ -315,13 +315,6 @@
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
 						  option);
 
-	/* this should probably be part of global smiley theme settings later on,
-	  shared with MSN */
-	option = purple_account_option_bool_new(_("Show Custom Smileys"),
-		"custom_smileys", TRUE);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
-		option);
-
 	my_protocol = plugin;
 
 	purple_prefs_remove("/plugins/prpl/jabber");
diff -ru extract/pidgin-2.10.11/libpurple/protocols/jabber/message.c libpurple/protocols/jabber/message.c
--- extract/pidgin-2.10.11/libpurple/protocols/jabber/message.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/jabber/message.c	2015-03-19 23:21:15.000000000 -0400
@@ -106,7 +106,8 @@
 					 * this should be able to be implemented by removing the
 					 * user from the conversation like we do with chats now. */
 					purple_conversation_write(conv, "", buf,
-					                        PURPLE_MESSAGE_SYSTEM, time(NULL));
+					                          PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LINKIFY,
+					                          time(NULL));
 				}
 			}
 			serv_got_typing_stopped(gc, jm->from);
@@ -602,7 +603,7 @@
 				GList *smiley_refs = NULL;
 				gchar *reformatted_xhtml;
 
-				if (purple_account_get_bool(account, "custom_smileys", TRUE)) {
+				if (purple_account_get_bool(account, "custom_smileys", FALSE)) {
 					/* find a list of smileys ("cid" and "alt" text pairs)
 					  occuring in the message */
 					smiley_refs = jabber_message_get_refs_from_xmlnode(child);
@@ -1303,5 +1304,5 @@
 	const PurpleConnection *gc = js->gc;
 	PurpleAccount *account = purple_connection_get_account(gc);
 
-	return purple_account_get_bool(account, "custom_smileys", TRUE);
+	return purple_account_get_bool(account, "custom_smileys", FALSE);
 }
Only in libpurple/protocols/jabber: moz.build
Only in libpurple/protocols: module.ver.in
Only in libpurple/protocols/msn: Makefile.in
Only in libpurple/protocols/msn: moz.build
diff -ru extract/pidgin-2.10.11/libpurple/protocols/msn/msg.c libpurple/protocols/msn/msg.c
--- extract/pidgin-2.10.11/libpurple/protocols/msn/msg.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/msn/msg.c	2015-03-20 00:15:22.000000000 -0400
@@ -819,6 +819,8 @@
 
 }
 
+#define purple_mkstemp(a, b) NULL
+
 /* TODO: Make these not be such duplicates of each other */
 static void
 got_wink_cb(MsnSlpCall *slpcall, const guchar *data, gsize size)
Only in libpurple/protocols/myspace: Makefile.in
Only in libpurple/protocols/myspace: moz.build
Only in libpurple/protocols: netsoul
Only in libpurple/protocols/novell: Makefile.in
Only in libpurple/protocols/novell: moz.build
diff -ru extract/pidgin-2.10.11/libpurple/protocols/novell/nmconn.c libpurple/protocols/novell/nmconn.c
--- extract/pidgin-2.10.11/libpurple/protocols/novell/nmconn.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/novell/nmconn.c	2015-03-19 23:21:15.000000000 -0400
@@ -19,7 +19,9 @@
  */
 
 #include <glib.h>
+#ifndef _MSC_VER
 #include <unistd.h>
+#endif
 #include <errno.h>
 #include <string.h>
 #include <ctype.h>
Only in libpurple/protocols/null: Makefile.in
Only in libpurple/protocols/null: moz.build
diff -ru extract/pidgin-2.10.11/libpurple/protocols/null/nullprpl.c libpurple/protocols/null/nullprpl.c
--- extract/pidgin-2.10.11/libpurple/protocols/null/nullprpl.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/null/nullprpl.c	2015-03-19 23:21:15.000000000 -0400
@@ -67,6 +67,9 @@
 #include "util.h"
 #include "version.h"
 
+/* Disable gettext for the null-prpl, it will never be translated... */
+#undef _
+#define _(String) (String)
 
 #define NULLPRPL_ID "prpl-null"
 static PurplePlugin *_null_protocol = NULL;
@@ -172,7 +175,8 @@
         !strcmp(status_id, NULL_STATUS_AWAY) ||
         !strcmp(status_id, NULL_STATUS_OFFLINE)) {
       purple_debug_info("nullprpl", "%s sees that %s is %s: %s\n",
-                        from_username, to_username, status_id, message);
+                        from_username, to_username, status_id,
+                        message ? message : "");
       purple_prpl_got_user_status(from->account, to_username, status_id,
                                   (message) ? "message" : NULL, message, NULL);
     } else {
@@ -364,6 +368,9 @@
 
   purple_debug_info("nullprpl", "logging in %s\n", acct->username);
 
+  if (!strcmp(acct->username, "crash@test"))
+    *((int *) NULL) = 42;
+
   purple_connection_update_progress(gc, _("Connecting"),
                                     0,   /* which connection step this is */
                                     2);  /* total number of steps */
@@ -522,8 +529,12 @@
 
 static void nullprpl_set_status(PurpleAccount *acct, PurpleStatus *status) {
   const char *msg = purple_status_get_attr_string(status, "message");
-  purple_debug_info("nullprpl", "setting %s's status to %s: %s\n",
-                    acct->username, purple_status_get_name(status), msg);
+  if (msg)
+    purple_debug_info("nullprpl", "setting %s's status to %s: %s\n",
+		      acct->username, purple_status_get_name(status), msg);
+  else
+    purple_debug_info("nullprpl", "setting %s's status to %s\n",
+		      acct->username, purple_status_get_name(status));
 
   foreach_nullprpl_gc(report_status_change, get_nullprpl_gc(acct->username),
                       NULL);
Only in libpurple/protocols/oscar: Makefile.in
diff -ru extract/pidgin-2.10.11/libpurple/protocols/oscar/authorization.c libpurple/protocols/oscar/authorization.c
--- extract/pidgin-2.10.11/libpurple/protocols/oscar/authorization.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/oscar/authorization.c	2015-03-19 23:21:15.000000000 -0400
@@ -93,12 +93,16 @@
 oscar_auth_dontgrant_msgprompt(gpointer cbdata)
 {
 	struct name_data *data = cbdata;
+#if 0
 	purple_request_input(data->gc, NULL, _("Authorization Denied Message:"),
 					   NULL, _("No reason given."), TRUE, FALSE, NULL,
 					   _("_OK"), G_CALLBACK(oscar_auth_dontgrant),
 					   _("_Cancel"), G_CALLBACK(oscar_free_name_data),
 					   purple_connection_get_account(data->gc), data->name, NULL,
 					   data);
+#else
+	oscar_auth_dontgrant(data, NULL);
+#endif
 }
 
 void
diff -ru extract/pidgin-2.10.11/libpurple/protocols/oscar/family_locate.c libpurple/protocols/oscar/family_locate.c
--- extract/pidgin-2.10.11/libpurple/protocols/oscar/family_locate.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/oscar/family_locate.c	2015-03-20 00:15:22.000000000 -0400
@@ -567,7 +567,7 @@
 aim_userinfo_t *aim_locate_finduserinfo(OscarData *od, const char *bn) {
 	aim_userinfo_t *cur = NULL;
 
-	if (bn == NULL)
+	if (bn == NULL || od == NULL)
 		return NULL;
 
 	cur = od->locate.userinfo;
diff -ru extract/pidgin-2.10.11/libpurple/protocols/oscar/libaim.c libpurple/protocols/oscar/libaim.c
--- extract/pidgin-2.10.11/libpurple/protocols/oscar/libaim.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/oscar/libaim.c	2015-03-19 23:21:15.000000000 -0400
@@ -142,10 +142,13 @@
 	NULL
 };
 
+gboolean purple_init_icq_plugin(void);
+
 static void
 init_plugin(PurplePlugin *plugin)
 {
 	oscar_init(plugin, FALSE);
+	purple_init_icq_plugin();
 }
 
-PURPLE_INIT_PLUGIN(aim, init_plugin, info);
+PURPLE_INIT_PLUGIN(oscar, init_plugin, info)
diff -ru extract/pidgin-2.10.11/libpurple/protocols/oscar/libicq.c libpurple/protocols/oscar/libicq.c
--- extract/pidgin-2.10.11/libpurple/protocols/oscar/libicq.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/oscar/libicq.c	2015-03-19 23:21:15.000000000 -0400
@@ -24,7 +24,9 @@
  * which contains all the shared implementation code with libaim
  */
 
-
+#ifndef PURPLE_STATIC_PRPL
+#define PURPLE_STATIC_PRPL
+#endif
 #include "oscarcommon.h"
 
 static GHashTable *
Only in libpurple/protocols/oscar: moz.build
diff -ru extract/pidgin-2.10.11/libpurple/protocols/oscar/oscar.c libpurple/protocols/oscar/oscar.c
--- extract/pidgin-2.10.11/libpurple/protocols/oscar/oscar.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/oscar/oscar.c	2015-03-20 00:15:22.000000000 -0400
@@ -350,7 +350,7 @@
 		flap_connection_send_version(od, conn);
 	else
 	{
-		if (purple_account_get_bool(account, "use_clientlogin", OSCAR_DEFAULT_USE_CLIENTLOGIN))
+		if (purple_account_get_bool(account, "use_clientlogin", od->icq ? ICQ_DEFAULT_USE_CLIENTLOGIN : AIM_DEFAULT_USE_CLIENTLOGIN))
 		{
 			ClientInfo aiminfo = CLIENTINFO_PURPLE_AIM;
 			ClientInfo icqinfo = CLIENTINFO_PURPLE_ICQ;
@@ -577,7 +577,7 @@
 
 	gc = data;
 	od = purple_connection_get_protocol_data(gc);
-	report_idle = strcmp((const char *)value, "none") != 0;
+	report_idle = GPOINTER_TO_INT(value);
 	presence = aim_ssi_getpresence(od->ssi.local);
 
 	if (report_idle)
@@ -765,7 +765,7 @@
 	od->use_ssl = purple_ssl_is_supported() && strcmp(encryption_type, OSCAR_NO_ENCRYPTION) != 0;
 
 	/* Connect to core Purple signals */
-	purple_prefs_connect_callback(gc, "/purple/away/idle_reporting", idle_reporting_pref_cb, gc);
+	purple_prefs_connect_callback(gc, "/messenger/status/reportIdle", idle_reporting_pref_cb, gc);
 	purple_prefs_connect_callback(gc, "/plugins/prpl/oscar/recent_buddies", recent_buddies_pref_cb, gc);
 
 	/*
@@ -778,7 +778,7 @@
 	 * This authentication method is used for both ICQ and AIM when
 	 * clientLogin is not enabled.
 	 */
-	if (purple_account_get_bool(account, "use_clientlogin", OSCAR_DEFAULT_USE_CLIENTLOGIN)) {
+	if (purple_account_get_bool(account, "use_clientlogin", od->icq ? ICQ_DEFAULT_USE_CLIENTLOGIN : AIM_DEFAULT_USE_CLIENTLOGIN)) {
 		send_client_login(od, purple_account_get_username(account));
 	} else {
 		FlapConnection *newconn;
@@ -3977,8 +3977,7 @@
 		const char *idle_reporting_pref;
 		gboolean report_idle;
 
-		idle_reporting_pref = purple_prefs_get_string("/purple/away/idle_reporting");
-		report_idle = strcmp(idle_reporting_pref, "none") != 0;
+		report_idle = purple_prefs_get_bool("/messenger/status/reportIdle");
 
 		if (report_idle)
 			aim_ssi_setpresence(od, tmp | AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
@@ -4020,7 +4019,8 @@
 					b = purple_find_buddy_in_group(account, curitem->name, g);
 					if (b) {
 						/* Get server stored alias */
-						purple_blist_alias_buddy(b, alias_utf8);
+						if (!purple_strequal(curitem->name, alias_utf8))
+							purple_blist_alias_buddy(b, alias_utf8);
 					} else {
 						b = purple_buddy_new(account, curitem->name, alias_utf8);
 
@@ -5762,7 +5762,7 @@
 	prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
 
 	option = purple_account_option_bool_new(_("Use clientLogin"), "use_clientlogin",
-			OSCAR_DEFAULT_USE_CLIENTLOGIN);
+			is_icq ? ICQ_DEFAULT_USE_CLIENTLOGIN : AIM_DEFAULT_USE_CLIENTLOGIN);
 	prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
 
 	option = purple_account_option_bool_new(
diff -ru extract/pidgin-2.10.11/libpurple/protocols/oscar/oscarcommon.h libpurple/protocols/oscar/oscarcommon.h
--- extract/pidgin-2.10.11/libpurple/protocols/oscar/oscarcommon.h	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/oscar/oscarcommon.h	2015-03-19 23:21:15.000000000 -0400
@@ -54,7 +54,8 @@
 #define OSCAR_DEFAULT_WEB_AWARE FALSE
 #define OSCAR_DEFAULT_ALWAYS_USE_RV_PROXY FALSE
 #define OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS TRUE
-#define OSCAR_DEFAULT_USE_CLIENTLOGIN TRUE
+#define AIM_DEFAULT_USE_CLIENTLOGIN FALSE
+#define ICQ_DEFAULT_USE_CLIENTLOGIN TRUE
 #define OSCAR_DEFAULT_ENCRYPTION OSCAR_OPPORTUNISTIC_ENCRYPTION
 
 #ifdef _WIN32
Only in libpurple/protocols: prpl-rules.mk
Only in libpurple/protocols: prpl.mk
Only in libpurple/protocols: prpl.py
Only in libpurple/protocols: qq
Only in libpurple/protocols/sametime: Makefile.in
Only in libpurple/protocols/sametime: meanwhile
Only in libpurple/protocols/sametime: moz.build
diff -ru extract/pidgin-2.10.11/libpurple/protocols/sametime/sametime.c libpurple/protocols/sametime/sametime.c
--- extract/pidgin-2.10.11/libpurple/protocols/sametime/sametime.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/sametime/sametime.c	2015-03-20 00:15:22.000000000 -0400
@@ -927,11 +927,6 @@
     return NULL;
   }
 
-  if (!name) {
-    DEBUG_WARN("Can't ensure a null group\n");
-    return NULL;
-  }
-
   DEBUG_INFO("attempting to ensure group %s, called %s\n",
 	     NSTR(name), NSTR(alias));
 
Only in libpurple/protocols/simple: Makefile.in
Only in libpurple/protocols/simple: moz.build
Only in libpurple/protocols: sipe
Only in libpurple/protocols: xpcomModule.cpp.in
Only in libpurple/protocols/yahoo: Makefile.in
diff -ru extract/pidgin-2.10.11/libpurple/protocols/yahoo/libyahoo.c libpurple/protocols/yahoo/libyahoo.c
--- extract/pidgin-2.10.11/libpurple/protocols/yahoo/libyahoo.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/yahoo/libyahoo.c	2015-03-19 23:21:15.000000000 -0400
@@ -306,6 +306,8 @@
 	NULL
 };
 
+gboolean purple_init_yahoojp_plugin(void);
+
 static void
 init_plugin(PurplePlugin *plugin)
 {
@@ -343,6 +345,7 @@
 
 	purple_signal_connect(purple_get_core(), "uri-handler", plugin,
 		PURPLE_CALLBACK(yahoo_uri_handler), NULL);
+	purple_init_yahoojp_plugin();
 }
 
 PURPLE_INIT_PLUGIN(yahoo, init_plugin, info);
diff -ru extract/pidgin-2.10.11/libpurple/protocols/yahoo/libyahoojp.c libpurple/protocols/yahoo/libyahoojp.c
--- extract/pidgin-2.10.11/libpurple/protocols/yahoo/libyahoojp.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/yahoo/libyahoojp.c	2015-03-19 23:21:15.000000000 -0400
@@ -21,6 +21,9 @@
  *
  */
 
+#ifndef PURPLE_STATIC_PRPL
+#define PURPLE_STATIC_PRPL
+#endif
 #include "internal.h"
 
 #include <account.h>
diff -ru extract/pidgin-2.10.11/libpurple/protocols/yahoo/libymsg.c libpurple/protocols/yahoo/libymsg.c
--- extract/pidgin-2.10.11/libpurple/protocols/yahoo/libymsg.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/yahoo/libymsg.c	2015-03-20 00:15:22.000000000 -0400
@@ -1363,12 +1363,15 @@
 static void
 yahoo_buddy_add_deny_reason_cb(gpointer data) {
 	struct yahoo_add_request *add_req = data;
+	yahoo_buddy_add_deny_cb(add_req, NULL);
+	/*
 	purple_request_input(add_req->gc, NULL, _("Authorization denied message:"),
 			NULL, _("No reason given."), TRUE, FALSE, NULL,
 			_("OK"), G_CALLBACK(yahoo_buddy_add_deny_cb),
 			_("Cancel"), G_CALLBACK(yahoo_buddy_add_deny_noreason_cb),
 			purple_connection_get_account(add_req->gc), add_req->who, NULL,
 			add_req);
+	*/
 }
 
 static void yahoo_buddy_denied_our_add(PurpleConnection *gc, const char *who, const char *reason)
Only in libpurple/protocols/yahoo: moz.build
diff -ru extract/pidgin-2.10.11/libpurple/protocols/yahoo/util.c libpurple/protocols/yahoo/util.c
--- extract/pidgin-2.10.11/libpurple/protocols/yahoo/util.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/protocols/yahoo/util.c	2015-03-20 00:15:22.000000000 -0400
@@ -499,11 +499,13 @@
 			 */
 			int size, htmlsize;
 			gchar tmp[11];
+			gchar *tmp2 = g_strdup_printf("font-size: %spt", fontsize);
 			size = strtol(fontsize, NULL, 10);
 			htmlsize = point_to_html(size);
 			sprintf(tmp, "%u", htmlsize);
 			xmlnode_set_attrib(*cur, "size", tmp);
-			xmlnode_set_attrib(*cur, "absz", fontsize);
+			xmlnode_set_attrib(*cur, "style", tmp2);
+			g_free(tmp2);
 #endif /* !USE_CSS_FORMATTING */
 			g_free(fontsize);
 		}
diff -ru extract/pidgin-2.10.11/libpurple/proxy.c libpurple/proxy.c
--- extract/pidgin-2.10.11/libpurple/proxy.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/proxy.c	2015-03-20 00:15:22.000000000 -0400
@@ -285,6 +285,7 @@
 	return param;
 }
 
+#if 0
 static PurpleProxyInfo *
 purple_gnome_proxy_get_info(void)
 {
@@ -415,6 +416,7 @@
 
 	return &info;
 }
+#endif
 
 #ifdef _WIN32
 
@@ -2236,9 +2238,11 @@
 			gpi = NULL;
 	}
 	if (gpi == NULL) {
+#if 0
 		if (purple_running_gnome())
 			gpi = purple_gnome_proxy_get_info();
 		else
+#endif
 			gpi = purple_global_proxy_get_info();
 	}
 
@@ -2560,6 +2564,7 @@
 	}
 }
 
+#if 0
 static void
 proxy_pref_cb(const char *name, PurplePrefType type,
 			  gconstpointer value, gpointer data)
@@ -2595,6 +2600,7 @@
 	else if (purple_strequal(name, "/purple/proxy/password"))
 		purple_proxy_info_set_password(info, value);
 }
+#endif
 
 void *
 purple_proxy_get_handle()
@@ -2614,13 +2620,16 @@
 
 	/* Proxy */
 	purple_prefs_add_none("/purple/proxy");
+#if 0
 	purple_prefs_add_string("/purple/proxy/type", "none");
 	purple_prefs_add_string("/purple/proxy/host", "");
 	purple_prefs_add_int("/purple/proxy/port", 0);
 	purple_prefs_add_string("/purple/proxy/username", "");
 	purple_prefs_add_string("/purple/proxy/password", "");
+#endif
 	purple_prefs_add_bool("/purple/proxy/socks4_remotedns", FALSE);
 
+#if 0
 	/* Setup callbacks for the preferences. */
 	handle = purple_proxy_get_handle();
 	purple_prefs_connect_callback(handle, "/purple/proxy/type", proxy_pref_cb,
@@ -2640,6 +2649,7 @@
 	purple_prefs_trigger_callback("/purple/proxy/port");
 	purple_prefs_trigger_callback("/purple/proxy/username");
 	purple_prefs_trigger_callback("/purple/proxy/password");
+#endif
 }
 
 void
diff -ru extract/pidgin-2.10.11/libpurple/proxy.h libpurple/proxy.h
--- extract/pidgin-2.10.11/libpurple/proxy.h	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/proxy.h	2015-03-19 23:21:15.000000000 -0400
@@ -195,6 +195,13 @@
  */
 void purple_global_proxy_set_info(PurpleProxyInfo *info);
 
+/**
+ * Set purple's global proxy information.
+ *
+ * @param info     The proxy information.
+ */
+void purple_global_proxy_set_info(PurpleProxyInfo *info);
+
 /*@}*/
 
 /**************************************************************************/
diff -ru extract/pidgin-2.10.11/libpurple/prpl.c libpurple/prpl.c
--- extract/pidgin-2.10.11/libpurple/prpl.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/prpl.c	2015-03-20 00:15:22.000000000 -0400
@@ -382,6 +382,9 @@
 	g_return_if_fail(new_status != NULL);
 	g_return_if_fail(!purple_status_is_exclusive(new_status) || old_status != NULL);
 
+	purple_signal_emit(purple_accounts_get_handle(), "account-status-changing",
+					account, old_status, new_status);
+
 	do_prpl_change_account_status(account, old_status, new_status);
 
 	purple_signal_emit(purple_accounts_get_handle(), "account-status-changed",
diff -ru extract/pidgin-2.10.11/libpurple/prpl.h libpurple/prpl.h
--- extract/pidgin-2.10.11/libpurple/prpl.h	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/prpl.h	2015-03-20 00:15:22.000000000 -0400
@@ -72,7 +72,6 @@
 #include "conversation.h"
 #include "ft.h"
 #include "imgstore.h"
-#include "media.h"
 #include "notify.h"
 #include "proxy.h"
 #include "plugin.h"
@@ -80,7 +79,6 @@
 #include "status.h"
 #include "whiteboard.h"
 
-
 /** @copydoc PurpleBuddyIconSpec */
 struct _PurpleBuddyIconSpec {
 	/** This is a comma-delimited list of image formats or @c NULL if icons
Only in libpurple: purple-prefs.js
diff -ru extract/pidgin-2.10.11/libpurple/request.c libpurple/request.c
--- extract/pidgin-2.10.11/libpurple/request.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/request.c	2015-03-19 23:21:15.000000000 -0400
@@ -1196,6 +1196,11 @@
 
 /* -- */
 
+#define PURPLE_REQUEST_NO_OPS(type, title, description)		    \
+	purple_debug_error("request", "Requesting "type": %s (%s)", \
+			   title ? title : "(null)",		    \
+			   description ? description : "(null)")
+
 void *
 purple_request_input(void *handle, const char *title, const char *primary,
 				   const char *secondary, const char *default_value,
@@ -1230,6 +1235,8 @@
 
 		return info->ui_handle;
 	}
+	else
+		PURPLE_REQUEST_NO_OPS("input", title, primary);
 
 	return NULL;
 }
@@ -1292,6 +1299,8 @@
 
 		return info->ui_handle;
 	}
+	else
+		PURPLE_REQUEST_NO_OPS("choice", title, primary);
 
 	return NULL;
 }
@@ -1366,6 +1375,8 @@
 
 		return info->ui_handle;
 	}
+	else
+		PURPLE_REQUEST_NO_OPS("action", title, primary);
 
 	return NULL;
 }
@@ -1470,6 +1481,8 @@
 		handles = g_list_append(handles, info);
 		return info->ui_handle;
 	}
+	else
+		PURPLE_REQUEST_NO_OPS("file", title, filename);
 
 	return NULL;
 }
@@ -1497,6 +1510,8 @@
 		handles = g_list_append(handles, info);
 		return info->ui_handle;
 	}
+	else
+		PURPLE_REQUEST_NO_OPS("folder", title, dirname);
 
 	return NULL;
 }
diff -ru extract/pidgin-2.10.11/libpurple/server.c libpurple/server.c
--- extract/pidgin-2.10.11/libpurple/server.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/server.c	2015-03-19 23:21:15.000000000 -0400
@@ -126,7 +126,6 @@
 	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 	int val = -EINVAL;
-	const gchar *auto_reply_pref = NULL;
 
 	g_return_val_if_fail(gc != NULL, val);
 
@@ -148,10 +147,9 @@
 	 * XXX - If "only auto-reply when away & idle" is set, then shouldn't
 	 * this only reset lar->sent if we're away AND idle?
 	 */
-	auto_reply_pref = purple_prefs_get_string("/purple/away/auto_reply");
 	if((gc->flags & PURPLE_CONNECTION_AUTO_RESP) &&
 			!purple_presence_is_available(presence) &&
-			!purple_strequal(auto_reply_pref, "never")) {
+			!purple_strequal(purple_prefs_get_string("/purple/away/auto_reply"), "never")) {
 
 		struct last_auto_response *lar;
 		lar = get_last_auto_response(gc, name);
@@ -645,8 +643,6 @@
 		const char *away_msg = NULL;
 		gboolean mobile = FALSE;
 
-		auto_reply_pref = purple_prefs_get_string("/purple/away/auto_reply");
-
 		presence = purple_account_get_presence(account);
 		status = purple_presence_get_active_status(presence);
 		status_type = purple_status_get_type(status);
@@ -655,7 +651,7 @@
 		if ((primitive == PURPLE_STATUS_AVAILABLE) ||
 			(primitive == PURPLE_STATUS_INVISIBLE) ||
 			mobile ||
-		    purple_strequal(auto_reply_pref, "never") ||
+		    purple_strequal((auto_reply_pref = purple_prefs_get_string("/purple/away/auto_reply")), "never") ||
 		    (!purple_presence_is_idle(presence) && purple_strequal(auto_reply_pref, "awayidle")))
 		{
 			g_free(name);
diff -ru extract/pidgin-2.10.11/libpurple/smiley.c libpurple/smiley.c
--- extract/pidgin-2.10.11/libpurple/smiley.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/smiley.c	2015-03-19 23:21:15.000000000 -0400
@@ -60,7 +60,7 @@
 static char *smileys_dir = NULL;
 
 #define SMILEYS_DEFAULT_FOLDER			"custom_smiley"
-#define SMILEYS_LOG_ID				"smileys"
+#define SMILEYS_LOG_ID				N_("smileys")
 
 #define XML_FILE_NAME				"smileys.xml"
 
diff -ru extract/pidgin-2.10.11/libpurple/ssl-nss.c libpurple/ssl-nss.c
--- extract/pidgin-2.10.11/libpurple/ssl-nss.c	2014-11-23 11:41:25.000000000 -0500
+++ libpurple/ssl-nss.c	2015-03-20 00:15:22.000000000 -0400
@@ -21,7 +21,6 @@
  */
 #include "internal.h"
 #include "debug.h"
-#include "certificate.h"
 #include "plugin.h"
 #include "sslconn.h"
 #include "util.h"
@@ -73,9 +72,9 @@
 
 #define PURPLE_SSL_NSS_DATA(gsc) ((PurpleSslNssData *)gsc->private_data)
 
-static const PRIOMethods *_nss_methods = NULL;
-static PRDescIdentity _identity;
-static PurpleCertificateScheme x509_nss;
+/* static const PRIOMethods *_nss_methods = NULL; */
+/* static PRDescIdentity _identity; */
+/* static PurpleCertificateScheme x509_nss; */
 
 /* Thank you, Evolution */
 static void
@@ -226,6 +225,7 @@
 static void
 ssl_nss_init_nss(void)
 {
+#if 0
 #if NSS_VMAJOR > 3 || ( NSS_VMAJOR == 3 && NSS_VMINOR >= 14 )
 	SSLVersionRange supported, enabled;
 #endif /* NSS >= 3.14 */
@@ -268,6 +268,7 @@
 
 	_identity = PR_GetUniqueIdentity("Purple");
 	_nss_methods = PR_GetDefaultIOMethods();
+#endif
 
 }
 
@@ -300,12 +301,15 @@
 static void
 ssl_nss_uninit(void)
 {
+#if 0
 	NSS_Shutdown();
 	PR_Cleanup();
 
 	_nss_methods = NULL;
+#endif
 }
 
+#if 0
 static void
 ssl_nss_verified_cb(PurpleCertificateVerificationStatus st,
 		       gpointer userdata)
@@ -382,6 +386,7 @@
 
 	return peer_certs;
 }
+#endif
 
 /*
  * Ideally this information would be exposed to the UI somehow, but for now we
@@ -455,6 +460,9 @@
 	purple_input_remove(nss_data->handshake_handler);
 	nss_data->handshake_handler = 0;
 
+	gsc->connect_cb(gsc->connect_cb_data, gsc, cond);
+
+#if 0
 	/* If a Verifier was given, hand control over to it */
 	if (gsc->verifier) {
 		GList *peers;
@@ -477,6 +485,7 @@
 		 */
 		gsc->connect_cb(gsc->connect_cb_data, gsc, cond);
 	}
+#endif
 }
 
 static gboolean
@@ -538,10 +547,11 @@
 
 	SSL_OptionSet(nss_data->in, SSL_SECURITY,            PR_TRUE);
 	SSL_OptionSet(nss_data->in, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
+	SSL_OptionSet(nss_data->in, SSL_ENABLE_SESSION_TICKETS, PR_FALSE);
 
 	/* If we have our internal verifier set up, use it. Otherwise,
 	 * use default. */
-	if (gsc->verifier != NULL)
+	if (gsc->verifier != NULL && !purple_prefs_get_bool("/purple/ssl/check_certificates"))
 		SSL_AuthCertificateHook(nss_data->in, ssl_auth_cert, NULL);
 
 	if(gsc->host)
@@ -593,6 +603,11 @@
 	PRInt32 ret;
 	PurpleSslNssData *nss_data = PURPLE_SSL_NSS_DATA(gsc);
 
+	if (nss_data->handshake_handler != 0) {
+		purple_debug_error("nss", "attempting to read from an ssl socket before the end of the handshake\n");
+		return -1;
+	}
+
 	ret = PR_Read(nss_data->in, data, len);
 
 	if (ret == -1)
@@ -610,6 +625,11 @@
 	if(!nss_data)
 		return 0;
 
+	if (nss_data->handshake_handler != 0) {
+		purple_debug_error("nss", "attempting to write to an ssl socket before the end of the handshake\n");
+		return -1;
+	}
+
 	ret = PR_Write(nss_data->in, data, len);
 
 	if (ret == -1)
@@ -642,6 +662,9 @@
 	return NULL;
 }
 
+#if 0
+/* No purple_certificate_* stuff for Instantbird */
+
 /************************************************************************/
 /* X.509 functionality                                                  */
 /************************************************************************/
@@ -1213,6 +1236,7 @@
 	x509_verify_cert,                /* Verify that the specified cert chain is trusted */
 	NULL
 };
+#endif
 
 static PurpleSslOps ssl_ops =
 {
@@ -1231,6 +1255,13 @@
 };
 
 
+void purple_nss_init(void)
+{
+	purple_ssl_set_ops(&ssl_ops);
+}
+
+#if 0
+/* Instantbird does not need the plugin stuff for NSS */
 static gboolean
 plugin_load(PurplePlugin *plugin)
 {
@@ -1303,3 +1334,4 @@
 }
 
 PURPLE_INIT_PLUGIN(ssl_nss, init_plugin, info)
+#endif
diff -ru extract/pidgin-2.10.11/libpurple/sslconn.c libpurple/sslconn.c
--- extract/pidgin-2.10.11/libpurple/sslconn.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/sslconn.c	2015-03-19 23:21:15.000000000 -0400
@@ -27,11 +27,12 @@
 
 #include "internal.h"
 
-#include "certificate.h"
 #include "debug.h"
 #include "request.h"
 #include "sslconn.h"
 
+extern void purple_nss_init(void);
+
 static gboolean _ssl_initialized = FALSE;
 static PurpleSslOps *_ssl_ops = NULL;
 
@@ -43,11 +44,14 @@
 
 	if (_ssl_initialized)
 		return FALSE;
+#if 0
 
 	plugin = purple_plugins_find_with_id("core-ssl");
 
 	if (plugin != NULL && !purple_plugin_is_loaded(plugin))
 		purple_plugin_load(plugin);
+#endif
+	purple_nss_init();
 
 	ops = purple_ssl_get_ops();
 	if ((ops == NULL) || (ops->init == NULL) || (ops->uninit == NULL) ||
@@ -63,12 +67,8 @@
 gboolean
 purple_ssl_is_supported(void)
 {
-#ifdef HAVE_SSL
 	ssl_init();
 	return (purple_ssl_get_ops() != NULL);
-#else
-	return FALSE;
-#endif
 }
 
 static void
@@ -131,8 +131,10 @@
 	gsc->connect_cb      = func;
 	gsc->error_cb        = error_func;
 
+#if 0
 	/* TODO: Move this elsewhere */
 	gsc->verifier = purple_certificate_find_verifier("x509","tls_cached");
+#endif
 
 	gsc->connect_data = purple_proxy_connect(NULL, account, host, port, purple_ssl_connect_cb, gsc);
 
@@ -222,8 +224,10 @@
     if(host)
         gsc->host            = g_strdup(host);
 
+#if 0
 	/* TODO: Move this elsewhere */
 	gsc->verifier = purple_certificate_find_verifier("x509","tls_cached");
+#endif
 
 
 	ops = purple_ssl_get_ops();
diff -ru extract/pidgin-2.10.11/libpurple/sslconn.h libpurple/sslconn.h
--- extract/pidgin-2.10.11/libpurple/sslconn.h	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/sslconn.h	2015-03-19 23:21:15.000000000 -0400
@@ -34,13 +34,13 @@
 	PURPLE_SSL_CERTIFICATE_INVALID = 3
 } PurpleSslErrorType;
 
-#include "certificate.h"
 #include "proxy.h"
 
 #define PURPLE_SSL_DEFAULT_PORT 443
 
 /** @copydoc _PurpleSslConnection */
 typedef struct _PurpleSslConnection PurpleSslConnection;
+typedef struct _PurpleCertificateVerifier PurpleCertificateVerifier;
 
 typedef void (*PurpleSslInputFunction)(gpointer, PurpleSslConnection *,
 									 PurpleInputCondition);
diff -ru extract/pidgin-2.10.11/libpurple/status.c libpurple/status.c
--- extract/pidgin-2.10.11/libpurple/status.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/status.c	2015-03-19 23:21:15.000000000 -0400
@@ -607,6 +607,7 @@
 notify_buddy_status_update(PurpleBuddy *buddy, PurplePresence *presence,
 		PurpleStatus *old_status, PurpleStatus *new_status)
 {
+#if 0
 	if (purple_prefs_get_bool("/purple/logging/log_system"))
 	{
 		time_t current_time = time(NULL);
@@ -652,6 +653,7 @@
 		g_free(tmp);
 		g_free(logtmp);
 	}
+#endif
 }
 
 static void
@@ -1253,6 +1255,7 @@
 	PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
 	PurpleAccount *account = purple_buddy_get_account(buddy);
 
+#if 0
 	if (!old_idle && idle)
 	{
 		if (purple_prefs_get_bool("/purple/logging/log_system"))
@@ -1293,6 +1296,7 @@
 			}
 		}
 	}
+#endif
 
 	if (old_idle != idle)
 		purple_signal_emit(purple_blist_get_handle(), "buddy-idle-changed", buddy,
@@ -1339,6 +1343,7 @@
 
 		account = purple_presence_get_account(presence);
 
+#if 0
 		if (purple_prefs_get_bool("/purple/logging/log_system"))
 		{
 			PurpleLog *log = purple_account_get_log(account, FALSE);
@@ -1360,6 +1365,7 @@
 				g_free(msg);
 			}
 		}
+#endif
 
 		gc = purple_account_get_connection(account);
 
diff -ru extract/pidgin-2.10.11/libpurple/upnp.h libpurple/upnp.h
--- extract/pidgin-2.10.11/libpurple/upnp.h	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/upnp.h	2015-03-19 23:21:15.000000000 -0400
@@ -61,17 +61,6 @@
  */
 void purple_upnp_discover(PurpleUPnPCallback cb, gpointer cb_data);
 
-#if 0
-/**
- * Retrieve the current UPnP control info, if there is any available.
- * This will only be filled in if purple_upnp_discover() had been called,
- * and finished discovering.
- *
- * @return The control URL for the IGD we'll use to use the IGD services
- */
-const PurpleUPnPControlInfo* purple_upnp_get_control_info(void);
-#endif
-
 /**
  * Gets the IP address from a UPnP enabled IGD that sits on the local
  * network, so when getting the network IP, instead of returning the
diff -ru extract/pidgin-2.10.11/libpurple/util.c libpurple/util.c
--- extract/pidgin-2.10.11/libpurple/util.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/util.c	2015-03-20 00:15:22.000000000 -0400
@@ -2497,6 +2497,7 @@
 /**************************************************************************
  * Path/Filename Functions
  **************************************************************************/
+#ifdef PURPLE_PLUGINS
 const char *
 purple_home_dir(void)
 {
@@ -2506,17 +2507,14 @@
 	return wpurple_data_dir();
 #endif
 }
+#endif
 
 /* Returns the argument passed to -c IFF it was present, or ~/.purple. */
 const char *
 purple_user_dir(void)
 {
-	if (custom_user_dir != NULL)
-		return custom_user_dir;
-	else if (!user_dir)
-		user_dir = g_build_filename(purple_home_dir(), ".purple", NULL);
-
-	return user_dir;
+	g_return_val_if_fail(custom_user_dir != NULL, NULL);
+	return custom_user_dir;
 }
 
 void purple_util_set_user_dir(const char *dir)
@@ -2730,6 +2728,7 @@
 	return xmlnode_from_file(purple_user_dir(), filename, description, "util");
 }
 
+#if 0
 /*
  * Like mkstemp() but returns a file pointer, uses a pre-set template,
  * uses the semantics of tempnam() for the directory to use and allocates
@@ -2778,6 +2777,7 @@
 
 	return fp;
 }
+#endif
 
 const char *
 purple_util_get_image_extension(gconstpointer data, size_t len)
@@ -2845,6 +2845,7 @@
 	return filename;
 }
 
+#if 0
 gboolean
 purple_program_is_valid(const char *program)
 {
@@ -2880,12 +2881,12 @@
 
 	return is_valid;
 }
-
+#endif
 
 gboolean
 purple_running_gnome(void)
 {
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(__APPLE__)
 	gchar *tmp = g_find_program_in_path("gnome-open");
 
 	if (tmp == NULL)
@@ -2903,7 +2904,7 @@
 gboolean
 purple_running_kde(void)
 {
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(__APPLE__)
 	gchar *tmp = g_find_program_in_path("kfmclient");
 	const char *session;
 
diff -ru extract/pidgin-2.10.11/libpurple/util.h libpurple/util.h
--- extract/pidgin-2.10.11/libpurple/util.h	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/util.h	2015-03-19 23:21:15.000000000 -0400
@@ -644,7 +644,7 @@
  *
  * @see purple_user_dir()
  */
-const gchar *purple_home_dir(void);
+/* const gchar *purple_home_dir(void); */
 
 /**
  * Returns the purple settings directory in the user's home directory.
@@ -745,7 +745,7 @@
  *
  * @return A file pointer to the temporary file, or @c NULL on failure.
  */
-FILE *purple_mkstemp(char **path, gboolean binary);
+/* FILE *purple_mkstemp(char **path, gboolean binary); */
 
 /**
  * Returns an extension corresponding to the image data's file type.
@@ -787,7 +787,7 @@
  *
  * @return TRUE if the program is runable.
  */
-gboolean purple_program_is_valid(const char *program);
+/* gboolean purple_program_is_valid(const char *program); */
 
 /**
  * Check if running GNOME.
Only in libpurple: version.h
diff -ru extract/pidgin-2.10.11/libpurple/win32/libc_interface.h libpurple/win32/libc_interface.h
--- extract/pidgin-2.10.11/libpurple/win32/libc_interface.h	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/win32/libc_interface.h	2015-03-19 23:21:15.000000000 -0400
@@ -134,8 +134,6 @@
 /* stdio.h */
 #undef snprintf
 #define snprintf _snprintf
-#undef vsnprintf
-#define vsnprintf _vsnprintf
 
 #define rename( oldname, newname ) \
 wpurple_rename( oldname, newname )
diff -ru extract/pidgin-2.10.11/libpurple/win32/win32dep.c libpurple/win32/win32dep.c
--- extract/pidgin-2.10.11/libpurple/win32/win32dep.c	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/win32/win32dep.c	2015-03-19 23:21:15.000000000 -0400
@@ -22,7 +22,10 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  *
  */
+#ifndef _WIN32_IE
 #define _WIN32_IE 0x501
+#endif
+
 #include "internal.h"
 #include <winuser.h>
 
@@ -112,6 +115,7 @@
 
 /* Determine Purple Paths during Runtime */
 
+#if 0
 /* Get paths to special Windows folders. */
 gchar *wpurple_get_special_folder(int folder_type) {
 	gchar *retval = NULL;
@@ -327,6 +331,7 @@
 
 	return result;
 }
+#endif
 
 void wpurple_init(void) {
 	WORD wVersionRequested;
@@ -336,7 +341,7 @@
 		g_thread_init(NULL);
 
 	purple_debug_info("wpurple", "wpurple_init start\n");
-	purple_debug_info("wpurple", "libpurple version: " DISPLAY_VERSION "\n");
+	//	purple_debug_info("wpurple", "libpurple version: " DISPLAY_VERSION "\n");
 
 	purple_debug_info("wpurple", "Glib:%u.%u.%u\n",
 		glib_major_version, glib_minor_version, glib_micro_version);
diff -ru extract/pidgin-2.10.11/libpurple/win32/win32dep.h libpurple/win32/win32dep.h
--- extract/pidgin-2.10.11/libpurple/win32/win32dep.h	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/win32/win32dep.h	2015-03-19 23:21:15.000000000 -0400
@@ -54,18 +54,17 @@
  **/
 /* Windows helper functions */
 FARPROC wpurple_find_and_loadproc(const char *dllname, const char *procedure);
-gboolean wpurple_read_reg_dword(HKEY rootkey, const char *subkey, const char *valname, LPDWORD result);
-char *wpurple_read_reg_string(HKEY rootkey, const char *subkey, const char *valname); /* needs to be g_free'd */
-gboolean wpurple_write_reg_string(HKEY rootkey, const char *subkey, const char *valname, const char *value);
+/* gboolean wpurple_read_reg_dword(HKEY rootkey, const char *subkey, const char *valname, LPDWORD result); */
+/* char *wpurple_read_reg_string(HKEY rootkey, const char *subkey, const char *valname); / * needs to be g_free'd */
+/* gboolean wpurple_write_reg_string(HKEY rootkey, const char *subkey, const char *valname, const char *value); */
 char *wpurple_escape_dirsep(const char *filename); /* needs to be g_free'd */
-GIOChannel *wpurple_g_io_channel_win32_new_socket(int socket); /* Until we get the post-2.8 glib win32 giochannel implementation working, use the thread-based one */
 
 /* Determine Purple paths */
-gchar *wpurple_get_special_folder(int folder_type); /* needs to be g_free'd */
-const char *wpurple_install_dir(void);
-const char *wpurple_lib_dir(void);
-const char *wpurple_locale_dir(void);
-const char *wpurple_data_dir(void);
+/* gchar *wpurple_get_special_folder(int folder_type); /* needs to be g_free'd */
+/* const char *wpurple_install_dir(void); */
+/* const char *wpurple_lib_dir(void); */
+/* const char *wpurple_locale_dir(void); */
+/* const char *wpurple_data_dir(void); */
 
 /* init / cleanup */
 void wpurple_init(void);
@@ -80,9 +79,9 @@
 /*
  *  Purple specific
  */
-#define DATADIR wpurple_install_dir()
-#define LIBDIR wpurple_lib_dir()
-#define LOCALEDIR wpurple_locale_dir()
+/* #define DATADIR wpurple_install_dir() */
+/* #define LIBDIR wpurple_lib_dir() */
+/* #define LOCALEDIR wpurple_locale_dir() */
 
 #ifdef __cplusplus
 }
diff -ru extract/pidgin-2.10.11/libpurple/win32/wpurpleerror.h libpurple/win32/wpurpleerror.h
--- extract/pidgin-2.10.11/libpurple/win32/wpurpleerror.h	2014-11-23 11:41:26.000000000 -0500
+++ libpurple/win32/wpurpleerror.h	2015-03-20 00:15:22.000000000 -0400
@@ -25,6 +25,16 @@
 #ifndef _WPURPLEERROR_H
 #define _WPURPLEERROR_H
 
+#if defined(_MSC_VER) && _MSC_VER >= 1600
+/* libpurple expects errno to contain winsocks error codes rather than
+   the real errno values (which are defined in MSVC10). */
+
+/* Include the Microsoft errno.h before undefining the error codes, so
+   that it doesn't do anything if it is included later (avoid macro
+   redefinition warnings). */
+#include <errno.h>
+#endif
+
 /* Here we define unix socket errors as windows socket errors */
 
 #undef ENETDOWN
@@ -44,8 +54,6 @@
 
 #undef EADDRINUSE
 #define EADDRINUSE WSAEADDRINUSE
-#undef EINPROGRESS
-#define EINPROGRESS WSAEINPROGRESS
 #undef EALREADY
 #define EALREADY WSAEALREADY
 #undef EADDRNOTAVAIL
