Merge from trunk

Sat, 02 Feb 2013 21:20:08 +0100

author
Tomasz Wasilczyk <tomkiewicz@cpw.pidgin.im>
date
Sat, 02 Feb 2013 21:20:08 +0100
changeset 34415
378c6f53452d
parent 34414
751567312cdd (current diff)
parent 33724
b40615082e93 (diff)
child 34416
95be3544aa84

Merge from trunk

libpurple/ciphers/md5.c file | annotate | diff | comparison | revisions
libpurple/ciphers/sha1.c file | annotate | diff | comparison | revisions
libpurple/ciphers/sha256.c file | annotate | diff | comparison | revisions
libpurple/protocols/gg/gg.c file | annotate | diff | comparison | revisions
libpurple/protocols/gg/image.c file | annotate | diff | comparison | revisions
share/ca-certs/Microsoft_Internet_Authority.pem file | annotate | diff | comparison | revisions
share/ca-certs/Microsoft_Secure_Server_Authority.pem file | annotate | diff | comparison | revisions
share/ca-certs/Verisign_RSA_Secure_Server_CA.pem file | annotate | diff | comparison | revisions
--- a/.hgignore	Sat Feb 02 18:29:35 2013 +0100
+++ b/.hgignore	Sat Feb 02 21:20:08 2013 +0100
@@ -10,6 +10,7 @@
 .*/perl/common/MYMETA\.(json|yml)
 .*~$
 .*\.a$
+.*\.asc$
 .*\.bak$
 .*\.bs$
 .*\.def$
--- a/COPYRIGHT	Sat Feb 02 18:29:35 2013 +0100
+++ b/COPYRIGHT	Sat Feb 02 21:20:08 2013 +0100
@@ -17,6 +17,7 @@
 
 Copyright (C) 1998-2012 by the following:
 
+Mark
 Saleem Abdulrasool
 Jakub Adam
 Dave Ahlswede
@@ -73,6 +74,7 @@
 Éric Boumaour
 Chris Boyle
 Stanislav Brabec
+Bartosz Brachaczek
 Quentin Brandon
 Derrick J Brashear
 Mauro Sérgio Ferreira Brasil
@@ -175,6 +177,7 @@
 Gavan Fantom (gavan)
 Leonardo Fernandes
 David Fiander
+Michael Fiedler
 Ryan Flegel
 Rob Flynn <gaim@robflynn.com>
 Rob Foehl (rwf)
@@ -459,6 +462,7 @@
 Thanumalayan S.
 Jonathan Sailor
 Elliott Sales de Andrade
+Catalin Salgau
 Tomasz Sałaciński <tsalacinski@gmail.com>
 Pradyumna Sampath
 Arvind Samptur
@@ -511,6 +515,7 @@
 Lex Spoon
 Chris Stafford
 Kevin Stange
+Ferdinand Stehle
 Joshua Stein
 Jakub Steiner
 Richard Stellingwerff
@@ -537,6 +542,7 @@
 Cestonaro Thilo
 Will Thompson
 Douglas Thrift (douglaswth)
+Niels Thykier
 Mark Tiefenbruck
 Andrew Tinney
 Jeffery To
--- a/ChangeLog	Sat Feb 02 18:29:35 2013 +0100
+++ b/ChangeLog	Sat Feb 02 21:20:08 2013 +0100
@@ -10,6 +10,8 @@
 	* Add email notification in the docklet area. (Alexei) (#3571)
 	* Add a pref to select the type messages in conversation that triggers 
 	  the docklet notification. (Momchil) (#12598)
+	* Complete support for receiving a limited amount of history when
+	  joining a room. (Kha) (#15458)
 
 	Finch:
 	* Support the conversation-extended signal for extending the
@@ -60,21 +62,83 @@
 	* Fix a crash at startup with large contact list. Avatar support for
 	  buddies will be disabled till 3.0.0. (#15226, #14305)
 
+	General:
+	* The configure script will now exit with status 1 when specifying
+	  invalid protocol plugins using the --with-static-prpls and
+	  --with-dynamic-prpls arguments. (Michael Fiedler) (#15316)
+
+	libpurple:
+	* Don't link directly to libgcrypt when building with GnuTLS support.
+	  (Bartosz Brachaczek) (#15329)
+	* Fix UPnP mappings on routers that return empty <URLBase/> elements
+	  in their response. (Ferdinand Stehle) (#15373)
+	* Tcl plugin uses saner, race-free plugin loading.
+	* Fix the Tcl signals-test plugin for savedstatus-changed.
+	  (Andrew Shadura) (#15443)
+
+	Pidgin:
+	* Make Pidgin more friendly to non-X11 GTK+, such as MacPorts' +no_x11
+	  variant.
+
 	Gadu-Gadu:
 	* Fix a crash at startup with large contact list. Avatar support for
 	  buddies will be disabled till 3.0.0. (#15226, #14305)
 
+	IRC:
+	* Support for SASL authentication.  (Thijs Alkemade, Andy Spencer)
+	  (#13270)
+	* Print topic setter information at channel join. (#13317)
+
 	MSN:
+	* Fix SSL certificate issue when signing into MSN for some users.
 	* Fix a crash when removing a user before its icon is loaded. (Mark
 	  Barfield) (#15217)
 
+	MXit:
+	* Display farewell messages in a different colour to distinguish
+	  them from normal messages.
+	* Add support for typing notification.
+	* Add support for the Relationship Status profile attribute.
+	* Remove all reference to Hidden Number.
+	* Ignore new invites to join a GroupChat if you're already joined, or
+	  still have a pending invite.
+	* The buddy's name was not centered vertically in the buddy-list if they
+	  did not have a status-message or mood set.
+	* Fix decoding of font-size changes in the markup of received messages.
+
 	Yahoo!:
 	* Fix a double-free in profile/picture loading code. (Mihai Serban)
 	  (#15053)
+	* Fix retrieving server-side buddy aliases. (Catalin Salgu) (#15381)
 
 	Plugins:
 	* The Voice/Video Settings plugin supports using the sndio GStreamer
-	 backends. (Brad Smith) (#14414)
+	  backends. (Brad Smith) (#14414)
+	* Fix a crash in the Contact Availability Detection plugin. (Mark)
+	  (#15327)
+	* Make the Message Notification plugin more friendly to non-X11 GTK+,
+	  such as MacPorts' +no_x11 variant.
+
+	Windows-Specific Changes:
+	* Compile with secure flags (#15290)
+	* Installer downloads GTK+ Runtime and Debug Symbols more securely.
+	  (#15277)
+	* Updates to a number of dependencies, some of which have security
+	  related fixes. (#14571, #15285, #15286)
+		* ATK 1.32.0-2
+		* Cyrus SASL 2.1.25
+		* expat 2.1.0-1
+		* freetype 2.4.10-1
+		* gettext 0.18.1.1-2
+		* Glib 2.28.8-1
+		* libpng 1.4.12-1
+		* libxml2 2.9.0-1
+		* NSS 3.13.6 and NSPR 4.9.2
+		* Pango 1.29.4-1
+		* SILC 1.1.10
+		* zlib 1.2.5-2
+	* Patch libmeanwhile (sametime library) to fix crash. (Jonathan Rice)
+	  (#12637)
 
 version 2.10.6 (07/06/2012):
 	Pidgin:
--- a/ChangeLog.API	Sat Feb 02 18:29:35 2013 +0100
+++ b/ChangeLog.API	Sat Feb 02 21:20:08 2013 +0100
@@ -78,10 +78,12 @@
 		* PidginDockletFlag
 
 		Changed:
+		* account-authorization-requested signal merged with account-authorization-requested-with-message signal
 		* purple_account_add_buddy now takes an invite message as the last
 		  parameter
 		* purple_account_add_buddies now takes an invite message as the last
 		  parameter
+		* purple_buddy_icon_unref no longer has a return value
 		* purple_certificate_check_signature_chain now returns a list of failing
 		  PurpleCertificate*s as the second parameter
 		* purple_connection_error now takes a PurpleConnectionError
@@ -89,6 +91,8 @@
 		* purple_conversation_get_gc renamed to
 		  purple_conversation_get_connection
 		* purple_dnsquery_a now takes a PurpleAccount as the first parameter
+		* purple_imgstore_add renamed to purple_imgstore_new
+		* purple_imgstore_add_with_id renamed to purple_imgstore_new_with_id
 		* purple_network_listen now takes the protocol family as the second
 		  parameter
 		* purple_network_listen now takes a boolean indicating external port
@@ -103,6 +107,8 @@
 		  a GList
 		* purple_notify_user_info_prepend_pair renamed to
 		  purple_notify_user_info_prepend_pair_html
+		* pidgin_setup_screenname_autocomplete now takes a filter function and
+		  its data as final two arguments
 		* purple_srv_resolve now takes a PurpleAccount as the first parameter
 		* purple_str_size_to_units now takes a goffset as the size parameter
 		* purple_txt_resolve now takes a PurpleAccount as the first parameter
@@ -118,6 +124,9 @@
 		* purple_xfer_set_bytes_sent now takes a goffset as the bytes_sent
 		  parameter
 		* purple_xfer_set_size now takes a goffset as the size parameter
+		* PurpleCertificateVerificationStatus enumeration is now merged with
+		  internal flags, thus removing PURPLE_CERTIFICATE_INVALID and
+		  replacing it with more precise errors.
 		* PurpleConnectionUiOps.report_disconnect now passes a
 		  PurpleConnectionError as the second parameter
 		* PurpleXfer.bytes_remaining is now a goffset
@@ -142,6 +151,7 @@
 		* _PurplePrivacyType
 		* _PurpleSoundEventID
 		* _XMLNodeType
+		* account-authorization-requested-with-message signal
 		* GtkIMHtml.clipboard_html_string
 		* GtkIMHtml.clipboard_text_string
 		* GtkIMHtmlFontDetail
@@ -155,12 +165,16 @@
 		* pidgin_check_if_dir
 		* PIDGIN_DIALOG
 		* pidgin_dialogs_alias_contact
+		* pidgin_mini_dialog_links_supported
 		* pidgin_set_custom_buddy_icon
-		* pidgin_setup_screenname_autocomplete
+		* pidgin_setup_screenname_autocomplete_with_filter
 		* PidginBuddyList.connection_errors
 		* PidginConversation.sg
 		* purple_account_add_buddies_with_invite
 		* purple_account_add_buddy_with_invite
+		* purple_blist_load
+		* purple_blist_new
+		* purple_set_blist
 		* purple_blist_update_buddy_icon
 		* purple_buddy_get_local_alias
 		* purple_buddy_icons_has_custom_icon
@@ -192,6 +206,7 @@
 		* purple_plugins_unregister_load_notify_cb
 		* purple_plugins_unregister_probe_notify_cb
 		* purple_plugins_unregister_unload_notify_cb
+		* purple_pounces_load
 		* purple_presence_add_status
 		* purple_presence_add_list
 		* purple_proxy_connect_socks5
@@ -216,6 +231,7 @@
 		* purple_util_fetch_url_request, instead.
 		* purple_util_fetch_url_request_len_with_account.  Use
 		  purple_util_fetch_url_request, instead.
+		* PurpleCertificateVerificationStatus.PURPLE_CERTIFICATE_INVALID
 		* PurpleConnectionUiOps.report_disconnect_reason
 		* PurplePluginProtocolInfo.add_buddy_with_invite
 		* PurplePluginProtocolInfo.add_buddies_with_invite
--- a/Makefile.am	Sat Feb 02 18:29:35 2013 +0100
+++ b/Makefile.am	Sat Feb 02 21:20:08 2013 +0100
@@ -54,13 +54,13 @@
 # ... and have no changes in the working copy. (this isn't really necessary with hg because hg id appends a "+")
 	test "x`hg st -mard`" = x
 
-packages:
+sign-packages: dist
 	gpg -ab pidgin-$(PACKAGE_VERSION).tar.gz
 	gpg -ab pidgin-$(PACKAGE_VERSION).tar.bz2
 	gpg --verify pidgin-$(PACKAGE_VERSION).tar.gz.asc pidgin-$(PACKAGE_VERSION).tar.gz
 	gpg --verify pidgin-$(PACKAGE_VERSION).tar.bz2.asc pidgin-$(PACKAGE_VERSION).tar.bz2
 
-release: commit-check version-check distcheck packages
+release: commit-check version-check distcheck sign-packages
 
 if INSTALL_I18N
 PO_DIR=po
--- a/Makefile.mingw	Sat Feb 02 18:29:35 2013 +0100
+++ b/Makefile.mingw	Sat Feb 02 21:20:08 2013 +0100
@@ -31,11 +31,21 @@
     exit; \
 }' VERSION)
 
-GTK_INSTALL_VERSION = 2.16.6.0
+GTK_INSTALL_VERSION = 2.16.6.1
+
+authenticode_sign = $(MONO_SIGNCODE) \
+		    -spc "$(SIGNCODE_SPC)" -v "$(SIGNCODE_PVK)" \
+		    -a sha1 -$$ commercial \
+		    -n "$(2)" -i "https://pidgin.im" \
+		    -t "http://timestamp.verisign.com/scripts/timstamp.dll" -tr 10 \
+		    $(1)
+
+gpg_sign = $(GPG_SIGN) -ab $(1) && $(GPG_SIGN) --verify $(1).asc
 
 STRIPPED_RELEASE_DIR = $(PIDGIN_TREE_TOP)/pidgin-$(PIDGIN_VERSION)-win32bin
 DEBUG_SYMBOLS_DIR = $(PIDGIN_TREE_TOP)/pidgin-$(PIDGIN_VERSION)-dbgsym
 
+PIDGIN_INST_DEP_DIR="$(WIN32_DEV_TOP)/pidgin-inst-deps-20120910"
 
 # Any *.dll or *.exe files included in win32-install-dir that we don't compile
 # should be included in this list so they don't get stripped
@@ -55,9 +65,9 @@
 	libplc4.dll \
 	libplds4.dll \
 	libsasl.dll \
+	libssp-0.dll \
 	libxml2-2.dll \
 	nss3.dll \
-	nssckbi.dll \
 	nssutil3.dll \
 	saslANONYMOUS.dll \
 	saslCRAMMD5.dll \
@@ -77,7 +87,7 @@
 
 include $(PIDGIN_COMMON_RULES)
 
-.PHONY: all docs install installer installer_offline installer_zip debug_symbols_zip installers clean uninstall create_release_install_dir generate_installer_includes $(PIDGIN_REVISION_H) $(PIDGIN_REVISION_RAW_TXT)
+.PHONY: all docs install installer installer_offline installer_zip debug_symbols_zip installers clean uninstall create_release_install_dir generate_installer_includes $(PIDGIN_REVISION_H) $(PIDGIN_REVISION_RAW_TXT) gtk_runtime_zip
 
 all: $(PIDGIN_CONFIG_H) $(PIDGIN_REVISION_H)
 	$(MAKE) -C $(PURPLE_TOP) -f $(MINGW_MAKEFILE)
@@ -98,12 +108,13 @@
 	cp $(GTKSPELL_TOP)/bin/libgtkspell-0.dll $(PIDGIN_INSTALL_DIR)/spellcheck
 	cp $(ENCHANT_TOP)/bin/libenchant.dll $(PIDGIN_INSTALL_DIR)/spellcheck
 	cp -R $(ENCHANT_TOP)/lib/enchant/*.dll $(PIDGIN_INSTALL_DIR)/spellcheck/lib/enchant
-	cp $(WIN32_DEV_TOP)/pidgin-inst-deps-20100315/exchndl.dll $(PIDGIN_INSTALL_DIR)
+	cp $(PIDGIN_INST_DEP_DIR)/exchndl.dll $(PIDGIN_INSTALL_DIR)
+	cp $(GCC_SSP_TOP)/bin/libssp-0.dll $(PIDGIN_INSTALL_DIR)
 
-pidgin/win32/nsis/gtk-runtime-$(GTK_BUNDLE_VERSION).zip:
-	pidgin/win32/nsis/generate_gtk_zip.sh `pwd`
+gtk_runtime_zip:
+	pidgin/win32/nsis/generate_gtk_zip.sh "`pwd`" "$(GPG_SIGN)"
 
-generate_installer_includes: create_release_install_dir pidgin/win32/nsis/gtk-runtime-$(GTK_BUNDLE_VERSION).zip debug_symbols_zip $(PIDGIN_TREE_TOP)/pidgin/win32/nsis/nsis_translations.desktop
+generate_installer_includes: create_release_install_dir gtk_runtime_zip debug_symbols_zip $(PIDGIN_TREE_TOP)/pidgin/win32/nsis/nsis_translations.desktop
 	rm -f pidgin/win32/nsis/pidgin-translations.nsh pidgin/win32/nsis/pidgin-spellcheck.nsh pidgin/win32/nsis/pidgin-spellcheck-preselect.nsh
 	find $(STRIPPED_RELEASE_DIR)/locale -maxdepth 1 -mindepth 1 \
 	 -exec basename {} ';' \
@@ -137,18 +148,32 @@
 	find $(STRIPPED_RELEASE_DIR) \( -name '*.dll' -o -name '*.exe' \) \
 	 -not \( -false $(EXTERNAL_DLLS_FIND_EXP) \) \
 	 -exec $(STRIP) --strip-unneeded {} ';'
+	$(call authenticode_sign, $(STRIPPED_RELEASE_DIR)/pidgin.exe, "Pidgin $(PIDGIN_VERSION)")
 
 installer: generate_installer_includes
-	$(MAKENSIS) -V3 -DPIDGIN_VERSION="$(PIDGIN_VERSION)" -DPIDGIN_PRODUCT_VERSION="$(PIDGIN_PRODUCT_VERSION)" -DPIDGIN_INSTALL_DIR="$(STRIPPED_RELEASE_DIR)" -DGTK_INSTALL_VERSION="$(GTK_INSTALL_VERSION)" pidgin/win32/nsis/pidgin-installer.nsi
+	$(eval $@_DEBUG_SYMBOLS_SHA1SUM := $(shell sha1sum $(DEBUG_SYMBOLS_DIR).zip | sed -e "s/\ .*$$//"))
+	$(eval $@_GTK_SHA1SUM := $(shell sha1sum pidgin/win32/nsis/gtk-runtime-$(GTK_INSTALL_VERSION).zip | sed -e "s/\ .*$$//"))
+	$(MAKENSIS) -V3 -DPIDGIN_VERSION="$(PIDGIN_VERSION)" -DPIDGIN_PRODUCT_VERSION="$(PIDGIN_PRODUCT_VERSION)" \
+		-DPIDGIN_INSTALL_DIR="$(STRIPPED_RELEASE_DIR)" -DGTK_INSTALL_VERSION="$(GTK_INSTALL_VERSION)" \
+		-DDEBUG_SYMBOLS_SHA1SUM="$($@_DEBUG_SYMBOLS_SHA1SUM)" -DGTK_SHA1SUM="$($@_GTK_SHA1SUM)"\
+		pidgin/win32/nsis/pidgin-installer.nsi
+	$(call authenticode_sign, pidgin/win32/nsis/pidgin-$(PIDGIN_VERSION).exe, "Pidgin Installer")
 	mv pidgin/win32/nsis/pidgin-$(PIDGIN_VERSION).exe ./
+	$(call gpg_sign, pidgin-$(PIDGIN_VERSION).exe)
 
 installer_offline: generate_installer_includes
-	$(MAKENSIS) -V3 -DPIDGIN_VERSION="$(PIDGIN_VERSION)" -DPIDGIN_PRODUCT_VERSION="$(PIDGIN_PRODUCT_VERSION)" -DOFFLINE_INSTALLER -DPIDGIN_INSTALL_DIR="$(STRIPPED_RELEASE_DIR)" -DGTK_INSTALL_VERSION="$(GTK_INSTALL_VERSION)" pidgin/win32/nsis/pidgin-installer.nsi
+	$(MAKENSIS) -V3 -DPIDGIN_VERSION="$(PIDGIN_VERSION)" -DPIDGIN_PRODUCT_VERSION="$(PIDGIN_PRODUCT_VERSION)" \
+		-DPIDGIN_INSTALL_DIR="$(STRIPPED_RELEASE_DIR)" -DGTK_INSTALL_VERSION="$(GTK_INSTALL_VERSION)" \
+		-DOFFLINE_INSTALLER \
+		pidgin/win32/nsis/pidgin-installer.nsi
+	$(call authenticode_sign, pidgin/win32/nsis/pidgin-$(PIDGIN_VERSION)-offline.exe, "Pidgin Installer")
 	mv pidgin/win32/nsis/pidgin-$(PIDGIN_VERSION)-offline.exe ./
+	$(call gpg_sign, pidgin-$(PIDGIN_VERSION)-offline.exe)
 
 installer_zip: create_release_install_dir
 	rm -f pidgin-$(PIDGIN_VERSION)-win32-bin.zip
 	zip -9 -r pidgin-$(PIDGIN_VERSION)-win32-bin.zip $(STRIPPED_RELEASE_DIR)
+	$(call gpg_sign, pidgin-$(PIDGIN_VERSION)-win32-bin.zip)
 
 debug_symbols_zip: install
 	rm -rf $(DEBUG_SYMBOLS_DIR) $(DEBUG_SYMBOLS_DIR).zip
@@ -156,7 +181,9 @@
 	tar -cf - `find $(PIDGIN_INSTALL_DIR) \( -name '*.dll' -o -name '*.exe' \) \
 	 -not \( -false $(EXTERNAL_DLLS_FIND_EXP) \) -print` \
 	 | tar --strip 2 --xform s/$$/.dbgsym/ -xC $(DEBUG_SYMBOLS_DIR) -f -
+	cp $(MEANWHILE_TOP)/bin/libmeanwhile-1.dll.unstripped $(DEBUG_SYMBOLS_DIR)/libmeanwhile-1.dll.dbgsym
 	zip -9 -r $(DEBUG_SYMBOLS_DIR).zip $(DEBUG_SYMBOLS_DIR) 
+	$(call gpg_sign, $(DEBUG_SYMBOLS_DIR).zip)
 
 installers: installer installer_offline debug_symbols_zip installer_zip
 
--- a/autogen.sh	Sat Feb 02 18:29:35 2013 +0100
+++ b/autogen.sh	Sat Feb 02 21:20:08 2013 +0100
@@ -160,5 +160,8 @@
 ###############################################################################
 # Run configure
 ###############################################################################
-echo "running ./configure ${CONFIGURE_FLAGS} $@"
-./configure ${CONFIGURE_FLAGS} $@
+if test -z "$NOCONFIGURE"; then
+	echo "running ./configure ${CONFIGURE_FLAGS} $@"
+	./configure ${CONFIGURE_FLAGS} $@
+fi
+
--- a/configure.ac	Sat Feb 02 18:29:35 2013 +0100
+++ b/configure.ac	Sat Feb 02 21:20:08 2013 +0100
@@ -1,5 +1,5 @@
 dnl Process this file with autoconf to produce a configure script.
-AC_PREREQ([2.50])
+AC_PREREQ([2.63])
 
 # UPDATING VERSION NUMBERS FOR RELEASES
 #
@@ -74,9 +74,8 @@
 
 AC_CANONICAL_HOST
 AC_CONFIG_HEADERS([config.h])
-AM_INIT_AUTOMAKE([1.9 -Wno-portability dist-bzip2])
-dnl TODO: Always use AM_SILENT_RULES when we depend on automake >= 1.11
-m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+AM_INIT_AUTOMAKE([1.11 -Wno-portability dist-bzip2])
+AM_SILENT_RULES([yes])
 
 PURPLE_MAJOR_VERSION=purple_major_version
 PURPLE_MINOR_VERSION=purple_minor_version
@@ -110,8 +109,8 @@
 dnl Checks for programs.
 AC_PROG_CC
 AM_PROG_CC_C_O
-AC_DISABLE_STATIC
-AC_PROG_LIBTOOL
+LT_PREREQ([2.2.6])
+LT_INIT([disable-static])
 LIBTOOL="$LIBTOOL --silent"
 AC_PROG_INSTALL
 PKG_PROG_PKG_CONFIG
@@ -158,7 +157,7 @@
 	[AC_DEFINE([HAVE_GETADDRINFO], [1],
 		[Define to 1 if you have the getaddrinfo function.])],
 	[AC_CHECK_LIB(socket, getaddrinfo,
-		[AC_DEFINE([HAVE_GETADDRINFO]) LIBS="-lsocket -lsnl $LIBS"], , , -lnsl)])
+		[AC_DEFINE([HAVE_GETADDRINFO]) LIBS="-lsocket -lnsl $LIBS"], , -lnsl)])
 AC_CHECK_FUNCS(inet_ntop)
 AC_CHECK_FUNCS(getifaddrs)
 dnl Check for socklen_t (in Unix98)
@@ -208,7 +207,7 @@
   AC_MSG_ERROR([unable to find the ceil() function])
 ])
 
-AC_MSG_CHECKING(for fileno())
+AC_MSG_CHECKING([for fileno()])
 AC_RUN_IFELSE([AC_LANG_SOURCE([[
 #include <stdio.h>
 
@@ -232,7 +231,7 @@
 	AC_MSG_RESULT(no)
 ])
 
-AC_MSG_CHECKING(for the %z format string in strftime())
+AC_MSG_CHECKING([for the %z format string in strftime()])
 AC_RUN_IFELSE([AC_LANG_SOURCE([[
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
@@ -297,10 +296,10 @@
 dnl #######################################################################
 dnl # Disable creation and installation of translation files
 dnl #######################################################################
-AC_ARG_ENABLE(nls, AC_HELP_STRING([--disable-nls], [disable installation of translation files]), enable_i18n="$enableval", enable_i18n=yes)
+AC_ARG_ENABLE(nls, AS_HELP_STRING([--disable-nls], [disable installation of translation files]), enable_i18n="$enableval", enable_i18n=yes)
 
 if test x$enable_i18n = xyes; then
-	AC_PROG_INTLTOOL
+	IT_PROG_INTLTOOL
 	GETTEXT_PACKAGE=pidgin
 	AC_SUBST(GETTEXT_PACKAGE)
 
@@ -332,16 +331,16 @@
 AM_CONDITIONAL(INSTALL_I18N, test "x$enable_i18n" = "xyes")
 
 dnl #######################################################################
-dnl # Check for GLib 2.16 (required)
+dnl # Check for GLib 2.20 (required)
 dnl #######################################################################
 # TODO: gmodule-2.0 is only needed if enable_plugins is 'yes'.  It
 #       might be nice to change this check so that it's not required
 #       if enable_plugins is 'no'.
-PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.16.0 gobject-2.0 gmodule-2.0 gthread-2.0], , [
+PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.20.0 gobject-2.0 gmodule-2.0 gthread-2.0], , [
 	AC_MSG_RESULT(no)
 	AC_MSG_ERROR([
 
-You must have GLib 2.16.0 or newer development headers installed to build.
+You must have GLib 2.20.0 or newer development headers installed to build.
 
 If you have these installed already you may need to install pkg-config so
 I can find them.
@@ -353,7 +352,7 @@
 AC_SUBST(GLIB_GENMARSHAL)
 
 AC_ARG_WITH([extraversion],
-			AC_HELP_STRING([--with-extraversion=STRING],
+			AS_HELP_STRING([--with-extraversion=STRING],
 						   [extra version number to be displayed in Help->About and --help (for packagers)]),
 						   EXTRA_VERSION=$withval)
 
@@ -363,55 +362,55 @@
 	AC_DEFINE_UNQUOTED(DISPLAY_VERSION, "$VERSION", [display version info])
 fi
 
-AC_ARG_ENABLE(missing-dependencies, [AC_HELP_STRING([--disable-missing-dependencies],
+AC_ARG_ENABLE(missing-dependencies, [AS_HELP_STRING([--disable-missing-dependencies],
 		[skip missing dependencies instead of aborting configure])],
 	force_deps="$enableval", force_deps="yes")
 
 AC_ARG_WITH(x, [],
 	with_x="$withval", with_x="yes")
-AC_ARG_ENABLE(gtkui, [AC_HELP_STRING([--disable-gtkui],
+AC_ARG_ENABLE(gtkui, [AS_HELP_STRING([--disable-gtkui],
 		[compile without GTK+ user interface])],
 	enable_gtkui="$enableval", enable_gtkui="yes")
-AC_ARG_WITH(gtk, [AC_HELP_STRING([--with-gtk=<version>],
+AC_ARG_WITH(gtk, [AS_HELP_STRING([--with-gtk=<version>],
 		[compile with GTK+ 2 or 3 user interface (default: auto)])],
 	with_gtk="$withval", with_gtk="auto")
-AC_ARG_ENABLE(consoleui, [AC_HELP_STRING([--disable-consoleui],
+AC_ARG_ENABLE(consoleui, [AS_HELP_STRING([--disable-consoleui],
 		[compile without console user interface])],
 	[enable_consoleui=$enableval force_finch=$enableval], [enable_consoleui=yes force_finch=no])
 
 dnl #######################################################################
-dnl # Check for GTK+ 2.10 and other things used by the GTK UI
+dnl # Check for GTK+ 2.18 and other things used by the GTK UI
 dnl #######################################################################
 AC_ARG_ENABLE(screensaver,
-	[AC_HELP_STRING([--disable-screensaver],
+	[AS_HELP_STRING([--disable-screensaver],
 		[compile without X screensaver extension (used to detect idleness)])],
 	enable_screensaver="$enableval", enable_screensaver="yes")
 AC_ARG_ENABLE(sm,
-	[AC_HELP_STRING([--disable-sm],
+	[AS_HELP_STRING([--disable-sm],
 		[compile without X session management support])],
 	enable_sm="$enableval", enable_sm="yes")
 AC_ARG_ENABLE(startup-notification,
-	[AC_HELP_STRING([--disable-startup-notification],
+	[AS_HELP_STRING([--disable-startup-notification],
 		[compile without startup notification support])],
 	enable_startup_notification="$enableval", enable_startup_notification="yes")
 AC_ARG_ENABLE(gtkspell,
-	[AC_HELP_STRING([--disable-gtkspell],
+	[AS_HELP_STRING([--disable-gtkspell],
 		[compile without GtkSpell automatic spell checking])],
 	enable_gtkspell="$enableval", enable_gtkspell="yes")
 AC_ARG_ENABLE(gevolution,
-	[AC_HELP_STRING([--enable-gevolution],
+	[AS_HELP_STRING([--enable-gevolution],
 		[compile with the Evolution plugin])],
 	enable_gevolution="$enableval", enable_gevolution="no")
 AC_ARG_ENABLE(cap,
-	[AC_HELP_STRING([--enable-cap],
+	[AS_HELP_STRING([--enable-cap],
 		[compile with Contact Availability Prediction plugin])],
 	enable_cap="$enableval", enable_cap="no")
 AC_ARG_ENABLE(gestures,
-	[AC_HELP_STRING([--disable-gestures],
+	[AS_HELP_STRING([--disable-gestures],
 		[compile without the gestures plugin])],
 	enable_gestures="$enableval", enable_gestures="yes")
 AC_ARG_ENABLE(gcr,
-	[AC_HELP_STRING([--enable-gcr],
+	[AS_HELP_STRING([--enable-gcr],
 		[compile with GCR certificate widgets])],
 	enable_gcr="$enableval", enable_gcr="no")
 
@@ -440,20 +439,20 @@
 running configure.
 ])])
 	elif test "x$with_gtk" = "x2"; then
-		PKG_CHECK_MODULES(GTK, [gtk+-2.0 >= 2.10.0], , [
+		PKG_CHECK_MODULES(GTK, [gtk+-2.0 >= 2.18.0], , [
 			AC_MSG_RESULT(no)
 			AC_MSG_ERROR([
-You must have GTK+ 2.10.0 or newer development headers installed to compile
+You must have GTK+ 2.18.0 or newer development headers installed to compile
 Pidgin.  If you want to build only Finch then specify --disable-gtkui when
 running configure.
 ])])
 	elif test "x$with_gtk" = "xauto"; then
 		PKG_CHECK_MODULES(GTK, [gtk+-3.0 >= 3.0.0], [with_gtk=3], [
 			AC_MSG_RESULT(no)
-			PKG_CHECK_MODULES(GTK, [gtk+-2.0 >= 2.10.0], [with_gtk=2], [
+			PKG_CHECK_MODULES(GTK, [gtk+-2.0 >= 2.18.0], [with_gtk=2], [
 				AC_MSG_RESULT(no)
 				AC_MSG_ERROR([
-You must have GTK+ 2.10.0 or newer development headers installed to compile
+You must have GTK+ 2.18.0 or newer development headers installed to compile
 Pidgin.  If you want to build only Finch then specify --disable-gtkui when
 running configure.
 ])])])
@@ -463,6 +462,9 @@
 	AC_SUBST(GTK_CFLAGS)
 	AC_SUBST(GTK_LIBS)
 
+	GTK_PC_MODULE="gtk+-${with_gtk}.0"
+	AC_SUBST(GTK_PC_MODULE)
+
 	dnl We only really need Pango >= 1.4 for decent RTL support
 	PKG_CHECK_MODULES(PANGO, [pango >= 1.4.0],
 			AC_DEFINE(HAVE_PANGO14, 1, [Define if we have Pango 1.4 or newer.]),:)
@@ -715,7 +717,7 @@
 dnl #######################################################################
 GNT_LIBS=""
 GNT_CFLAGS=""
-AC_ARG_WITH(ncurses-headers, [AC_HELP_STRING([--with-ncurses-headers=DIR],
+AC_ARG_WITH(ncurses-headers, [AS_HELP_STRING([--with-ncurses-headers=DIR],
 		[compile finch against the ncurses includes in DIR])],
 		[ac_ncurses_includes="$withval"], [ac_ncurses_includes=""])
 if test "x$enable_consoleui" = "xyes"; then
@@ -816,10 +818,14 @@
 AC_SUBST(LIBXML_LIBS)
 
 dnl #######################################################################
-dnl # Check for JSON-GLib (required, if compiled with Gadu-Gadu support)
+dnl # Check for JSON-GLib (required)
 dnl #######################################################################
 
-PKG_CHECK_MODULES([JSON], [json-glib-1.0], [enable_json="yes"], [enable_json="no"])
+PKG_CHECK_MODULES([JSON], [json-glib-1.0 >= 0.14.0], , [
+	AC_MSG_RESULT(no)
+	AC_MSG_ERROR([
+You must have JSON-GLib >= 0.14.0 development headers installed to build.
+])])
 
 AC_SUBST(JSON_CFLAGS)
 AC_SUBST(JSON_LIBS)
@@ -846,9 +852,9 @@
 dnl # Check for GStreamer
 dnl #######################################################################
 AC_ARG_ENABLE(gstreamer,
-	[AC_HELP_STRING([--disable-gstreamer], [compile without GStreamer audio support])],
+	[AS_HELP_STRING([--disable-gstreamer], [compile without GStreamer audio support])],
 	enable_gst="$enableval", enable_gst="yes")
-AC_ARG_WITH(gstreamer, [AC_HELP_STRING([--with-gstreamer=<version>],
+AC_ARG_WITH(gstreamer, [AS_HELP_STRING([--with-gstreamer=<version>],
 		[compile with GStreamer 0.10 or 1.0 interface (default: auto)])],
 	with_gstreamer="$withval", with_gstreamer="auto")
 if test "x$enable_gst" != "xno"; then
@@ -916,7 +922,7 @@
 dnl #######################################################################
 if test "x$enable_gst" != "xno" -a "x$with_gstreamer" == "x1.0"; then
 	AC_ARG_ENABLE(gstreamer-video,
-		[AC_HELP_STRING([--disable-gstreamer-video], [compile without GStreamer 1.0 Video Overlay support])],
+		[AS_HELP_STRING([--disable-gstreamer-video], [compile without GStreamer 1.0 Video Overlay support])],
 			enable_gstvideo="$enableval", enable_gstvideo="yes")
 	if test "x$enable_gstvideo" != "xno"; then
 		PKG_CHECK_MODULES(GSTVIDEO, [gstreamer-video-1.0], [
@@ -936,7 +942,7 @@
 dnl #######################################################################
 if test "x$enable_gst" != "xno" -a "x$with_gstreamer" == "x0.10"; then
 	AC_ARG_ENABLE(gstreamer-interfaces,
-		[AC_HELP_STRING([--disable-gstreamer-interfaces], [compile without GStreamer 0.10 interface support])],
+		[AS_HELP_STRING([--disable-gstreamer-interfaces], [compile without GStreamer 0.10 interface support])],
 			enable_gstinterfaces="$enableval", enable_gstinterfaces="yes")
 	if test "x$enable_gstinterfaces" != "xno"; then
 		PKG_CHECK_MODULES(GSTINTERFACES, [gstreamer-interfaces-0.10], [
@@ -955,7 +961,7 @@
 dnl # Check for Farstream
 dnl #######################################################################
 AC_ARG_ENABLE(farstream,
-	[AC_HELP_STRING([--disable-farstream], [compile without farstream support])],
+	[AS_HELP_STRING([--disable-farstream], [compile without farstream support])],
 	enable_farstream="$enableval", enable_farstream="yes")
 if test "x$enable_farstream" != "xno"; then
 	if test "x$with_gstreamer" == "x1.0"; then
@@ -986,7 +992,7 @@
 dnl # Check for Voice and Video support
 dnl #######################################################################
 AC_ARG_ENABLE(vv,
-	[AC_HELP_STRING([--disable-vv], [compile without voice and video support])],
+	[AS_HELP_STRING([--disable-vv], [compile without voice and video support])],
 	enable_vv="$enableval", enable_vv="yes")
 if test "x$enable_vv" != "xno"; then
 	if test "x$enable_gst" != "xno" -a "x$with_gstreamer" == "x1.0" -a "x$enable_gstvideo" != "xno" -a "x$enable_farstream" != "xno"; then
@@ -1011,7 +1017,7 @@
 dnl #######################################################################
 
 AC_ARG_ENABLE(idn,
-	[AC_HELP_STRING([--disable-idn], [compile without IDN support])],
+	[AS_HELP_STRING([--disable-idn], [compile without IDN support])],
 	[enable_idn="$enableval" force_idn=$enableval], [enable_idn="yes" force_idn=no])
 if test "x$enable_idn" != "xno"; then
 	PKG_CHECK_MODULES(IDN, libidn >= 0.0.0, [
@@ -1034,7 +1040,7 @@
 dnl # Check for Meanwhile headers (for Sametime)
 dnl #######################################################################
 AC_ARG_ENABLE(meanwhile,
-	[AC_HELP_STRING([--disable-meanwhile],
+	[AS_HELP_STRING([--disable-meanwhile],
 		[compile without meanwhile (required for Sametime support)])],
 	enable_meanwhile="$enableval", enable_meanwhile="yes")
 if test "x$enable_meanwhile" = "xyes"; then
@@ -1056,13 +1062,13 @@
 dnl # Check for Native Avahi headers (for Bonjour)
 dnl #######################################################################
 AC_ARG_ENABLE(avahi,
-	[AC_HELP_STRING([--disable-avahi],
+	[AS_HELP_STRING([--disable-avahi],
 		[compile without avahi (required for Bonjour support)])],
 	enable_avahi="$enableval", enable_avahi="yes")
 
 if test "x$enable_avahi" = "xyes"; then
-	AC_ARG_WITH(avahi-client-includes, [AC_HELP_STRING([--with-avahi-client-includes=DIR], [compile the Bonjour plugin against the Avahi Client includes in DIR])], [ac_avahi_client_includes="$withval"], [ac_avahi_client_includes="no"])
-	AC_ARG_WITH(avahi-client-libs, [AC_HELP_STRING([--with-avahi-client-libs=DIR], [compile the Bonjour plugin against the Avahi Client libs in DIR])], [ac_avahi_client_libs="$withval"], [ac_avahi_client_libs="no"])
+	AC_ARG_WITH(avahi-client-includes, [AS_HELP_STRING([--with-avahi-client-includes=DIR], [compile the Bonjour plugin against the Avahi Client includes in DIR])], [ac_avahi_client_includes="$withval"], [ac_avahi_client_includes="no"])
+	AC_ARG_WITH(avahi-client-libs, [AS_HELP_STRING([--with-avahi-client-libs=DIR], [compile the Bonjour plugin against the Avahi Client libs in DIR])], [ac_avahi_client_libs="$withval"], [ac_avahi_client_libs="no"])
 	AVAHI_CFLAGS=""
 	AVAHI_LIBS=""
 
@@ -1109,8 +1115,8 @@
 dnl #######################################################################
 dnl # Check for SILC client includes and libraries
 dnl #######################################################################
-AC_ARG_WITH(silc-includes, [AC_HELP_STRING([--with-silc-includes=DIR], [compile the SILC plugin against includes in DIR])], [ac_silc_includes="$withval"], [ac_silc_includes="no"])
-AC_ARG_WITH(silc-libs, [AC_HELP_STRING([--with-silc-libs=DIR], [compile the SILC plugin against the SILC libs in DIR])], [ac_silc_libs="$withval"], [ac_silc_libs="no"])
+AC_ARG_WITH(silc-includes, [AS_HELP_STRING([--with-silc-includes=DIR], [compile the SILC plugin against includes in DIR])], [ac_silc_includes="$withval"], [ac_silc_includes="no"])
+AC_ARG_WITH(silc-libs, [AS_HELP_STRING([--with-silc-libs=DIR], [compile the SILC plugin against the SILC libs in DIR])], [ac_silc_libs="$withval"], [ac_silc_libs="no"])
 SILC_CFLAGS=""
 SILC_LIBS=""
 have_silc="no"
@@ -1156,8 +1162,8 @@
 dnl #######################################################################
 dnl # Check for Gadu-Gadu client includes and libraries
 dnl #######################################################################
-AC_ARG_WITH(gadu-includes, [AC_HELP_STRING([--with-gadu-includes=DIR], [compile the Gadu-Gadu plugin against includes in DIR])], [ac_gadu_includes="$withval"], [ac_gadu_includes="no"])
-AC_ARG_WITH(gadu-libs, [AC_HELP_STRING([--with-gadu-libs=DIR], [compile the Gadu-Gadu plugin against the libs in DIR])], [ac_gadu_libs="$withval"], [ac_gadu_libs="no"])
+AC_ARG_WITH(gadu-includes, [AS_HELP_STRING([--with-gadu-includes=DIR], [compile the Gadu-Gadu plugin against includes in DIR])], [ac_gadu_includes="$withval"], [ac_gadu_includes="no"])
+AC_ARG_WITH(gadu-libs, [AS_HELP_STRING([--with-gadu-libs=DIR], [compile the Gadu-Gadu plugin against the libs in DIR])], [ac_gadu_libs="$withval"], [ac_gadu_libs="no"])
 GADU_CFLAGS=""
 GADU_LIBS=""
 GADU_LIBGADU_VERSION=1.11.2
@@ -1260,7 +1266,7 @@
 AC_ARG_ENABLE(distrib,,,enable_distrib=no)
 AM_CONDITIONAL(DISTRIB, test "x$enable_distrib" = "xyes")
 DYNAMIC_PRPLS=all
-AC_ARG_WITH(static-prpls, [AC_HELP_STRING([--with-static-prpls], [Link to certain protocols statically])], [STATIC_PRPLS=`echo $withval | $sedpath 's/,/ /g'`], [STATIC_PRPLS=""])
+AC_ARG_WITH(static-prpls, [AS_HELP_STRING([--with-static-prpls], [Link to certain protocols statically])], [STATIC_PRPLS=`echo $withval | $sedpath 's/,/ /g'`], [STATIC_PRPLS=""])
 if test "x$STATIC_PRPLS" != "x" -a "x$DYNAMIC_PRPLS" = "xall"; then
 	DYNAMIC_PRPLS=""
 fi
@@ -1322,7 +1328,7 @@
 		simple)		static_simple=yes ;;
 		yahoo)		static_yahoo=yes ;;
 		zephyr)		static_zephyr=yes ;;
-		*)			echo "Invalid static protocol $i!!" ; exit ;;
+		*)			echo "Invalid static protocol $i!!" ; exit 1 ;;
 	esac
 done
 AM_CONDITIONAL(STATIC_BONJOUR, test "x$static_bonjour" = "xyes")
@@ -1343,7 +1349,7 @@
 AC_DEFINE_UNQUOTED(STATIC_PROTO_INIT, $extern_init static void static_proto_init(void) { $load_proto },
 	[Loads static protocol plugin module initialization functions.])
 
-AC_ARG_WITH(dynamic_prpls, [AC_HELP_STRING([--with-dynamic-prpls], [specify which protocols to build dynamically])], [DYNAMIC_PRPLS=`echo $withval | $sedpath 's/,/ /g'`])
+AC_ARG_WITH(dynamic_prpls, [AS_HELP_STRING([--with-dynamic-prpls], [specify which protocols to build dynamically])], [DYNAMIC_PRPLS=`echo $withval | $sedpath 's/,/ /g'`])
 if test "x$DYNAMIC_PRPLS" = "xall" ; then
 	DYNAMIC_PRPLS="bonjour gg irc jabber msn mxit myspace novell oscar sametime silc simple yahoo zephyr"
 fi
@@ -1376,23 +1382,19 @@
 		simple)		dynamic_simple=yes ;;
 		yahoo)		dynamic_yahoo=yes ;;
 		zephyr)		dynamic_zephyr=yes ;;
-		*)			echo "Invalid dynamic protocol $i!!" ; exit ;;
+		*)			echo "Invalid dynamic protocol $i!!" ; exit 1 ;;
 	esac
 done
 
-AC_ARG_ENABLE(plugins, [AC_HELP_STRING([--disable-plugins], [compile without plugin support])], , enable_plugins=yes)
-AC_ARG_WITH(krb4, [AC_HELP_STRING([--with-krb4=PREFIX], [compile Zephyr plugin with Kerberos 4 support])], kerberos="$withval", kerberos="no")
-AC_ARG_WITH(zephyr, [AC_HELP_STRING([--with-zephyr=PREFIX], [compile Zephyr plugin against external libzephyr])], zephyr="$withval", zephyr="no")
+AC_ARG_ENABLE(plugins, [AS_HELP_STRING([--disable-plugins], [compile without plugin support])], , enable_plugins=yes)
+AC_ARG_WITH(krb4, [AS_HELP_STRING([--with-krb4=PREFIX], [compile Zephyr plugin with Kerberos 4 support])], kerberos="$withval", kerberos="no")
+AC_ARG_WITH(zephyr, [AS_HELP_STRING([--with-zephyr=PREFIX], [compile Zephyr plugin against external libzephyr])], zephyr="$withval", zephyr="no")
 AM_CONDITIONAL(EXTERNAL_LIBZEPHYR, test "x$zephyr" != "xno")
 
 AC_CHECK_HEADERS(sys/utsname.h)
 AC_CHECK_FUNC(uname)
 
-AC_ARG_ENABLE(fortify, [AC_HELP_STRING([--disable-fortify], [compile without FORTIFY_SOURCE support])], , enable_fortify=yes)
-
-if test \( "x$static_gg" = "xyes" -o "x$dynamic_gg" = "xyes" \) -a "x$enable_json" != "xyes" ; then
-	AC_MSG_ERROR([json-glib-1.0 not found (required, when compiling with Gadu-Gadu support)])
-fi
+AC_ARG_ENABLE(fortify, [AS_HELP_STRING([--disable-fortify], [compile without FORTIFY_SOURCE support])], , enable_fortify=yes)
 
 DEBUG_CFLAGS="$DEBUG_CFLAGS -DPURPLE_DISABLE_DEPRECATED -DPIDGIN_DISABLE_DEPRECATED -DFINCH_DISABLE_DEPRECATED -DGNT_DISABLE_DEPRECATED"
 if test "x$GCC" = "xyes"; then
@@ -1485,8 +1487,8 @@
 dnl # Check for D-Bus libraries
 dnl #######################################################################
 
-AC_ARG_ENABLE(dbus, [AC_HELP_STRING([--disable-dbus], [disable D-Bus support])], , enable_dbus=yes)
-AC_ARG_ENABLE(nm, [AC_HELP_STRING([--disable-nm], [disable NetworkManager support (requires D-Bus)])], enable_nm=$enableval, enable_nm=yes)
+AC_ARG_ENABLE(dbus, [AS_HELP_STRING([--disable-dbus], [disable D-Bus support])], , enable_dbus=yes)
+AC_ARG_ENABLE(nm, [AS_HELP_STRING([--disable-nm], [disable NetworkManager support (requires D-Bus)])], enable_nm=$enableval, enable_nm=yes)
 
 if test "x$enable_dbus" = "xyes" ; then
 	AC_CHECK_PROG(enable_dbus, dbus-binding-tool, yes, no)
@@ -1544,7 +1546,7 @@
 dnl in C (brrrr ...).
 
 AC_ARG_WITH([python],
-			AC_HELP_STRING([--with-python=PATH],
+			AS_HELP_STRING([--with-python=PATH],
 						   [which python interpreter to use for dbus code generation]),
 			PYTHON=$withval)
 
@@ -1578,7 +1580,7 @@
 dnl # although a newer dbus is installed.  But I have tried to order the
 dnl # directory searching to keep this situation at a minimum.
 dnl ###########################################################################
-AC_ARG_WITH(dbus-services, [AC_HELP_STRING([--with-dbus-services=<dir>], [where the D-Bus services directory is located.])])
+AC_ARG_WITH(dbus-services, [AS_HELP_STRING([--with-dbus-services=<dir>], [where the D-Bus services directory is located.])])
 
 DBUS_SERVICES_DIR=""
 
@@ -1659,7 +1661,7 @@
 dnl #######################################################################
 dnl # Check for Mono support
 dnl #######################################################################
-AC_ARG_ENABLE(mono, [AC_HELP_STRING([--enable-mono], [compile with Mono runtime support (experimental)])], , enable_mono=no)
+AC_ARG_ENABLE(mono, [AS_HELP_STRING([--enable-mono], [compile with Mono runtime support (experimental)])], , enable_mono=no)
 if test x"$enable_mono" = x"yes" ; then
 	PKG_CHECK_MODULES(MONO, mono, [
 		AC_SUBST(MONO_CFLAGS)
@@ -1700,7 +1702,7 @@
 dnl #######################################################################
 dnl # Check for Perl support
 dnl #######################################################################
-AC_ARG_ENABLE(perl, [AC_HELP_STRING([--disable-perl], [compile without perl scripting])], , enable_perl=yes)
+AC_ARG_ENABLE(perl, [AS_HELP_STRING([--disable-perl], [compile without perl scripting])], , enable_perl=yes)
 
 if test "$enable_plugins" = no ; then
 	enable_perl=no
@@ -1823,7 +1825,7 @@
 dnl # Thanks go to Evolution for the checks.
 dnl #######################################################################
 
-AC_ARG_WITH(system-ssl-certs, [AC_HELP_STRING([--with-system-ssl-certs=<dir>], [directory containing system-wide SSL CA certificates])], [ssl_certificates_dir=$withval])
+AC_ARG_WITH(system-ssl-certs, [AS_HELP_STRING([--with-system-ssl-certs=<dir>], [directory containing system-wide SSL CA certificates])], [ssl_certificates_dir=$withval])
 
 SSL_CERTIFICATES_DIR=""
 if ! test -z "$ssl_certificates_dir" ; then
@@ -1893,7 +1895,7 @@
 	fi
 
 	AC_ARG_WITH(gnutls-libs,
-		[AC_HELP_STRING([--with-gnutls-libs=PREFIX], [location of GnuTLS libraries.])],
+		[AS_HELP_STRING([--with-gnutls-libs=PREFIX], [location of GnuTLS libraries.])],
 		[ with_gnutls_libs="$withval" ])
 
 	if test "x$with_gnutls_libs"     != "xno" -a \
@@ -1908,8 +1910,8 @@
 
 		AC_CACHE_CHECK([for GnuTLS libraries], ac_cv_gnutls_libs,
 		[
-			LIBS="$LIBS $with_gnutls_libs -lgnutls -lgcrypt"
-			AC_TRY_LINK_FUNC(gnutls_init, ac_cv_gnutls_libs="yes", ac_cv_gnutls_libs="no")
+			LIBS="$LIBS $with_gnutls_libs -lgnutls"
+			AC_LINK_IFELSE([AC_LANG_CALL([], [gnutls_init])], ac_cv_gnutls_libs="yes", ac_cv_gnutls_libs="no")
 			LIBS="$LIBS_save"
 		])
 
@@ -1917,7 +1919,7 @@
 			AC_DEFINE(HAVE_GNUTLS, 1, [Define if you have GnuTLS])
 			AC_DEFINE(HAVE_SSL)
 			msg_gnutls="GnuTLS"
-			GNUTLS_LIBS="$with_gnutls_libs -lgnutls -lgcrypt"
+			GNUTLS_LIBS="$with_gnutls_libs -lgnutls"
 
 			enable_gnutls="yes"
 		else
@@ -1980,19 +1982,19 @@
 	looked_for_nss="yes"
 
 	AC_ARG_WITH(nspr-includes,
-		[AC_HELP_STRING([--with-nspr-includes=PREFIX], [specify location of Mozilla nspr4 includes.])],
+		[AS_HELP_STRING([--with-nspr-includes=PREFIX], [specify location of Mozilla nspr4 includes.])],
 		[with_nspr_includes="$withval"])
 
 	AC_ARG_WITH(nspr-libs,
-		[AC_HELP_STRING([--with-nspr-libs=PREFIX], [specify location of Mozilla nspr4 libs.])],
+		[AS_HELP_STRING([--with-nspr-libs=PREFIX], [specify location of Mozilla nspr4 libs.])],
 		[with_nspr_libs="$withval"])
 
 	AC_ARG_WITH(nss-includes,
-		[AC_HELP_STRING([--with-nss-includes=PREFIX], [specify location of Mozilla nss3 includes.])],
+		[AS_HELP_STRING([--with-nss-includes=PREFIX], [specify location of Mozilla nss3 includes.])],
 		[with_nss_includes="$withval"])
 
 	AC_ARG_WITH(nss-libs,
-		[AC_HELP_STRING([--with-nss-libs=PREFIX], [specify location of Mozilla nss3 libs.])],
+		[AS_HELP_STRING([--with-nss-libs=PREFIX], [specify location of Mozilla nss3 libs.])],
 		[with_nss_libs="$withval"])
 
 
@@ -2112,7 +2114,7 @@
 					LDFLAGS="$LDFLAGS"
 				fi
 
-				AC_TRY_LINK_FUNC(PR_Init,
+				AC_LINK_IFELSE([AC_LANG_CALL([], [PR_Init])],
 					[ac_cv_moz_nspr_libs="yes"],
 					[ac_cv_moz_nspr_libs="no"])
 
@@ -2200,7 +2202,7 @@
 				LDFLAGS="$LDFLAGS -L$with_nspr_libs -L$with_nss_libs"
 				LIBS="$nsslibs $nsprlibs"
 
-				AC_TRY_LINK_FUNC(NSS_Init,
+				AC_LINK_IFELSE([AC_LANG_CALL([], [NSS_Init])],
 					[ac_cv_moz_nss_libs="yes"],
 					[ac_cv_moz_nss_libs="no"])
 
@@ -2208,7 +2210,7 @@
 					nsslibs="-lssl3 -lsmime3 -lnss3 -lsoftokn3"
 					LDFLAGS="$LDFLAGS -L$with_nspr_libs -L$with_nss_libs"
 					LIBS="$LIBS $nsslibs"
-					AC_TRY_LINK_FUNC(NSS_Init,
+					AC_LINK_IFELSE([AC_LANG_CALL([], [NSS_Init])],
 						[ac_cv_moz_nss_libs="yes"],
 						[ac_cv_moz_nss_libs="no"])
 				fi
@@ -2280,9 +2282,9 @@
 dnl #######################################################################
 dnl # Check for Tcl
 dnl #######################################################################
-AC_ARG_ENABLE(tcl, [AC_HELP_STRING([--disable-tcl],
+AC_ARG_ENABLE(tcl, [AS_HELP_STRING([--disable-tcl],
 	[compile without Tcl scripting])], enable_tcl="$enableval", enable_tcl="yes")
-AC_ARG_WITH(tclconfig, [AC_HELP_STRING([--with-tclconfig=DIR],
+AC_ARG_WITH(tclconfig, [AS_HELP_STRING([--with-tclconfig=DIR],
 	[directory containing tclConfig.sh])])
 
 if test "$enable_plugins" = no; then
@@ -2359,9 +2361,9 @@
 dnl #######################################################################
 dnl # Check for Tk
 dnl #######################################################################
-AC_ARG_ENABLE(tk, [AC_HELP_STRING([--disable-tk],
+AC_ARG_ENABLE(tk, [AS_HELP_STRING([--disable-tk],
 	[compile without Tcl support for Tk])], enable_tk="$enableval", enable_tk="yes")
-AC_ARG_WITH(tkconfig, [AC_HELP_STRING([--with-tkconfig=DIR],
+AC_ARG_WITH(tkconfig, [AS_HELP_STRING([--with-tkconfig=DIR],
 	[directory containing tkConfig.sh])])
 
 if test "$enable_tcl" = yes -a "$enable_tk" = yes; then
@@ -2443,7 +2445,7 @@
 dnl AC_CHECK_SIZEOF(short)
 AC_CHECK_FUNCS(snprintf connect)
 AC_SUBST(SASL_LIBS)
-AC_ARG_ENABLE(cyrus-sasl, AC_HELP_STRING([--enable-cyrus-sasl], [enable Cyrus SASL support for jabberd]), enable_cyrus_sasl=$enableval, enable_cyrus_sasl=no)
+AC_ARG_ENABLE(cyrus-sasl, AS_HELP_STRING([--enable-cyrus-sasl], [enable Cyrus SASL support for jabberd]), enable_cyrus_sasl=$enableval, enable_cyrus_sasl=no)
 if test "x$enable_cyrus_sasl" = "xyes" ; then
 	AC_CHECK_LIB(sasl2, sasl_client_init, [
 			AM_CONDITIONAL(USE_CYRUS_SASL, true)
@@ -2594,14 +2596,14 @@
 dnl #######################################################################
 dnl # Disable pixmap installation
 dnl #######################################################################
-AC_ARG_ENABLE(pixmaps-install, AC_HELP_STRING([--disable-pixmaps-install], [disable installation of pixmap files - Pidgin still needs them!]), enable_pixmaps="$enableval", enable_pixmaps=yes)
+AC_ARG_ENABLE(pixmaps-install, AS_HELP_STRING([--disable-pixmaps-install], [disable installation of pixmap files - Pidgin still needs them!]), enable_pixmaps="$enableval", enable_pixmaps=yes)
 
 AM_CONDITIONAL(INSTALL_PIXMAPS, test "x$enable_pixmaps" = "xyes")
 
 dnl #######################################################################
 dnl # Tweak status tray icon installation directory
 dnl #######################################################################
-AC_ARG_ENABLE(trayicon-compat, AC_HELP_STRING([--enable-trayicon-compat], [install tray icons in location compatible with older releases of hicolor-icon-theme]), enable_traycompat="$enableval", enable_traycompat=no)
+AC_ARG_ENABLE(trayicon-compat, AS_HELP_STRING([--enable-trayicon-compat], [install tray icons in location compatible with older releases of hicolor-icon-theme]), enable_traycompat="$enableval", enable_traycompat=no)
 
 AM_CONDITIONAL(ENABLE_TRAYCOMPAT, test "x$enable_traycompat" = "xyes")
 
@@ -2609,15 +2611,15 @@
 dnl # Check for Doxygen and dot (part of GraphViz)
 dnl #######################################################################
 AC_ARG_ENABLE(doxygen,
-	[AC_HELP_STRING([--disable-doxygen],
+	[AS_HELP_STRING([--disable-doxygen],
 		[disable documentation with doxygen])],
 	enable_doxygen="$enableval", enable_doxygen="yes")
 AC_ARG_ENABLE(dot,
-	[AC_HELP_STRING([--disable-dot],
+	[AS_HELP_STRING([--disable-dot],
 		[disable graphs in doxygen via 'dot'])],
 	enable_dot="$enableval", enable_dot="yes")
 AC_ARG_ENABLE(devhelp,
-	[AC_HELP_STRING([--disable-devhelp],
+	[AS_HELP_STRING([--disable-devhelp],
 		[disable building index for devhelp documentation browser])],
 	enable_devhelp="$enableval", enable_devhelp="yes")
 
@@ -2662,7 +2664,7 @@
 AM_CONDITIONAL(HAVE_DOXYGEN, test "x$enable_doxygen" = "xyes")
 AM_CONDITIONAL(HAVE_XSLTPROC, test "x$enable_devhelp" = "xyes")
 
-AC_ARG_ENABLE(debug, [AC_HELP_STRING([--enable-debug],
+AC_ARG_ENABLE(debug, [AS_HELP_STRING([--enable-debug],
 	[compile with debugging support])], , enable_debug=no)
 
 if test "x$enable_debug" = "xyes" ; then
@@ -2783,7 +2785,6 @@
 echo Use startup notification...... : $enable_startup_notification
 echo Build with GtkSpell support... : $enable_gtkspell
 echo Build with GCR widgets........ : $enable_gcr
-echo Build with JSON support....... : $enable_json
 echo
 echo Build with plugin support..... : $enable_plugins
 echo Build with Mono support....... : $enable_mono
--- a/doc/account-signals.dox	Sat Feb 02 18:29:35 2013 +0100
+++ b/doc/account-signals.dox	Sat Feb 02 21:20:08 2013 +0100
@@ -14,7 +14,6 @@
   @signal account-actions-changed
   @signal account-alias-changed
   @signal account-authorization-requested
-  @signal account-authorization-requested-with-message
   @signal account-authorization-denied
   @signal account-authorization-granted
   @signal account-error-changed
@@ -145,51 +144,41 @@
 
  @signaldef account-authorization-requested
   @signalproto
-int (*account_authorization_requested)(PurpleAccount *account, const char *user);
+int (*account_authorization_requested)(PurpleAccount *account, const char *user, const char *message, char **response);
   @endsignalproto
   @signaldesc
    Emitted when a user requests authorization.
-  @param account The account.
-  @param user    The name of the user requesting authorization.
-  @return Less than zero to deny the request without prompting, greater
-          than zero if the request should be granted. If zero is returned,
-          then the user will be prompted with the request.
- @endsignaldef
-
- @signaldef account-authorization-requested-with-message
-  @signalproto
-int (*account_authorization_requested)(PurpleAccount *account, const char *user, const char *message);
-  @endsignalproto
-  @signaldesc
-   Emitted when a user requests authorization.
-  @param account The account.
-  @param user    The name of the user requesting authorization.
-  @param message The authorization request message
+  @param account  The account.
+  @param user     The name of the user requesting authorization.
+  @param message  The authorization request message.
+  @param response The message to send in the response.
   @return PURPLE_ACCOUNT_RESPONSE_IGNORE to silently ignore the request,
           PURPLE_ACCOUNT_RESPONSE_DENY to block the request (the sender might
-          get informed, PURPLE_ACCOUNT_RESPONSE_ACCEPT if the request should be
+          get informed), PURPLE_ACCOUNT_RESPONSE_ACCEPT if the request should be
           granted. If PURPLE_ACCOUNT_RESPONSE_PASS is returned, then the user
           will be prompted with the request.
  @endsignaldef
 
  @signaldef account-authorization-denied
   @signalproto
-void (*account_authorization_denied)(PurpleAccount *account, const char *user);
+void (*account_authorization_denied)(PurpleAccount *account, const char *user, const char *message);
   @endsignalproto
   @signaldesc
    Emitted when the authorization request for a buddy is denied.
   @param account The account.
   @param user    The name of the user requesting authorization.
+  @param message The message to tell the buddy who was denied.
  @endsignaldef
 
  @signaldef account-authorization-granted
   @signalproto
-void (*account_authorization_granted)(PurpleAccount *account, const char *user);
+void (*account_authorization_granted)(PurpleAccount *account, const char *user, const char *message);
   @endsignalproto
   @signaldesc
    Emitted when the authorization request for a buddy is granted.
   @param account The account.
   @param user    The name of the user requesting authorization.
+  @param message The message to tell the buddy who was granted authorization.
  @endsignaldef
 
  @signaldef account-error-changed
--- a/finch/finch.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/finch/finch.c	Sat Feb 02 21:20:08 2013 +0100
@@ -219,11 +219,7 @@
 	gnt_input_add,
 	g_source_remove,
 	NULL, /* input_get_error */
-#if GLIB_CHECK_VERSION(2,14,0)
 	g_timeout_add_seconds,
-#else
-	NULL,
-#endif
 
 	/* padding */
 	NULL,
@@ -381,19 +377,12 @@
 		abort();
 	}
 
-	/* TODO: Move blist loading into purple_blist_init() */
-	purple_set_blist(purple_blist_new());
-	purple_blist_load();
-
 	/* TODO: should this be moved into finch_prefs_init() ? */
 	finch_prefs_update_old();
 
 	/* load plugins we had when we quit */
 	purple_plugins_load_saved("/finch/plugins/loaded");
 
-	/* TODO: Move pounces loading into purple_pounces_init() */
-	purple_pounces_load();
-
 	if (opt_nologin)
 	{
 		/* Set all accounts to "offline" */
--- a/finch/gntaccount.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/finch/gntaccount.c	Sat Feb 02 21:20:08 2013 +0100
@@ -1036,7 +1036,7 @@
 static void
 authorize_and_add_cb(auth_and_add *aa)
 {
-	aa->auth_cb(aa->data);
+	aa->auth_cb(NULL, aa->data);
 	purple_blist_request_add_buddy(aa->account, aa->username,
 	 	                    NULL, aa->alias);
 }
@@ -1044,7 +1044,7 @@
 static void
 deny_no_add_cb(auth_and_add *aa)
 {
-	aa->deny_cb(aa->data);
+	aa->deny_cb(NULL, aa->data);
 }
 
 static void *
--- a/finch/gntconv.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/finch/gntconv.c	Sat Feb 02 21:20:08 2013 +0100
@@ -383,7 +383,7 @@
 			purple_conversation_write(conv, NULL, _("The account has disconnected and you are no "
 						"longer in this chat. You will be automatically rejoined in the chat when "
 						"the account reconnects."),
-					PURPLE_MESSAGE_SYSTEM, time(NULL));
+					PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));
 		}
 		list = list->next;
 	}
--- a/finch/libgnt/gnt.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/finch/libgnt/gnt.h	Sat Feb 02 21:20:08 2013 +0100
@@ -40,19 +40,6 @@
 #include "gntkeys.h"
 
 /**
- * Get things to compile in Glib < 2.8
- */
-#if !GLIB_CHECK_VERSION(2,8,0)
-	#define G_PARAM_STATIC_NAME  G_PARAM_PRIVATE
-	#define G_PARAM_STATIC_NICK  G_PARAM_PRIVATE
-	#define G_PARAM_STATIC_BLURB  G_PARAM_PRIVATE
-#endif
-
-#if !GLIB_CHECK_VERSION(2,14,0)
-	#define g_timeout_add_seconds(time, callback, data)  g_timeout_add(time * 1000, callback, data)
-#endif
-
-/**
  * Initialize GNT.
  */
 void gnt_init(void);
--- a/finch/libgnt/gntcolors.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/finch/libgnt/gntcolors.c	Sat Feb 02 21:20:08 2013 +0100
@@ -142,7 +142,6 @@
 		restore_colors();
 }
 
-#if GLIB_CHECK_VERSION(2,6,0)
 int
 gnt_colors_get_color(char *key)
 {
@@ -293,8 +292,6 @@
 	g_strfreev(keys);
 }
 
-#endif  /* GKeyFile */
-
 int gnt_color_pair(int pair)
 {
 	return (hascolors ? COLOR_PAIR(pair) :
--- a/finch/libgnt/gntcolors.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/finch/libgnt/gntcolors.h	Sat Feb 02 21:20:08 2013 +0100
@@ -71,7 +71,6 @@
  */
 void gnt_uninit_colors(void);
 
-#if GLIB_CHECK_VERSION(2,6,0)
 /**
  * Parse color information from a file.
  *
@@ -96,7 +95,6 @@
  * @since 2.4.0
  */
 int gnt_colors_get_color(char *key);
-#endif
 
 /**
  * Return the appropriate character attribute for a specified color.
--- a/finch/libgnt/gntfilesel.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/finch/libgnt/gntfilesel.c	Sat Feb 02 21:20:08 2013 +0100
@@ -66,106 +66,6 @@
 	}
 }
 
-#if !GLIB_CHECK_VERSION(2,8,0)
-/* ripped from glib/gfileutils.c */
-static gchar *
-g_build_path_va (const gchar  *separator,
-		gchar       **str_array)
-{
-	GString *result;
-	gint separator_len = strlen (separator);
-	gboolean is_first = TRUE;
-	gboolean have_leading = FALSE;
-	const gchar *single_element = NULL;
-	const gchar *next_element;
-	const gchar *last_trailing = NULL;
-	gint i = 0;
-
-	result = g_string_new (NULL);
-
-	next_element = str_array[i++];
-
-	while (TRUE) {
-		const gchar *element;
-		const gchar *start;
-		const gchar *end;
-
-		if (next_element) {
-			element = next_element;
-			next_element = str_array[i++];
-		} else
-			break;
-
-		/* Ignore empty elements */
-		if (!*element)
-			continue;
-
-		start = element;
-
-		if (separator_len) {
-			while (start &&
-					strncmp (start, separator, separator_len) == 0)
-				start += separator_len;
-		}
-
-		end = start + strlen (start);
-
-		if (separator_len) {
-			while (end >= start + separator_len &&
-					strncmp (end - separator_len, separator, separator_len) == 0)
-				end -= separator_len;
-
-			last_trailing = end;
-			while (last_trailing >= element + separator_len &&
-					strncmp (last_trailing - separator_len, separator, separator_len) == 0)
-				last_trailing -= separator_len;
-
-			if (!have_leading) {
-				/* If the leading and trailing separator strings are in the
-				 * same element and overlap, the result is exactly that element
-				 */
-				if (last_trailing <= start)
-					single_element = element;
-
-				g_string_append_len (result, element, start - element);
-				have_leading = TRUE;
-			} else
-				single_element = NULL;
-		}
-
-		if (end == start)
-			continue;
-
-		if (!is_first)
-			g_string_append (result, separator);
-
-		g_string_append_len (result, start, end - start);
-		is_first = FALSE;
-	}
-
-	if (single_element) {
-		g_string_free (result, TRUE);
-		return g_strdup (single_element);
-	} else {
-		if (last_trailing)
-			g_string_append (result, last_trailing);
-
-		return g_string_free (result, FALSE);
-	}
-}
-
-static gchar *
-g_build_pathv (const gchar  *separator,
-		gchar       **args)
-{
-	if (!args)
-		return NULL;
-
-	return g_build_path_va (separator, args);
-}
-
-#endif
-
 static char *
 process_path(const char *path)
 {
--- a/finch/libgnt/gntmain.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/finch/libgnt/gntmain.c	Sat Feb 02 21:20:08 2013 +0100
@@ -675,7 +675,6 @@
 	return gnt_clipboard_get_string(clipboard);
 }
 
-#if GLIB_CHECK_VERSION(2,4,0)
 typedef struct
 {
 	void (*callback)(int status, gpointer data);
@@ -697,13 +696,11 @@
 	refresh();
 	refresh_screen();
 }
-#endif
 
 gboolean gnt_giveup_console(const char *wd, char **argv, char **envp,
 		gint *stin, gint *stout, gint *sterr,
 		void (*callback)(int status, gpointer data), gpointer data)
 {
-#if GLIB_CHECK_VERSION(2,4,0)
 	GPid pid = 0;
 	ChildProcess *cp = NULL;
 
@@ -721,18 +718,11 @@
 	g_child_watch_add(pid, reap_child, cp);
 
 	return TRUE;
-#else
-	return FALSE;
-#endif
 }
 
 gboolean gnt_is_refugee()
 {
-#if GLIB_CHECK_VERSION(2,4,0)
 	return (wm && wm->mode == GNT_KP_MODE_WAIT_ON_CHILD);
-#else
-	return FALSE;
-#endif
 }
 
 const char *C_(const char *x)
--- a/finch/libgnt/gntprogressbar.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/finch/libgnt/gntprogressbar.c	Sat Feb 02 21:20:08 2013 +0100
@@ -36,16 +36,9 @@
 struct _GntProgressBar
 {
 	GntWidget parent;
-#if !GLIB_CHECK_VERSION(2,4,0)
-	GntProgressBarPrivate priv;
-#endif
 };
 
-#if GLIB_CHECK_VERSION(2,4,0)
 #define GNT_PROGRESS_BAR_GET_PRIVATE(o)   (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNT_TYPE_PROGRESS_BAR, GntProgressBarPrivate))
-#else
-#define GNT_PROGRESS_BAR_GET_PRIVATE(o)   &(GNT_PROGRESS_BAR(o)->priv)
-#endif
 
 static GntWidgetClass *parent_class = NULL;
 
@@ -128,9 +121,7 @@
 
 	parent_class = GNT_WIDGET_CLASS (klass);
 
-#if GLIB_CHECK_VERSION(2,4,0)
 	g_type_class_add_private (g_class, sizeof (GntProgressBarPrivate));
-#endif
 
 	parent_class->draw = gnt_progress_bar_draw;
 	parent_class->size_request = gnt_progress_bar_size_request;
--- a/finch/libgnt/gntstyle.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/finch/libgnt/gntstyle.c	Sat Feb 02 21:20:08 2013 +0100
@@ -35,9 +35,7 @@
 
 #define MAX_WORKSPACES 99
 
-#if GLIB_CHECK_VERSION(2,6,0)
 static GKeyFile *gkfile;
-#endif
 
 static char * str_styles[GNT_STYLES];
 static int int_styles[GNT_STYLES];
@@ -50,7 +48,6 @@
 
 char *gnt_style_get_from_name(const char *group, const char *key)
 {
-#if GLIB_CHECK_VERSION(2,6,0)
 	const char *prg = g_get_prgname();
 	if ((group == NULL || *group == '\0') && prg &&
 			g_key_file_has_group(gkfile, prg))
@@ -58,15 +55,11 @@
 	if (!group)
 		group = "general";
 	return g_key_file_get_value(gkfile, group, key, NULL);
-#else
-	return NULL;
-#endif
 }
 
 int
 gnt_style_get_color(char *group, char *key)
 {
-#if GLIB_CHECK_VERSION(2,6,0)
 	int fg = 0, bg = 0;
 	gsize n;
 	char **vals;
@@ -79,14 +72,10 @@
 	}
 	g_strfreev(vals);
 	return ret;
-#else
-	return 0;
-#endif
 }
 
 char **gnt_style_get_string_list(const char *group, const char *key, gsize *length)
 {
-#if GLIB_CHECK_VERSION(2,6,0)
 	const char *prg = g_get_prgname();
 	if ((group == NULL || *group == '\0') && prg &&
 			g_key_file_has_group(gkfile, prg))
@@ -94,9 +83,6 @@
 	if (!group)
 		group = "general";
 	return g_key_file_get_string_list(gkfile, group, key, length, NULL);
-#else
-	return NULL;
-#endif
 }
 
 gboolean gnt_style_get_bool(GntStyle style, gboolean def)
@@ -134,7 +120,6 @@
 	return def;
 }
 
-#if GLIB_CHECK_VERSION(2,6,0)
 static void
 refine(char *text)
 {
@@ -175,11 +160,9 @@
 {
 	return (char *)gnt_key_translate(key);
 }
-#endif
 
 void gnt_style_read_workspaces(GntWM *wm)
 {
-#if GLIB_CHECK_VERSION(2,6,0)
 	int i;
 	gchar *name;
 	gsize c;
@@ -212,11 +195,10 @@
 			g_strfreev(titles);
 		}
 	}
-#endif
 }
+
 void gnt_style_read_actions(GType type, GntBindableClass *klass)
 {
-#if GLIB_CHECK_VERSION(2,6,0)
 	char *name;
 	GError *error = NULL;
 
@@ -264,12 +246,10 @@
 		g_strfreev(keys);
 	}
 	g_free(name);
-#endif
 }
 
 gboolean gnt_style_read_menu_accels(const char *name, GHashTable *table)
 {
-#if GLIB_CHECK_VERSION(2,6,0)
 	char *kname;
 	GError *error = NULL;
 	gboolean ret = FALSE;
@@ -322,13 +302,10 @@
 
 	g_free(kname);
 	return ret;
-#endif
-	return FALSE;
 }
 
 void gnt_styles_get_keyremaps(GType type, GHashTable *hash)
 {
-#if GLIB_CHECK_VERSION(2,6,0)
 	char *name;
 	GError *error = NULL;
 
@@ -373,10 +350,8 @@
 	}
 
 	g_free(name);
-#endif
 }
 
-#if GLIB_CHECK_VERSION(2,6,0)
 static void
 read_general_style(GKeyFile *kfile)
 {
@@ -419,11 +394,9 @@
 	}
 	g_strfreev(keys);
 }
-#endif
 
 void gnt_style_read_configure_file(const char *filename)
 {
-#if GLIB_CHECK_VERSION(2,6,0)
 	GError *error = NULL;
 	gkfile = g_key_file_new();
 
@@ -436,7 +409,6 @@
 	}
 	gnt_colors_parse(gkfile);
 	read_general_style(gkfile);
-#endif
 }
 
 void gnt_init_styles()
@@ -458,9 +430,7 @@
 		str_styles[i] = NULL;
 	}
 
-#if GLIB_CHECK_VERSION(2,6,0)
 	g_key_file_free(gkfile);
 	gkfile = NULL;
-#endif
 }
 
--- a/finch/libgnt/gntwm.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/finch/libgnt/gntwm.c	Sat Feb 02 21:20:08 2013 +0100
@@ -37,14 +37,7 @@
 #endif
 
 #include <glib.h>
-#if GLIB_CHECK_VERSION(2,6,0)
-#	include <glib/gstdio.h>
-#else
-#	include <sys/types.h>
-#	include <sys/stat.h>
-#	include <fcntl.h>
-#	define g_fopen open
-#endif
+#include <glib/gstdio.h>
 #include <ctype.h>
 #include <gmodule.h>
 #include <stdlib.h>
@@ -337,7 +330,6 @@
 static void
 read_window_positions(GntWM *wm)
 {
-#if GLIB_CHECK_VERSION(2,6,0)
 	GKeyFile *gfile = g_key_file_new();
 	char *filename = g_build_filename(g_get_home_dir(), ".gntpositions", NULL);
 	GError *error = NULL;
@@ -379,7 +371,6 @@
 
 	g_free(filename);
 	g_key_file_free(gfile);
-#endif
 }
 
 static gboolean check_idle(gpointer n)
@@ -1753,31 +1744,6 @@
 	return FALSE;
 }
 
-#if !GLIB_CHECK_VERSION(2,4,0)
-struct
-{
-	gpointer data;
-	gpointer value;
-} table_find_data;
-
-static void
-table_find_helper(gpointer key, gpointer value, gpointer data)
-{
-	GHRFunc func = data;
-	if (func(key, value, table_find_data.data))
-		table_find_data.value = value;
-}
-
-static gpointer
-g_hash_table_find(GHashTable * table, GHRFunc func, gpointer data)
-{
-	table_find_data.data = data;
-	table_find_data.value = NULL;
-	g_hash_table_foreach(table, table_find_helper, func);
-	return table_find_data.value;
-}
-#endif
-
 static GntWS *
 new_widget_find_workspace(GntWM *wm, GntWidget *widget)
 {
--- a/libpurple/Makefile.am	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/Makefile.am	Sat Feb 02 21:20:08 2013 +0100
@@ -119,6 +119,7 @@
 	desktopitem.h \
 	eventloop.h \
 	ft.h \
+	http.h \
 	idle.h \
 	imgstore.h \
 	log.h \
@@ -313,6 +314,7 @@
 	$(GSTVIDEO_LIBS) \
 	$(GSTINTERFACES_LIBS) \
 	$(IDN_LIBS) \
+	$(JSON_LIBS) \
 	ciphers/libpurple-ciphers.la \
 	-lm
 
@@ -330,7 +332,8 @@
 	$(GSTVIDEO_CFLAGS) \
 	$(GSTINTERFACES_CFLAGS) \
 	$(IDN_CFLAGS) \
-	$(NETWORKMANAGER_CFLAGS)
+	$(NETWORKMANAGER_CFLAGS) \
+	$(JSON_CFLAGS)
 
 # INSTALL_SSL_CERTIFICATES is true when SSL_CERTIFICATES_DIR is empty.
 # We want to use SSL_CERTIFICATES_DIR when it's not empty.
--- a/libpurple/Makefile.mingw	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/Makefile.mingw	Sat Feb 02 21:20:08 2013 +0100
@@ -10,6 +10,19 @@
 TARGET = libpurple
 NEEDED_DLLS = $(LIBXML2_TOP)/bin/libxml2-2.dll
 
+ifeq ($(CYRUS_SASL), 1)
+NEEDED_DLLS += $(CYRUS_SASL_TOP)/bin/libsasl.dll
+
+CYRUS_SASL_PLUGINS = \
+                        $(CYRUS_SASL_TOP)/bin/sasl2/saslANONYMOUS.dll \
+                        $(CYRUS_SASL_TOP)/bin/sasl2/saslCRAMMD5.dll \
+                        $(CYRUS_SASL_TOP)/bin/sasl2/saslDIGESTMD5.dll \
+                        $(CYRUS_SASL_TOP)/bin/sasl2/saslGSSAPI.dll \
+                        $(CYRUS_SASL_TOP)/bin/sasl2/saslLOGIN.dll \
+                        $(CYRUS_SASL_TOP)/bin/sasl2/saslPLAIN.dll
+
+endif
+
 ##
 ## INCLUDE PATHS
 ##
@@ -39,10 +52,7 @@
 			ciphers/gchecksum.c \
 			ciphers/hmac.c \
 			ciphers/md4.c \
-			ciphers/md5.c \
 			ciphers/rc4.c \
-			ciphers/sha1.c \
-			ciphers/sha256.c \
 			circbuffer.c \
 			cmds.c \
 			connection.c \
@@ -126,6 +136,10 @@
 install_shallow: $(PURPLE_INSTALL_DIR) $(TARGET).dll
 	cp $(TARGET).dll $(PURPLE_INSTALL_DIR)
 	cp $(NEEDED_DLLS) $(PURPLE_INSTALL_DIR)
+ifeq ($(CYRUS_SASL), 1)
+	mkdir -p $(PURPLE_INSTALL_DIR)/sasl2
+	cp $(CYRUS_SASL_PLUGINS) $(PURPLE_INSTALL_DIR)/sasl2
+endif
 
 install: install_shallow all
 	$(MAKE) -C $(PURPLE_PROTOS_TOP) -f $(MINGW_MAKEFILE) install
--- a/libpurple/account.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/account.c	Sat Feb 02 21:20:08 2013 +0100
@@ -1378,33 +1378,33 @@
 }
 
 static void
-request_auth_cb(void *data)
+request_auth_cb(const char *message, void *data)
 {
 	PurpleAccountRequestInfo *info = data;
 
 	handles = g_list_remove(handles, info);
 
 	if (info->auth_cb != NULL)
-		info->auth_cb(info->userdata);
+		info->auth_cb(message, info->userdata);
 
 	purple_signal_emit(purple_accounts_get_handle(),
-			"account-authorization-granted", info->account, info->user);
+			"account-authorization-granted", info->account, info->user, message);
 
 	purple_account_request_info_unref(info);
 }
 
 static void
-request_deny_cb(void *data)
+request_deny_cb(const char *message, void *data)
 {
 	PurpleAccountRequestInfo *info = data;
 
 	handles = g_list_remove(handles, info);
 
 	if (info->deny_cb != NULL)
-		info->deny_cb(info->userdata);
+		info->deny_cb(message, info->userdata);
 
 	purple_signal_emit(purple_accounts_get_handle(),
-			"account-authorization-denied", info->account, info->user);
+			"account-authorization-denied", info->account, info->user, message);
 
 	purple_account_request_info_unref(info);
 }
@@ -1417,6 +1417,7 @@
 	PurpleAccountUiOps *ui_ops;
 	PurpleAccountRequestInfo *info;
 	int plugin_return;
+	char *response = NULL;
 
 	g_return_val_if_fail(account     != NULL, NULL);
 	g_return_val_if_fail(remote_user != NULL, NULL);
@@ -1424,40 +1425,31 @@
 	ui_ops = purple_accounts_get_ui_ops();
 
 	plugin_return = GPOINTER_TO_INT(
-			purple_signal_emit_return_1(purple_accounts_get_handle(),
-				"account-authorization-requested", account, remote_user));
-
-	if (plugin_return > 0) {
-		if (auth_cb != NULL)
-			auth_cb(user_data);
-		return NULL;
-	} else if (plugin_return < 0) {
-		if (deny_cb != NULL)
-			deny_cb(user_data);
-		return NULL;
-	}
-
-	plugin_return = GPOINTER_TO_INT(
 			purple_signal_emit_return_1(
 				purple_accounts_get_handle(),
-				"account-authorization-requested-with-message",
-				account, remote_user, message
+				"account-authorization-requested",
+				account, remote_user, message, &response
 			));
 
 	switch (plugin_return)
 	{
 		case PURPLE_ACCOUNT_RESPONSE_IGNORE:
+			g_free(response);
 			return NULL;
 		case PURPLE_ACCOUNT_RESPONSE_ACCEPT:
 			if (auth_cb != NULL)
-				auth_cb(user_data);
+				auth_cb(response, user_data);
+			g_free(response);
 			return NULL;
 		case PURPLE_ACCOUNT_RESPONSE_DENY:
 			if (deny_cb != NULL)
-				deny_cb(user_data);
+				deny_cb(response, user_data);
+			g_free(response);
 			return NULL;
 	}
 
+	g_free(response);
+
 	if (ui_ops != NULL && ui_ops->request_authorize != NULL) {
 		info            = g_new0(PurpleAccountRequestInfo, 1);
 		info->type      = PURPLE_ACCOUNT_REQUEST_AUTHORIZATION;
@@ -3088,29 +3080,26 @@
 						 purple_value_new(PURPLE_TYPE_STRING));
 
 	purple_signal_register(handle, "account-authorization-requested",
-						purple_marshal_INT__POINTER_POINTER,
-						purple_value_new(PURPLE_TYPE_INT), 2,
+						purple_marshal_INT__POINTER_POINTER_POINTER,
+						purple_value_new(PURPLE_TYPE_INT), 4,
 						purple_value_new(PURPLE_TYPE_SUBTYPE,
 										PURPLE_SUBTYPE_ACCOUNT),
+						purple_value_new(PURPLE_TYPE_STRING),
+						purple_value_new(PURPLE_TYPE_STRING),
 						purple_value_new(PURPLE_TYPE_STRING));
 
-	purple_signal_register(handle, "account-authorization-requested-with-message",
-						purple_marshal_INT__POINTER_POINTER_POINTER,
-						purple_value_new(PURPLE_TYPE_INT), 3,
+	purple_signal_register(handle, "account-authorization-denied",
+						purple_marshal_VOID__POINTER_POINTER, NULL, 3,
 						purple_value_new(PURPLE_TYPE_SUBTYPE,
 										PURPLE_SUBTYPE_ACCOUNT),
 						purple_value_new(PURPLE_TYPE_STRING),
 						purple_value_new(PURPLE_TYPE_STRING));
-	purple_signal_register(handle, "account-authorization-denied",
-						purple_marshal_VOID__POINTER_POINTER, NULL, 2,
+
+	purple_signal_register(handle, "account-authorization-granted",
+						purple_marshal_VOID__POINTER_POINTER, NULL, 3,
 						purple_value_new(PURPLE_TYPE_SUBTYPE,
 										PURPLE_SUBTYPE_ACCOUNT),
-						purple_value_new(PURPLE_TYPE_STRING));
-
-	purple_signal_register(handle, "account-authorization-granted",
-						purple_marshal_VOID__POINTER_POINTER, NULL, 2,
-						purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
+						purple_value_new(PURPLE_TYPE_STRING),
 						purple_value_new(PURPLE_TYPE_STRING));
 
 	purple_signal_register(handle, "account-error-changed",
--- a/libpurple/account.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/account.h	Sat Feb 02 21:20:08 2013 +0100
@@ -36,7 +36,7 @@
 typedef struct _PurpleAccount      PurpleAccount;
 
 typedef gboolean (*PurpleFilterAccountFunc)(PurpleAccount *account);
-typedef void (*PurpleAccountRequestAuthorizationCb)(void *);
+typedef void (*PurpleAccountRequestAuthorizationCb)(const char *, void *);
 typedef void (*PurpleAccountRegistrationCb)(PurpleAccount *account, gboolean succeeded, void *user_data);
 typedef void (*PurpleAccountUnregistrationCb)(PurpleAccount *account, gboolean succeeded, void *user_data);
 typedef void (*PurpleSetPublicAliasSuccessCallback)(PurpleAccount *account, const char *new_alias);
@@ -97,7 +97,8 @@
 
 	/** Prompt for authorization when someone adds this account to their buddy
 	 * list.  To authorize them to see this account's presence, call \a
-	 * authorize_cb (\a user_data); otherwise call \a deny_cb (\a user_data);
+	 * authorize_cb (\a message, \a user_data); otherwise call
+	 * \a deny_cb (\a message, \a user_data);
 	 * @return a UI-specific handle, as passed to #close_account_request.
 	 */
 	void *(*request_authorize)(PurpleAccount *account,
--- a/libpurple/blist.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/blist.c	Sat Feb 02 21:20:08 2013 +0100
@@ -597,9 +597,8 @@
 	}
 }
 
-/* TODO: Make static and rename to load_blist */
-void
-purple_blist_load()
+static void
+load_blist(void)
 {
 	xmlnode *purple, *blist, *privacy;
 
@@ -721,7 +720,8 @@
  * Public API functions                                                      *
  *****************************************************************************/
 
-PurpleBuddyList *purple_blist_new()
+void
+purple_blist_boot(void)
 {
 	PurpleBlistUiOps *ui_ops;
 	GList *account;
@@ -749,13 +749,9 @@
 	if (ui_ops != NULL && ui_ops->new_list != NULL)
 		ui_ops->new_list(gbl);
 
-	return gbl;
-}
-
-void
-purple_set_blist(PurpleBuddyList *list)
-{
-	purplebuddylist = list;
+	purplebuddylist = gbl;
+
+	load_blist();
 }
 
 PurpleBuddyList *
--- a/libpurple/blist.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/blist.h	Sat Feb 02 21:20:08 2013 +0100
@@ -252,22 +252,6 @@
 /*@{*/
 
 /**
- * Creates a new buddy list
- *
- * @return The new buddy list.
- * @deprecated In 3.0.0, this will be handled by purple_blist_init()
- */
-PurpleBuddyList *purple_blist_new(void);
-
-/**
- * Sets the main buddy list.
- *
- * @param blist The buddy list you want to use.
- * @deprecated In 3.0.0, this will be handled by purple_blist_init()
- */
-void purple_set_blist(PurpleBuddyList *blist);
-
-/**
  * Returns the main buddy list.
  *
  * @return The main buddy list.
@@ -1008,11 +992,6 @@
 /****************************************************************************************/
 
 /**
- * Loads the buddy list from ~/.purple/blist.xml.
- */
-void purple_blist_load(void);
-
-/**
  * Schedule a save of the blist.xml file.  This is used by the privacy
  * API whenever the privacy settings are changed.  If you make a change
  * to blist.xml using one of the functions in the buddy list API, then
@@ -1204,6 +1183,13 @@
 void purple_blist_init(void);
 
 /**
+ * Loads the buddy list.
+ *
+ * You shouldn't call this. purple_core_init() will do it for you.
+ */
+void purple_blist_boot(void);
+
+/**
  * Uninitializes the buddy list subsystem.
  */
 void purple_blist_uninit(void);
--- a/libpurple/buddyicon.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/buddyicon.c	Sat Feb 02 21:20:08 2013 +0100
@@ -42,7 +42,7 @@
 	                                the icon data.                       */
 	char *username;            /**< The username the icon belongs to.    */
 	char *checksum;            /**< The protocol checksum.               */
-	int ref_count;             /**< The buddy icon reference count.      */
+	unsigned int ref_count;    /**< The buddy icon reference count.      */
 };
 
 /**
@@ -75,7 +75,7 @@
 static GHashTable *icon_data_cache = NULL;
 
 /**
- * This hash table contains references counts for how many times each
+ * This hash table contains reference counts for how many times each
  * icon in the ~/.purple/icons/ directory is being used.  It's pretty
  * crazy.  It maintains the reference count across sessions, too, so
  * if you exit Pidgin then this hash table is reconstructed the next
@@ -156,7 +156,7 @@
 	if (!purple_buddy_icons_is_caching())
 		return;
 
-	dirname  = purple_buddy_icons_get_cache_dir();
+	dirname = purple_buddy_icons_get_cache_dir();
 	path = g_build_filename(dirname, purple_imgstore_get_filename(img), NULL);
 
 	if (!g_file_test(dirname, G_FILE_TEST_IS_DIR))
@@ -189,7 +189,7 @@
 	if (GPOINTER_TO_INT(g_hash_table_lookup(icon_file_cache, filename)))
 		return;
 
-	dirname  = purple_buddy_icons_get_cache_dir();
+	dirname = purple_buddy_icons_get_cache_dir();
 	path = g_build_filename(dirname, filename, NULL);
 
 	if (g_file_test(path, G_FILE_TEST_EXISTS))
@@ -243,36 +243,26 @@
 }
 
 static PurpleStoredImage *
-purple_buddy_icon_data_new(guchar *icon_data, size_t icon_len, const char *filename)
+purple_buddy_icon_data_new(guchar *icon_data, size_t icon_len)
 {
 	char *file;
 	PurpleStoredImage *img;
 
 	g_return_val_if_fail(icon_data != NULL, NULL);
-	g_return_val_if_fail(icon_len  > 0,     NULL);
+	g_return_val_if_fail(icon_len > 0, NULL);
 
-	if (filename == NULL)
-	{
-		file = purple_util_get_image_filename(icon_data, icon_len);
-		if (file == NULL)
-		{
-			g_free(icon_data);
-			return NULL;
-		}
-	}
-	else
-		file = g_strdup(filename);
+	file = purple_util_get_image_filename(icon_data, icon_len);
 
-	if ((img = g_hash_table_lookup(icon_data_cache, file)))
-	{
+	img = g_hash_table_lookup(icon_data_cache, file);
+	if (img) {
 		g_free(file);
 		g_free(icon_data);
 		return purple_imgstore_ref(img);
 	}
 
-	img = purple_imgstore_add(icon_data, icon_len, file);
+	img = purple_imgstore_new(icon_data, icon_len, file);
 
-	/* This will take ownership of file and g_free it either now or later. */
+	/* This will take ownership of file and free it as needed */
 	g_hash_table_insert(icon_data_cache, file, img);
 
 	purple_buddy_icon_data_cache(img);
@@ -352,13 +342,13 @@
 	return icon;
 }
 
-PurpleBuddyIcon *
+void
 purple_buddy_icon_unref(PurpleBuddyIcon *icon)
 {
 	if (icon == NULL)
-		return NULL;
+		return;
 
-	g_return_val_if_fail(icon->ref_count > 0, NULL);
+	g_return_if_fail(icon->ref_count > 0);
 
 	icon->ref_count--;
 
@@ -375,11 +365,7 @@
 
 		PURPLE_DBUS_UNREGISTER_POINTER(icon);
 		g_slice_free(PurpleBuddyIcon, icon);
-
-		return NULL;
 	}
-
-	return icon;
 }
 
 void
@@ -469,7 +455,7 @@
 	if (data != NULL)
 	{
 		if (len > 0)
-			icon->img = purple_buddy_icon_data_new(data, len, NULL);
+			icon->img = purple_buddy_icon_data_new(data, len);
 		else
 			g_free(data);
 	}
@@ -638,6 +624,7 @@
 
 	if ((icon_cache == NULL) || ((icon = g_hash_table_lookup(icon_cache, username)) == NULL))
 	{
+		/* The icon is not currently cached in memory--try reading from disk */
 		PurpleBuddy *b = purple_find_buddy(account, username);
 		const char *protocol_icon_file;
 		const char *dirname;
@@ -729,9 +716,8 @@
 	PurpleStoredImage *img = NULL;
 	char *old_icon;
 
-	if (icon_data != NULL && icon_len > 0)
-	{
-		img = purple_buddy_icon_data_new(icon_data, icon_len, NULL);
+	if (icon_data != NULL && icon_len > 0) {
+		img = purple_buddy_icon_data_new(icon_data, icon_len);
 	}
 
 	old_icon = g_strdup(purple_account_get_string(account, "buddy_icon", NULL));
@@ -864,7 +850,7 @@
 	old_img = g_hash_table_lookup(pointer_icon_cache, node);
 
 	if (icon_data != NULL && icon_len > 0) {
-		img = purple_buddy_icon_data_new(icon_data, icon_len, NULL);
+		img = purple_buddy_icon_data_new(icon_data, icon_len);
 	}
 
 	old_icon = g_strdup(purple_blist_node_get_string(node,
@@ -1093,7 +1079,7 @@
 	pointer_icon_cache = g_hash_table_new(g_direct_hash, g_direct_equal);
 
     if (!cache_dir)
-    	cache_dir = g_build_filename(purple_user_dir(), "icons", NULL);
+		cache_dir = g_build_filename(purple_user_dir(), "icons", NULL);
 
 	purple_signal_connect(purple_imgstore_get_handle(), "image-deleting",
 	                      purple_buddy_icons_get_handle(),
--- a/libpurple/buddyicon.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/buddyicon.h	Sat Feb 02 21:20:08 2013 +0100
@@ -49,8 +49,8 @@
 /**
  * Creates a new buddy icon structure and populates it.
  *
- * If the buddy icon already exists, you'll get a reference to that structure,
- * which will have been updated with the data supplied.
+ * If an icon for this account+username already exists, you'll get a reference
+ * to that structure, which will have been updated with the data supplied.
  *
  * @param account   The account the user is on.
  * @param username  The username the icon belongs to.
@@ -79,10 +79,8 @@
  * If the reference count reaches 0, the icon will be destroyed.
  *
  * @param icon The buddy icon.
- *
- * @return @a icon, or @c NULL if the reference count reached 0.
  */
-PurpleBuddyIcon *purple_buddy_icon_unref(PurpleBuddyIcon *icon);
+void purple_buddy_icon_unref(PurpleBuddyIcon *icon);
 
 /**
  * Updates every instance of this icon.
@@ -331,7 +329,7 @@
 /**
  * Sets whether or not buddy icon caching is enabled.
  *
- * @param caching TRUE of buddy icon caching should be enabled, or
+ * @param caching TRUE if buddy icon caching should be enabled, or
  *                FALSE otherwise.
  */
 void purple_buddy_icons_set_caching(gboolean caching);
--- a/libpurple/certificate.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/certificate.c	Sat Feb 02 21:20:08 2013 +0100
@@ -41,53 +41,8 @@
 /** List of registered Pools */
 static GList *cert_pools = NULL;
 
-/*
- * TODO: Merge this with PurpleCertificateVerificationStatus for 3.0.0 */
-typedef enum {
-	PURPLE_CERTIFICATE_UNKNOWN_ERROR = -1,
-
-	/* Not an error */
-	PURPLE_CERTIFICATE_NO_PROBLEMS = 0,
-
-	/* Non-fatal */
-	PURPLE_CERTIFICATE_NON_FATALS_MASK = 0x0000FFFF,
-
-	/* The certificate is self-signed. */
-	PURPLE_CERTIFICATE_SELF_SIGNED = 0x01,
-
-	/* The CA is not in libpurple's pool of certificates. */
-	PURPLE_CERTIFICATE_CA_UNKNOWN = 0x02,
-
-	/* The current time is before the certificate's specified
-	 * activation time.
-	 */
-	PURPLE_CERTIFICATE_NOT_ACTIVATED = 0x04,
-
-	/* The current time is after the certificate's specified expiration time */
-	PURPLE_CERTIFICATE_EXPIRED = 0x08,
-
-	/* The certificate's subject name doesn't match the expected */
-	PURPLE_CERTIFICATE_NAME_MISMATCH = 0x10,
-
-	/* No CA pool was found. This shouldn't happen... */
-	PURPLE_CERTIFICATE_NO_CA_POOL = 0x20,
-
-	/* Fatal */
-	PURPLE_CERTIFICATE_FATALS_MASK = 0xFFFF0000,
-
-	/* The signature chain could not be validated. Due to limitations in the
-	 * the current API, this also indicates one of the CA certificates in the
-	 * chain is expired (or not yet activated). FIXME 3.0.0 */
-	PURPLE_CERTIFICATE_INVALID_CHAIN = 0x10000,
-
-	/* The signature has been revoked. */
-	PURPLE_CERTIFICATE_REVOKED = 0x20000,
-
-	PURPLE_CERTIFICATE_LAST = 0x40000,
-} PurpleCertificateInvalidityFlags;
-
 static const gchar *
-invalidity_reason_to_string(PurpleCertificateInvalidityFlags flag)
+invalidity_reason_to_string(PurpleCertificateVerificationStatus flag)
 {
 	switch (flag) {
 		case PURPLE_CERTIFICATE_SELF_SIGNED:
@@ -121,6 +76,9 @@
 		case PURPLE_CERTIFICATE_REVOKED:
 			return _("The certificate has been revoked.");
 			break;
+		case PURPLE_CERTIFICATE_REJECTED:
+			return _("The certificate was rejected by the user.");
+			break;
 		case PURPLE_CERTIFICATE_UNKNOWN_ERROR:
 		default:
 			return _("An unknown certificate error occurred.");
@@ -700,7 +658,7 @@
 			  "VRQ on cert from %s rejected\n",
 			  vrq->subject_name);
 
-	purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_INVALID);
+	purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_REJECTED);
 }
 
 static void
@@ -1319,7 +1277,7 @@
 
 	purple_debug_warning("certificate/x509/tls_cached", "User REJECTED cert\n");
 
-	purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_INVALID);
+	purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_REJECTED);
 }
 
 /** Validates a certificate by asking the user
@@ -1351,11 +1309,11 @@
 
 static void
 x509_tls_cached_unknown_peer(PurpleCertificateVerificationRequest *vrq,
-                             PurpleCertificateInvalidityFlags flags);
+                             PurpleCertificateVerificationStatus flags);
 
 static void
 x509_tls_cached_complete(PurpleCertificateVerificationRequest *vrq,
-                         PurpleCertificateInvalidityFlags flags)
+                         PurpleCertificateVerificationStatus flags)
 {
 	PurpleCertificatePool *tls_peers;
 	PurpleCertificate *peer_crt = vrq->cert_chain->data;
@@ -1377,13 +1335,16 @@
 		secondary = g_strconcat(tmp, " ", error, NULL);
 		g_free(tmp);
 
+		purple_debug_error("certificate/x509/tls_cached",
+		                   "Unable to validate certificate: %s\n", secondary);
+
 		purple_notify_error(NULL, /* TODO: Probably wrong. */
 					_("SSL Certificate Error"),
 					_("Unable to validate certificate"),
 					secondary);
 		g_free(secondary);
 
-		purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_INVALID);
+		purple_certificate_verify_complete(vrq, flags);
 		return;
 	} else if (flags & PURPLE_CERTIFICATE_NON_FATALS_MASK) {
 		/* Non-fatal error. Prompt the user. */
@@ -1448,7 +1409,7 @@
 
 static void
 x509_tls_cached_cert_in_cache(PurpleCertificateVerificationRequest *vrq,
-                              PurpleCertificateInvalidityFlags flags)
+                              PurpleCertificateVerificationStatus flags)
 {
 	/* TODO: Looking this up by name over and over is expensive.
 	   Fix, please! */
@@ -1502,7 +1463,7 @@
  */
 static void
 x509_tls_cached_check_subject_name(PurpleCertificateVerificationRequest *vrq,
-                                   PurpleCertificateInvalidityFlags flags)
+                                   PurpleCertificateVerificationStatus flags)
 {
 	PurpleCertificate *peer_crt;
 	GList *chain = vrq->cert_chain;
@@ -1531,7 +1492,7 @@
  */
 static void
 x509_tls_cached_unknown_peer(PurpleCertificateVerificationRequest *vrq,
-                             PurpleCertificateInvalidityFlags flags)
+                             PurpleCertificateVerificationStatus flags)
 {
 	PurpleCertificatePool *ca;
 	PurpleCertificate *peer_crt;
@@ -1611,7 +1572,7 @@
 	 * CA, or is a trusted CA (based on fingerprint).
 	 */
 	/* If, for whatever reason, there is no Certificate Authority pool
-	   loaded, we'll verify the subject name and then warn about thsi. */
+	   loaded, we'll verify the subject name and then warn about this. */
 	if ( !ca ) {
 		purple_debug_error("certificate/x509/tls_cached",
 				   "No X.509 Certificate Authority pool "
@@ -1637,8 +1598,6 @@
 			  "Also checking for a CA with DN=%s\n",
 			  ca2_id);
 	ca_crts = g_slist_concat(x509_ca_get_certs(ca_id), x509_ca_get_certs(ca2_id));
-	g_free(ca_id);
-	g_free(ca2_id);
 	if ( NULL == ca_crts ) {
 		flags |= PURPLE_CERTIFICATE_CA_UNKNOWN;
 
@@ -1647,6 +1606,8 @@
 				  "found. I'll prompt the user, I guess.\n");
 
 		x509_tls_cached_check_subject_name(vrq, flags);
+		g_free(ca_id);
+		g_free(ca2_id);
 		return;
 	}
 
@@ -1681,12 +1642,19 @@
 		g_byte_array_free(ca_fpr, TRUE);
 	}
 
-	if (valid == FALSE)
+	if (valid == FALSE) {
+		purple_debug_error("certificate/x509/tls_cached",
+		                   "Unable to verify final certificate %s signed by %s. "
+		                   "Not a trusted root or signed by a trusted root.\n",
+		                   ca2_id, ca_id);
 		flags |= PURPLE_CERTIFICATE_INVALID_CHAIN;
+	}
 
 	g_slist_foreach(ca_crts, (GFunc)purple_certificate_destroy, NULL);
 	g_slist_free(ca_crts);
 	g_byte_array_free(last_fpr, TRUE);
+	g_free(ca_id);
+	g_free(ca2_id);
 
 	x509_tls_cached_check_subject_name(vrq, flags);
 }
@@ -1697,7 +1665,7 @@
 	const gchar *tls_peers_name = "tls_peers"; /* Name of local cache */
 	PurpleCertificatePool *tls_peers;
 	time_t now, activation, expiration;
-	PurpleCertificateInvalidityFlags flags = PURPLE_CERTIFICATE_NO_PROBLEMS;
+	PurpleCertificateVerificationStatus flags = PURPLE_CERTIFICATE_VALID;
 	gboolean ret;
 
 	g_return_if_fail(vrq);
--- a/libpurple/certificate.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/certificate.h	Sat Feb 02 21:20:08 2013 +0100
@@ -36,8 +36,49 @@
 
 typedef enum
 {
-	PURPLE_CERTIFICATE_INVALID = 0,
-	PURPLE_CERTIFICATE_VALID = 1
+	PURPLE_CERTIFICATE_UNKNOWN_ERROR = -1,
+
+	/* Not an error */
+	PURPLE_CERTIFICATE_VALID = 0,
+
+	/* Non-fatal */
+	PURPLE_CERTIFICATE_NON_FATALS_MASK = 0x0000FFFF,
+
+	/* The certificate is self-signed. */
+	PURPLE_CERTIFICATE_SELF_SIGNED = 0x01,
+
+	/* The CA is not in libpurple's pool of certificates. */
+	PURPLE_CERTIFICATE_CA_UNKNOWN = 0x02,
+
+	/* The current time is before the certificate's specified
+	 * activation time.
+	 */
+	PURPLE_CERTIFICATE_NOT_ACTIVATED = 0x04,
+
+	/* The current time is after the certificate's specified expiration time */
+	PURPLE_CERTIFICATE_EXPIRED = 0x08,
+
+	/* The certificate's subject name doesn't match the expected */
+	PURPLE_CERTIFICATE_NAME_MISMATCH = 0x10,
+
+	/* No CA pool was found. This shouldn't happen... */
+	PURPLE_CERTIFICATE_NO_CA_POOL = 0x20,
+
+	/* Fatal */
+	PURPLE_CERTIFICATE_FATALS_MASK = 0xFFFF0000,
+
+	/* The signature chain could not be validated. Due to limitations in the
+	 * the current API, this also indicates one of the CA certificates in the
+	 * chain is expired (or not yet activated). FIXME 3.0.0 */
+	PURPLE_CERTIFICATE_INVALID_CHAIN = 0x10000,
+
+	/* The signature has been revoked. */
+	PURPLE_CERTIFICATE_REVOKED = 0x20000,
+
+	/* The certificate was rejected by the user. */
+	PURPLE_CERTIFICATE_REJECTED = 0x40000,
+
+	PURPLE_CERTIFICATE_LAST = 0x80000,
 } PurpleCertificateVerificationStatus;
 
 typedef struct _PurpleCertificate PurpleCertificate;
--- a/libpurple/ciphers/Makefile.am	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/ciphers/Makefile.am	Sat Feb 02 21:20:08 2013 +0100
@@ -5,10 +5,7 @@
 	gchecksum.c \
 	hmac.c \
 	md4.c \
-	md5.c \
-	rc4.c \
-	sha1.c \
-	sha256.c
+	rc4.c
 
 INCLUDES = -I$(top_srcdir)/libpurple
 
--- a/libpurple/ciphers/gchecksum.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/ciphers/gchecksum.c	Sat Feb 02 21:20:08 2013 +0100
@@ -1,7 +1,5 @@
 #include <cipher.h>
 
-#if GLIB_CHECK_VERSION(2,16,0)
-
 static void
 purple_g_checksum_init(PurpleCipherContext *context, GChecksumType type)
 {
@@ -19,13 +17,7 @@
     checksum = purple_cipher_context_get_data(context);
     g_return_if_fail(checksum != NULL);
 
-#if GLIB_CHECK_VERSION(2,18,0)
     g_checksum_reset(checksum);
-#else
-    g_checksum_free(checksum);
-    checksum = g_checksum_new(type);
-    purple_cipher_context_set_data(context, checksum);
-#endif
 }
 
 static void
@@ -139,6 +131,3 @@
 PURPLE_G_CHECKSUM_IMPLEMENTATION(md5, MD5, G_CHECKSUM_MD5, 64);
 PURPLE_G_CHECKSUM_IMPLEMENTATION(sha1, SHA1, G_CHECKSUM_SHA1, 64);
 PURPLE_G_CHECKSUM_IMPLEMENTATION(sha256, SHA256, G_CHECKSUM_SHA256, 64);
-
-#endif /* GLIB_CHECK_VERSION(2,16,0) */
-
--- a/libpurple/ciphers/md5.c	Sat Feb 02 18:29:35 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,326 +0,0 @@
-/*
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * Original md5
- * Copyright (C) 2001-2003  Christophe Devine <c.devine@cr0.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-#include <cipher.h>
-
-#if !GLIB_CHECK_VERSION(2,16,0)
-
-#define MD5_HMAC_BLOCK_SIZE 64
-
-struct MD5Context {
-	guint32 total[2];
-	guint32 state[4];
-	guchar buffer[64];
-};
-
-#define MD5_GET_GUINT32(n,b,i) {            \
-	(n) = ((guint32)(b) [(i)    ]      )    \
-	| ((guint32)(b) [(i) + 1] <<  8)    \
-	| ((guint32)(b) [(i) + 2] << 16)    \
-	| ((guint32)(b) [(i) + 3] << 24);   \
-}
-#define MD5_PUT_GUINT32(n,b,i) {            \
-	(b)[(i)    ] = (guchar)((n)      );     \
-	(b)[(i) + 1] = (guchar)((n) >>  8);     \
-	(b)[(i) + 2] = (guchar)((n) >> 16);     \
-	(b)[(i) + 3] = (guchar)((n) >> 24);     \
-}
-
-static size_t
-md5_get_block_size(PurpleCipherContext *context)
-{
-	/* This does not change (in this case) */
-	return MD5_HMAC_BLOCK_SIZE;
-}
-
-static void
-md5_init(PurpleCipherContext *context, gpointer extra) {
-	struct MD5Context *md5_context;
-
-	md5_context = g_new0(struct MD5Context, 1);
-
-	purple_cipher_context_set_data(context, md5_context);
-
-	purple_cipher_context_reset(context, extra);
-}
-
-static void
-md5_reset(PurpleCipherContext *context, gpointer extra) {
-	struct MD5Context *md5_context;
-
-	md5_context = purple_cipher_context_get_data(context);
-
-	md5_context->total[0] = 0;
-	md5_context->total[1] = 0;
-
-	md5_context->state[0] = 0x67452301;
-	md5_context->state[1] = 0xEFCDAB89;
-	md5_context->state[2] = 0x98BADCFE;
-	md5_context->state[3] = 0x10325476;
-
-	memset(md5_context->buffer, 0, sizeof(md5_context->buffer));
-}
-
-static void
-md5_uninit(PurpleCipherContext *context) {
-	struct MD5Context *md5_context;
-
-	purple_cipher_context_reset(context, NULL);
-
-	md5_context = purple_cipher_context_get_data(context);
-	memset(md5_context, 0, sizeof(*md5_context));
-
-	g_free(md5_context);
-	md5_context = NULL;
-}
-
-static void
-md5_process(struct MD5Context *md5_context, const guchar data[64]) {
-	guint32 X[16], A, B, C, D;
-
-	A = md5_context->state[0];
-	B = md5_context->state[1];
-	C = md5_context->state[2];
-	D = md5_context->state[3];
-
-	MD5_GET_GUINT32(X[ 0], data,  0);
-	MD5_GET_GUINT32(X[ 1], data,  4);
-	MD5_GET_GUINT32(X[ 2], data,  8);
-	MD5_GET_GUINT32(X[ 3], data, 12);
-	MD5_GET_GUINT32(X[ 4], data, 16);
-	MD5_GET_GUINT32(X[ 5], data, 20);
-	MD5_GET_GUINT32(X[ 6], data, 24);
-	MD5_GET_GUINT32(X[ 7], data, 28);
-	MD5_GET_GUINT32(X[ 8], data, 32);
-	MD5_GET_GUINT32(X[ 9], data, 36);
-	MD5_GET_GUINT32(X[10], data, 40);
-	MD5_GET_GUINT32(X[11], data, 44);
-	MD5_GET_GUINT32(X[12], data, 48);
-	MD5_GET_GUINT32(X[13], data, 52);
-	MD5_GET_GUINT32(X[14], data, 56);
-	MD5_GET_GUINT32(X[15], data, 60);
-
-#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
-#define P(a,b,c,d,k,s,t) {      \
-	a += F(b,c,d) + X[k] + t;   \
-	a = S(a,s) + b;             \
-}
-
-	/* first pass */
-#define F(x,y,z) (z ^ (x & (y ^ z)))
-	P(A, B, C, D,  0,  7, 0xD76AA478);
-	P(D, A, B, C,  1, 12, 0xE8C7B756);
-	P(C, D, A, B,  2, 17, 0x242070DB);
-	P(B, C, D, A,  3, 22, 0xC1BDCEEE);
-	P(A, B, C, D,  4,  7, 0xF57C0FAF);
-	P(D, A, B, C,  5, 12, 0x4787C62A);
-	P(C, D, A, B,  6, 17, 0xA8304613);
-	P(B, C, D, A,  7, 22, 0xFD469501);
-	P(A, B, C, D,  8,  7, 0x698098D8);
-	P(D, A, B, C,  9, 12, 0x8B44F7AF);
-	P(C, D, A, B, 10, 17, 0xFFFF5BB1);
-	P(B, C, D, A, 11, 22, 0x895CD7BE);
-	P(A, B, C, D, 12,  7, 0x6B901122);
-	P(D, A, B, C, 13, 12, 0xFD987193);
-	P(C, D, A, B, 14, 17, 0xA679438E);
-	P(B, C, D, A, 15, 22, 0x49B40821);
-#undef F
-
-	/* second pass */
-#define F(x,y,z) (y ^ (z & (x ^ y)))
-	P(A, B, C, D,  1,  5, 0xF61E2562);
-	P(D, A, B, C,  6,  9, 0xC040B340);
-	P(C, D, A, B, 11, 14, 0x265E5A51);
-	P(B, C, D, A,  0, 20, 0xE9B6C7AA);
-	P(A, B, C, D,  5,  5, 0xD62F105D);
-	P(D, A, B, C, 10,  9, 0x02441453);
-	P(C, D, A, B, 15, 14, 0xD8A1E681);
-	P(B, C, D, A,  4, 20, 0xE7D3FBC8);
-	P(A, B, C, D,  9,  5, 0x21E1CDE6);
-	P(D, A, B, C, 14,  9, 0xC33707D6);
-	P(C, D, A, B,  3, 14, 0xF4D50D87);
-	P(B, C, D, A,  8, 20, 0x455A14ED);
-	P(A, B, C, D, 13,  5, 0xA9E3E905);
-	P(D, A, B, C,  2,  9, 0xFCEFA3F8);
-	P(C, D, A, B,  7, 14, 0x676F02D9);
-	P(B, C, D, A, 12, 20, 0x8D2A4C8A);
-#undef F
-
-	/* third pass */
-#define F(x,y,z) (x ^ y ^ z)
-	P(A, B, C, D,  5,  4, 0xFFFA3942);
-	P(D, A, B, C,  8, 11, 0x8771F681);
-	P(C, D, A, B, 11, 16, 0x6D9D6122);
-	P(B, C, D, A, 14, 23, 0xFDE5380C);
-	P(A, B, C, D,  1,  4, 0xA4BEEA44);
-	P(D, A, B, C,  4, 11, 0x4BDECFA9);
-	P(C, D, A, B,  7, 16, 0xF6BB4B60);
-	P(B, C, D, A, 10, 23, 0xBEBFBC70);
-	P(A, B, C, D, 13,  4, 0x289B7EC6);
-	P(D, A, B, C,  0, 11, 0xEAA127FA);
-	P(C, D, A, B,  3, 16, 0xD4EF3085);
-	P(B, C, D, A,  6, 23, 0x04881D05);
-	P(A, B, C, D,  9,  4, 0xD9D4D039);
-	P(D, A, B, C, 12, 11, 0xE6DB99E5);
-	P(C, D, A, B, 15, 16, 0x1FA27CF8);
-	P(B, C, D, A,  2, 23, 0xC4AC5665);
-#undef F
-
-	/* forth pass */
-#define F(x,y,z) (y ^ (x | ~z))
-	P(A, B, C, D,  0,  6, 0xF4292244);
-	P(D, A, B, C,  7, 10, 0x432AFF97);
-	P(C, D, A, B, 14, 15, 0xAB9423A7);
-	P(B, C, D, A,  5, 21, 0xFC93A039);
-	P(A, B, C, D, 12,  6, 0x655B59C3);
-	P(D, A, B, C,  3, 10, 0x8F0CCC92);
-	P(C, D, A, B, 10, 15, 0xFFEFF47D);
-	P(B, C, D, A,  1, 21, 0x85845DD1);
-	P(A, B, C, D,  8,  6, 0x6FA87E4F);
-	P(D, A, B, C, 15, 10, 0xFE2CE6E0);
-	P(C, D, A, B,  6, 15, 0xA3014314);
-	P(B, C, D, A, 13, 21, 0x4E0811A1);
-	P(A, B, C, D,  4,  6, 0xF7537E82);
-	P(D, A, B, C, 11, 10, 0xBD3AF235);
-	P(C, D, A, B,  2, 15, 0x2AD7D2BB);
-	P(B, C, D, A,  9, 21, 0xEB86D391);
-#undef F
-#undef P
-#undef S
-
-	md5_context->state[0] += A;
-	md5_context->state[1] += B;
-	md5_context->state[2] += C;
-	md5_context->state[3] += D;
-	}
-
-static void
-md5_append(PurpleCipherContext *context, const guchar *data, size_t len) {
-	struct MD5Context *md5_context = NULL;
-	guint32 left = 0, fill = 0;
-
-	g_return_if_fail(context != NULL);
-
-	md5_context = purple_cipher_context_get_data(context);
-	g_return_if_fail(md5_context != NULL);
-
-	left = md5_context->total[0] & 0x3F;
-	fill = 64 - left;
-
-	md5_context->total[0] += len;
-	md5_context->total[0] &= 0xFFFFFFFF;
-
-	if(md5_context->total[0] < len)
-		md5_context->total[1]++;
-
-	if(left && len >= fill) {
-		memcpy((md5_context->buffer + left), data, fill);
-		md5_process(md5_context, md5_context->buffer);
-		len -= fill;
-		data += fill;
-		left = 0;
-	}
-
-	while(len >= 64) {
-		md5_process(md5_context, data);
-		len -= 64;
-		data += 64;
-	}
-
-	if(len) {
-		memcpy((md5_context->buffer + left), data, len);
-	}
-}
-
-	static gboolean
-md5_digest(PurpleCipherContext *context, size_t in_len, guchar digest[16],
-		size_t *out_len)
-{
-	struct MD5Context *md5_context = NULL;
-	guint32 last, pad;
-	guint32 high, low;
-	guchar message[8];
-	guchar padding[64] = {
-		0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-	};
-
-	g_return_val_if_fail(in_len >= 16, FALSE);
-
-	md5_context = purple_cipher_context_get_data(context);
-
-	high = (md5_context->total[0] >> 29)
-		| (md5_context->total[1] << 3);
-	low = (md5_context->total[0] << 3);
-
-	MD5_PUT_GUINT32(low, message, 0);
-	MD5_PUT_GUINT32(high, message, 4);
-
-	last = md5_context->total[0] & 0x3F;
-	pad = (last < 56) ? (56 - last) : (120 - last);
-
-	md5_append(context, padding, pad);
-	md5_append(context, message, 8);
-
-	MD5_PUT_GUINT32(md5_context->state[0], digest, 0);
-	MD5_PUT_GUINT32(md5_context->state[1], digest, 4);
-	MD5_PUT_GUINT32(md5_context->state[2], digest, 8);
-	MD5_PUT_GUINT32(md5_context->state[3], digest, 12);
-
-	if(out_len)
-		*out_len = 16;
-
-	return TRUE;
-}
-
-static PurpleCipherOps MD5Ops = {
-	NULL,			/* Set Option		*/
-	NULL,			/* Get Option		*/
-	md5_init,		/* init				*/
-	md5_reset,		/* reset			*/
-	md5_uninit,	/* uninit			*/
-	NULL,			/* set iv			*/
-	md5_append,	/* append			*/
-	md5_digest,		/* digest			*/
-	NULL,			/* encrypt			*/
-	NULL,			/* decrypt			*/
-	NULL,			/* set salt			*/
-	NULL,			/* get salt size	*/
-	NULL,			/* set key			*/
-	NULL,			/* get key size		*/
-	NULL,			/* set batch mode */
-	NULL,			/* get batch mode */
-	md5_get_block_size,	/* get block size */
-	NULL			/* set key with len */
-};
-
-PurpleCipherOps *
-purple_md5_cipher_get_ops(void) {
-	return &MD5Ops;
-}
-
-#endif /* !GLIB_CHECK_VERSION(2,16,0) */
-
--- a/libpurple/ciphers/sha1.c	Sat Feb 02 18:29:35 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,281 +0,0 @@
-/*
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-#include <cipher.h>
-#include <util.h>
-
-#if !GLIB_CHECK_VERSION(2,16,0)
-
-#define SHA1_HMAC_BLOCK_SIZE    64
-#define SHA1_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xFFFFFFFF)
-
-struct SHA1Context {
-	guint32 H[5];
-	guint32 W[80];
-
-	gint lenW;
-
-	guint32 sizeHi;
-	guint32 sizeLo;
-};
-
-static size_t
-sha1_get_block_size(PurpleCipherContext *context)
-{
-	/* This does not change (in this case) */
-	return SHA1_HMAC_BLOCK_SIZE;
-}
-
-static void
-sha1_hash_block(struct SHA1Context *sha1_ctx) {
-	gint i;
-	guint32 A, B, C, D, E, T;
-
-	for(i = 16; i < 80; i++) {
-		sha1_ctx->W[i] = SHA1_ROTL(sha1_ctx->W[i -  3] ^
-				sha1_ctx->W[i -  8] ^
-				sha1_ctx->W[i - 14] ^
-				sha1_ctx->W[i - 16], 1);
-	}
-
-	A = sha1_ctx->H[0];
-	B = sha1_ctx->H[1];
-	C = sha1_ctx->H[2];
-	D = sha1_ctx->H[3];
-	E = sha1_ctx->H[4];
-
-	for(i = 0; i < 20; i++) {
-		T = (SHA1_ROTL(A, 5) + (((C ^ D) & B) ^ D) + E + sha1_ctx->W[i] + 0x5A827999) & 0xFFFFFFFF;
-		E = D;
-		D = C;
-		C = SHA1_ROTL(B, 30);
-		B = A;
-		A = T;
-	}
-
-	for(i = 20; i < 40; i++) {
-		T = (SHA1_ROTL(A, 5) + (B ^ C ^ D) + E + sha1_ctx->W[i] + 0x6ED9EBA1) & 0xFFFFFFFF;
-		E = D;
-		D = C;
-		C = SHA1_ROTL(B, 30);
-		B = A;
-		A = T;
-	}
-
-	for(i = 40; i < 60; i++) {
-		T = (SHA1_ROTL(A, 5) + ((B & C) | (D & (B | C))) + E + sha1_ctx->W[i] + 0x8F1BBCDC) & 0xFFFFFFFF;
-		E = D;
-		D = C;
-		C = SHA1_ROTL(B, 30);
-		B = A;
-		A = T;
-	}
-
-	for(i = 60; i < 80; i++) {
-		T = (SHA1_ROTL(A, 5) + (B ^ C ^ D) + E + sha1_ctx->W[i] + 0xCA62C1D6) & 0xFFFFFFFF;
-		E = D;
-		D = C;
-		C = SHA1_ROTL(B, 30);
-		B = A;
-		A = T;
-	}
-
-	sha1_ctx->H[0] += A;
-	sha1_ctx->H[1] += B;
-	sha1_ctx->H[2] += C;
-	sha1_ctx->H[3] += D;
-	sha1_ctx->H[4] += E;
-}
-
-static void
-sha1_set_opt(PurpleCipherContext *context, const gchar *name, void *value) {
-	struct SHA1Context *ctx;
-
-	ctx = purple_cipher_context_get_data(context);
-
-	if(purple_strequal(name, "sizeHi")) {
-		ctx->sizeHi = GPOINTER_TO_INT(value);
-	} else if(purple_strequal(name, "sizeLo")) {
-		ctx->sizeLo = GPOINTER_TO_INT(value);
-	} else if(purple_strequal(name, "lenW")) {
-		ctx->lenW = GPOINTER_TO_INT(value);
-	}
-}
-
-static void *
-sha1_get_opt(PurpleCipherContext *context, const gchar *name) {
-	struct SHA1Context *ctx;
-
-	ctx = purple_cipher_context_get_data(context);
-
-	if(purple_strequal(name, "sizeHi")) {
-		return GINT_TO_POINTER(ctx->sizeHi);
-	} else if(purple_strequal(name, "sizeLo")) {
-		return GINT_TO_POINTER(ctx->sizeLo);
-	} else if(purple_strequal(name, "lenW")) {
-		return GINT_TO_POINTER(ctx->lenW);
-	}
-
-	return NULL;
-}
-
-static void
-sha1_init(PurpleCipherContext *context, void *extra) {
-	struct SHA1Context *sha1_ctx;
-
-	sha1_ctx = g_new0(struct SHA1Context, 1);
-
-	purple_cipher_context_set_data(context, sha1_ctx);
-
-	purple_cipher_context_reset(context, extra);
-}
-
-static void
-sha1_reset(PurpleCipherContext *context, void *extra) {
-	struct SHA1Context *sha1_ctx;
-	gint i;
-
-	sha1_ctx = purple_cipher_context_get_data(context);
-
-	g_return_if_fail(sha1_ctx);
-
-	sha1_ctx->lenW = 0;
-	sha1_ctx->sizeHi = 0;
-	sha1_ctx->sizeLo = 0;
-
-	sha1_ctx->H[0] = 0x67452301;
-	sha1_ctx->H[1] = 0xEFCDAB89;
-	sha1_ctx->H[2] = 0x98BADCFE;
-	sha1_ctx->H[3] = 0x10325476;
-	sha1_ctx->H[4] = 0xC3D2E1F0;
-
-	for(i = 0; i < 80; i++)
-		sha1_ctx->W[i] = 0;
-}
-
-static void
-sha1_uninit(PurpleCipherContext *context) {
-	struct SHA1Context *sha1_ctx;
-
-	purple_cipher_context_reset(context, NULL);
-
-	sha1_ctx = purple_cipher_context_get_data(context);
-
-	memset(sha1_ctx, 0, sizeof(struct SHA1Context));
-
-	g_free(sha1_ctx);
-	sha1_ctx = NULL;
-}
-
-static void
-sha1_append(PurpleCipherContext *context, const guchar *data, size_t len) {
-	struct SHA1Context *sha1_ctx;
-	gint i;
-
-	sha1_ctx = purple_cipher_context_get_data(context);
-
-	g_return_if_fail(sha1_ctx);
-
-	for(i = 0; i < len; i++) {
-		sha1_ctx->W[sha1_ctx->lenW / 4] <<= 8;
-		sha1_ctx->W[sha1_ctx->lenW / 4] |= data[i];
-
-		if((++sha1_ctx->lenW) % 64 == 0) {
-			sha1_hash_block(sha1_ctx);
-			sha1_ctx->lenW = 0;
-		}
-
-		sha1_ctx->sizeLo += 8;
-		sha1_ctx->sizeHi += (sha1_ctx->sizeLo < 8);
-	}
-}
-
-static gboolean
-sha1_digest(PurpleCipherContext *context, size_t in_len, guchar digest[20],
-            size_t *out_len)
-{
-	struct SHA1Context *sha1_ctx;
-	guchar pad0x80 = 0x80, pad0x00 = 0x00;
-	guchar padlen[8];
-	gint i;
-
-	g_return_val_if_fail(in_len >= 20, FALSE);
-
-	sha1_ctx = purple_cipher_context_get_data(context);
-
-	g_return_val_if_fail(sha1_ctx, FALSE);
-
-	padlen[0] = (guchar)((sha1_ctx->sizeHi >> 24) & 255);
-	padlen[1] = (guchar)((sha1_ctx->sizeHi >> 16) & 255);
-	padlen[2] = (guchar)((sha1_ctx->sizeHi >> 8) & 255);
-	padlen[3] = (guchar)((sha1_ctx->sizeHi >> 0) & 255);
-	padlen[4] = (guchar)((sha1_ctx->sizeLo >> 24) & 255);
-	padlen[5] = (guchar)((sha1_ctx->sizeLo >> 16) & 255);
-	padlen[6] = (guchar)((sha1_ctx->sizeLo >> 8) & 255);
-	padlen[7] = (guchar)((sha1_ctx->sizeLo >> 0) & 255);
-
-	/* pad with a 1, then zeroes, then length */
-	purple_cipher_context_append(context, &pad0x80, 1);
-	while(sha1_ctx->lenW != 56)
-		purple_cipher_context_append(context, &pad0x00, 1);
-	purple_cipher_context_append(context, padlen, 8);
-
-	for(i = 0; i < 20; i++) {
-		digest[i] = (guchar)(sha1_ctx->H[i / 4] >> 24);
-		sha1_ctx->H[i / 4] <<= 8;
-	}
-
-	purple_cipher_context_reset(context, NULL);
-
-	if(out_len)
-		*out_len = 20;
-
-	return TRUE;
-}
-
-static PurpleCipherOps SHA1Ops = {
-	sha1_set_opt,		/* Set Option		*/
-	sha1_get_opt,		/* Get Option		*/
-	sha1_init,		/* init				*/
-	sha1_reset,		/* reset			*/
-	sha1_uninit,		/* uninit			*/
-	NULL,			/* set iv			*/
-	sha1_append,		/* append			*/
-	sha1_digest,	/* digest			*/
-	NULL,			/* encrypt			*/
-	NULL,			/* decrypt			*/
-	NULL,			/* set salt			*/
-	NULL,			/* get salt size	*/
-	NULL,			/* set key			*/
-	NULL,			/* get key size		*/
-	NULL,			/* set batch mode */
-	NULL,			/* get batch mode */
-	sha1_get_block_size,	/* get block size */
-	NULL			/* set key with len */
-};
-
-PurpleCipherOps *
-purple_sha1_cipher_get_ops(void) {
-	return &SHA1Ops;
-}
-
-#endif /* !GLIB_CHECK_VERSION(2,16,0) */
-
--- a/libpurple/ciphers/sha256.c	Sat Feb 02 18:29:35 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,283 +0,0 @@
-/*
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-#include <cipher.h>
-
-#if !GLIB_CHECK_VERSION(2,16,0)
-
-#define SHA256_HMAC_BLOCK_SIZE  64
-#define SHA256_ROTR(X,n) ((((X) >> (n)) | ((X) << (32-(n)))) & 0xFFFFFFFF)
-
-static const guint32 sha256_K[64] =
-{
-	0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
-	0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
-	0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
-	0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
-	0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
-	0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
-	0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
-	0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
-};
-
-struct SHA256Context {
-	guint32 H[8];
-	guint32 W[64];
-
-	gint lenW;
-
-	guint32 sizeHi;
-	guint32 sizeLo;
-};
-
-static size_t
-sha256_get_block_size(PurpleCipherContext *context)
-{
-	/* This does not change (in this case) */
-	return SHA256_HMAC_BLOCK_SIZE;
-}
-
-static void
-sha256_hash_block(struct SHA256Context *sha256_ctx) {
-	gint i;
-	guint32 A, B, C, D, E, F, G, H, T1, T2;
-
-	for(i = 16; i < 64; i++) {
-		sha256_ctx->W[i] =
-			  (SHA256_ROTR(sha256_ctx->W[i-2], 17) ^ SHA256_ROTR(sha256_ctx->W[i-2],  19) ^ (sha256_ctx->W[i-2] >> 10))
-			+ sha256_ctx->W[i-7]
-			+ (SHA256_ROTR(sha256_ctx->W[i-15], 7) ^ SHA256_ROTR(sha256_ctx->W[i-15], 18) ^ (sha256_ctx->W[i-15] >> 3))
-			+ sha256_ctx->W[i-16];
-	}
-
-	A = sha256_ctx->H[0];
-	B = sha256_ctx->H[1];
-	C = sha256_ctx->H[2];
-	D = sha256_ctx->H[3];
-	E = sha256_ctx->H[4];
-	F = sha256_ctx->H[5];
-	G = sha256_ctx->H[6];
-	H = sha256_ctx->H[7];
-
-	for(i = 0; i < 64; i++) {
-		T1 = H
-			+ (SHA256_ROTR(E, 6) ^ SHA256_ROTR(E, 11) ^ SHA256_ROTR(E, 25))
-			+ ((E & F) ^ ((~E) & G))
-			+ sha256_K[i] + sha256_ctx->W[i];
-		T2 = (SHA256_ROTR(A, 2) ^ SHA256_ROTR(A, 13) ^ SHA256_ROTR(A, 22))
-			+ ((A & B) ^ (A & C) ^ (B & C));
-		H = G;
-		G = F;
-		F = E;
-		E = D + T1;
-		D = C;
-		C = B;
-		B = A;
-		A = T1 + T2;
-	}
-
-	sha256_ctx->H[0] += A;
-	sha256_ctx->H[1] += B;
-	sha256_ctx->H[2] += C;
-	sha256_ctx->H[3] += D;
-	sha256_ctx->H[4] += E;
-	sha256_ctx->H[5] += F;
-	sha256_ctx->H[6] += G;
-	sha256_ctx->H[7] += H;
-}
-
-static void
-sha256_set_opt(PurpleCipherContext *context, const gchar *name, void *value) {
-	struct SHA256Context *ctx;
-
-	ctx = purple_cipher_context_get_data(context);
-
-	if(!strcmp(name, "sizeHi")) {
-		ctx->sizeHi = GPOINTER_TO_INT(value);
-	} else if(!strcmp(name, "sizeLo")) {
-		ctx->sizeLo = GPOINTER_TO_INT(value);
-	} else if(!strcmp(name, "lenW")) {
-		ctx->lenW = GPOINTER_TO_INT(value);
-	}
-}
-
-static void *
-sha256_get_opt(PurpleCipherContext *context, const gchar *name) {
-	struct SHA256Context *ctx;
-
-	ctx = purple_cipher_context_get_data(context);
-
-	if(!strcmp(name, "sizeHi")) {
-		return GINT_TO_POINTER(ctx->sizeHi);
-	} else if(!strcmp(name, "sizeLo")) {
-		return GINT_TO_POINTER(ctx->sizeLo);
-	} else if(!strcmp(name, "lenW")) {
-		return GINT_TO_POINTER(ctx->lenW);
-	}
-
-	return NULL;
-}
-
-static void
-sha256_init(PurpleCipherContext *context, void *extra) {
-	struct SHA256Context *sha256_ctx;
-
-	sha256_ctx = g_new0(struct SHA256Context, 1);
-
-	purple_cipher_context_set_data(context, sha256_ctx);
-
-	purple_cipher_context_reset(context, extra);
-}
-
-static void
-sha256_reset(PurpleCipherContext *context, void *extra) {
-	struct SHA256Context *sha256_ctx;
-	gint i;
-
-	sha256_ctx = purple_cipher_context_get_data(context);
-
-	g_return_if_fail(sha256_ctx);
-
-	sha256_ctx->lenW = 0;
-	sha256_ctx->sizeHi = 0;
-	sha256_ctx->sizeLo = 0;
-
-	sha256_ctx->H[0] = 0x6a09e667;
-	sha256_ctx->H[1] = 0xbb67ae85;
-	sha256_ctx->H[2] = 0x3c6ef372;
-	sha256_ctx->H[3] = 0xa54ff53a;
-	sha256_ctx->H[4] = 0x510e527f;
-	sha256_ctx->H[5] = 0x9b05688c;
-	sha256_ctx->H[6] = 0x1f83d9ab;
-	sha256_ctx->H[7] = 0x5be0cd19;
-
-	for(i = 0; i < 64; i++)
-		sha256_ctx->W[i] = 0;
-}
-
-static void
-sha256_uninit(PurpleCipherContext *context) {
-	struct SHA256Context *sha256_ctx;
-
-	purple_cipher_context_reset(context, NULL);
-
-	sha256_ctx = purple_cipher_context_get_data(context);
-
-	memset(sha256_ctx, 0, sizeof(struct SHA256Context));
-
-	g_free(sha256_ctx);
-	sha256_ctx = NULL;
-}
-
-static void
-sha256_append(PurpleCipherContext *context, const guchar *data, size_t len) {
-	struct SHA256Context *sha256_ctx;
-	gint i;
-
-	sha256_ctx = purple_cipher_context_get_data(context);
-
-	g_return_if_fail(sha256_ctx);
-
-	for(i = 0; i < len; i++) {
-		sha256_ctx->W[sha256_ctx->lenW / 4] <<= 8;
-		sha256_ctx->W[sha256_ctx->lenW / 4] |= data[i];
-
-		if((++sha256_ctx->lenW) % 64 == 0) {
-			sha256_hash_block(sha256_ctx);
-			sha256_ctx->lenW = 0;
-		}
-
-		sha256_ctx->sizeLo += 8;
-		sha256_ctx->sizeHi += (sha256_ctx->sizeLo < 8);
-	}
-}
-
-static gboolean
-sha256_digest(PurpleCipherContext *context, size_t in_len, guchar digest[32],
-              size_t *out_len)
-{
-	struct SHA256Context *sha256_ctx;
-	guchar pad0x80 = 0x80, pad0x00 = 0x00;
-	guchar padlen[8];
-	gint i;
-
-	g_return_val_if_fail(in_len >= 32, FALSE);
-
-	sha256_ctx = purple_cipher_context_get_data(context);
-
-	g_return_val_if_fail(sha256_ctx, FALSE);
-
-	padlen[0] = (guchar)((sha256_ctx->sizeHi >> 24) & 255);
-	padlen[1] = (guchar)((sha256_ctx->sizeHi >> 16) & 255);
-	padlen[2] = (guchar)((sha256_ctx->sizeHi >> 8) & 255);
-	padlen[3] = (guchar)((sha256_ctx->sizeHi >> 0) & 255);
-	padlen[4] = (guchar)((sha256_ctx->sizeLo >> 24) & 255);
-	padlen[5] = (guchar)((sha256_ctx->sizeLo >> 16) & 255);
-	padlen[6] = (guchar)((sha256_ctx->sizeLo >> 8) & 255);
-	padlen[7] = (guchar)((sha256_ctx->sizeLo >> 0) & 255);
-
-	/* pad with a 1, then zeroes, then length */
-	purple_cipher_context_append(context, &pad0x80, 1);
-	while(sha256_ctx->lenW != 56)
-		purple_cipher_context_append(context, &pad0x00, 1);
-	purple_cipher_context_append(context, padlen, 8);
-
-	for(i = 0; i < 32; i++) {
-		digest[i] = (guchar)(sha256_ctx->H[i / 4] >> 24);
-		sha256_ctx->H[i / 4] <<= 8;
-	}
-
-	purple_cipher_context_reset(context, NULL);
-
-	if(out_len)
-		*out_len = 32;
-
-	return TRUE;
-}
-
-static PurpleCipherOps SHA256Ops = {
-	sha256_set_opt,			/* Set Option		*/
-	sha256_get_opt,			/* Get Option		*/
-	sha256_init,	/* init				*/
-	sha256_reset,	/* reset			*/
-	sha256_uninit,	/* uninit			*/
-	NULL,			/* set iv			*/
-	sha256_append,	/* append			*/
-	sha256_digest,	/* digest			*/
-	NULL,			/* encrypt			*/
-	NULL,			/* decrypt			*/
-	NULL,			/* set salt			*/
-	NULL,			/* get salt size	*/
-	NULL,			/* set key			*/
-	NULL,			/* get key size		*/
-	NULL,			/* set batch mode */
-	NULL,			/* get batch mode */
-	sha256_get_block_size,	/* get block size */
-	NULL			/* set key with len */
-};
-
-PurpleCipherOps *
-purple_sha256_cipher_get_ops(void) {
-	return &SHA256Ops;
-}
-
-#endif /* !GLIB_CHECK_VERSION(2,16,0) */
-
--- a/libpurple/core.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/core.c	Sat Feb 02 21:20:08 2013 +0100
@@ -189,6 +189,9 @@
 	/* The UI may have registered some theme types, so refresh them */
 	purple_theme_manager_refresh();
 
+	/* Load the buddy list after UI init */
+	purple_blist_boot();
+
 	return TRUE;
 }
 
@@ -261,9 +264,11 @@
 #endif
 
 	purple_cmds_uninit();
-	/* Everything after util_uninit cannot try to write things to the confdir */
+	purple_log_uninit();
+	/* Everything after util_uninit cannot try to write things to the
+	 * confdir nor use purple_escape_js
+	 */
 	purple_util_uninit();
-	purple_log_uninit();
 
 	purple_signals_uninit();
 
--- a/libpurple/example/nullclient.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/example/nullclient.c	Sat Feb 02 21:20:08 2013 +0100
@@ -103,11 +103,7 @@
 	glib_input_add,
 	g_source_remove,
 	NULL,
-#if GLIB_CHECK_VERSION(2,14,0)
 	g_timeout_add_seconds,
-#else
-	NULL,
-#endif
 
 	/* padding */
 	NULL,
@@ -218,19 +214,12 @@
 		abort();
 	}
 
-	/* Create and load the buddylist. */
-	purple_set_blist(purple_blist_new());
-	purple_blist_load();
-
 	/* Load the preferences. */
 	purple_prefs_load();
 
 	/* Load the desired plugins. The client should save the list of loaded plugins in
 	 * the preferences using purple_plugins_save_loaded(PLUGIN_SAVE_PREF) */
 	purple_plugins_load_saved(PLUGIN_SAVE_PREF);
-
-	/* Load the pounces. */
-	purple_pounces_load();
 }
 
 static void
--- a/libpurple/ft.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/ft.c	Sat Feb 02 21:20:08 2013 +0100
@@ -303,7 +303,7 @@
 	if (print_thumbnail && thumbnail_data) {
 		gchar *message_with_img;
 		gpointer data = g_memdup(thumbnail_data, size);
-		int id = purple_imgstore_add_with_id(data, size, NULL);
+		int id = purple_imgstore_new_with_id(data, size, NULL);
 
 		message_with_img =
 			g_strdup_printf("<img src='" PURPLE_STORED_IMAGE_PROTOCOL "%d'> %s",
--- a/libpurple/glibcompat.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/glibcompat.h	Sat Feb 02 21:20:08 2013 +0100
@@ -25,10 +25,6 @@
  * Also, any public API should not depend on this file.
  */
 
-#if !GLIB_CHECK_VERSION(2, 20, 0)
-
-#define G_OFFSET_FORMAT G_GINT64_FORMAT
-
 #if !GLIB_CHECK_VERSION(2, 28, 0)
 
 static inline gint64 g_get_monotonic_time(void)
@@ -53,6 +49,5 @@
 }
 
 #endif /* 2.28.0 */
-#endif /* 2.20.0 */
 
 #endif /* _PIDGINGLIBCOMPAT_H_ */
--- a/libpurple/http.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/http.c	Sat Feb 02 21:20:08 2013 +0100
@@ -2016,14 +2016,22 @@
 	return response->contents->len;
 }
 
-const gchar * purple_http_response_get_data(PurpleHttpResponse *response)
+const gchar * purple_http_response_get_data(PurpleHttpResponse *response, size_t *len)
 {
+	const gchar *ret = "";
+
 	g_return_val_if_fail(response != NULL, NULL);
 
-	if (response->contents == NULL)
-		return "";
-
-	return response->contents->str;
+	if (response->contents != NULL) {
+		ret = response->contents->str;
+		if(len)
+			*len = response->contents->len;
+	} else {
+		if(len)
+			*len = 0;
+	}
+
+	return ret;
 }
 
 const GList * purple_http_response_get_all_headers(PurpleHttpResponse *response)
--- a/libpurple/http.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/http.h	Sat Feb 02 21:20:08 2013 +0100
@@ -528,9 +528,10 @@
  * Response data is not written, if writer callback was set for request.
  *
  * @param response The response.
+ * @param len      Return address for the size of the data.  Can be NULL.
  * @return         The data.
  */
-const gchar * purple_http_response_get_data(PurpleHttpResponse *response);
+const gchar * purple_http_response_get_data(PurpleHttpResponse *response, size_t *len);
 
 /**
  * Gets all headers got with response.
--- a/libpurple/imgstore.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/imgstore.c	Sat Feb 02 21:20:08 2013 +0100
@@ -36,20 +36,20 @@
 static unsigned int nextid = 0;
 
 /*
- * NOTE: purple_imgstore_add() creates these without zeroing the memory, so
+ * NOTE: purple_imgstore_new() creates these without zeroing the memory, so
  * NOTE: make sure to update that function when adding members.
  */
 struct _PurpleStoredImage
 {
 	int id;
 	guint8 refcount;
-	size_t size;		/**< The image data's size.	*/
-	char *filename;		/**< The filename (for the UI)	*/
-	gpointer data;		/**< The image data.		*/
+	size_t size;     /**< The image data's size. */
+	char *filename;  /**< The filename (for the UI) */
+	gpointer data;   /**< The image data. */
 };
 
 PurpleStoredImage *
-purple_imgstore_add(gpointer data, size_t size, const char *filename)
+purple_imgstore_new(gpointer data, size_t size, const char *filename)
 {
 	PurpleStoredImage *img;
 
@@ -82,30 +82,33 @@
 		g_error_free(err);
 		return NULL;
 	}
-	return purple_imgstore_add(data, len, path);
+	return purple_imgstore_new(data, len, path);
 }
 
 int
-purple_imgstore_add_with_id(gpointer data, size_t size, const char *filename)
+purple_imgstore_new_with_id(gpointer data, size_t size, const char *filename)
 {
-	PurpleStoredImage *img = purple_imgstore_add(data, size, filename);
-	if (img) {
-		/*
-		 * Use the next unused id number.  We do it in a loop on the
-		 * off chance that nextid wraps back around to 0 and the hash
-		 * table still contains entries from the first time around.
-		 */
-		do {
-			img->id = ++nextid;
-		} while (img->id == 0 || g_hash_table_lookup(imgstore, &(img->id)) != NULL);
-
-		g_hash_table_insert(imgstore, &(img->id), img);
+	PurpleStoredImage *img = purple_imgstore_new(data, size, filename);
+	if (!img) {
+		return 0;
 	}
 
-	return (img ? img->id : 0);
+	/*
+	 * Use the next unused id number.  We do it in a loop on the
+	 * off chance that nextid wraps back around to 0 and the hash
+	 * table still contains entries from the first time around.
+	 */
+	do {
+		img->id = ++nextid;
+	} while (img->id == 0 || g_hash_table_lookup(imgstore, &(img->id)) != NULL);
+
+	g_hash_table_insert(imgstore, &(img->id), img);
+
+	return img->id;
 }
 
-PurpleStoredImage *purple_imgstore_find_by_id(int id) {
+PurpleStoredImage *purple_imgstore_find_by_id(int id)
+{
 	PurpleStoredImage *img = g_hash_table_lookup(imgstore, &id);
 
 	if (img != NULL)
@@ -114,7 +117,8 @@
 	return img;
 }
 
-gconstpointer purple_imgstore_get_data(PurpleStoredImage *img) {
+gconstpointer purple_imgstore_get_data(PurpleStoredImage *img)
+{
 	g_return_val_if_fail(img != NULL, NULL);
 
 	return img->data;
--- a/libpurple/imgstore.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/imgstore.h	Sat Feb 02 21:20:08 2013 +0100
@@ -1,5 +1,6 @@
 /**
- * @file imgstore.h IM Image Store API
+ * @file imgstore.h Utility functions for reference-counted in-memory
+ *       image data.
  * @ingroup core
  * @see @ref imgstore-signals
  */
@@ -39,66 +40,89 @@
 G_BEGIN_DECLS
 
 /**
- * Add an image to the store.
+ * Create a new PurpleStoredImage.
  *
- * The caller owns a reference to the image in the store, and must dereference
- * the image with purple_imgstore_unref() for it to be freed.
+ * The image is not added to the image store and no ID is assigned.  If you
+ * need to reference the image by an ID, use purple_imgstore_new_with_id()
+ * instead.
  *
- * No ID is allocated when using this function.  If you need to reference the
- * image by an ID, use purple_imgstore_add_with_id() instead.
+ * The caller owns a reference to this image and must dereference it with
+ * purple_imgstore_unref() for it to be freed.
  *
- * @param data		Pointer to the image data, which the imgstore will take
- *                      ownership of and free as appropriate.  If you want a
- *                      copy of the data, make it before calling this function.
- * @param size		Image data's size.
- * @param filename	Filename associated with image.  This is for your
+ * @param data      Pointer to the image data, which the imgstore will take
+ *                  ownership of and free as appropriate.  If you want a
+ *                  copy of the data, make it before calling this function.
+ * @param size      Image data's size.
+ * @param filename  Filename associated with image.  This is for your
  *                  convenience.  It could be the full path to the
  *                  image or, more commonly, the filename of the image
  *                  without any directory information.  It can also be
  *                  NULL, if you don't need to keep track of a filename.
+ *                  If you intend to use this filename to write the file to
+ *                  disk, make sure the filename is appropriately escaped.
+ *                  You may wish to use purple_escape_filename().
  *
- * @return The stored image.
+ * @return The image, or NULL if the image could not be created (because of
+ *         empty data or size).
  */
 PurpleStoredImage *
-purple_imgstore_add(gpointer data, size_t size, const char *filename);
+purple_imgstore_new(gpointer data, size_t size, const char *filename);
 
 /**
- * Create an image and add it to the store.
+ * Create a PurpleStoredImage using purple_imgstore_new() by reading the
+ * given filename from disk.
+ *
+ * The image is not added to the image store and no ID is assigned.  If you
+ * need to reference the image by an ID, use purple_imgstore_new_with_id()
+ * instead.
  *
- * @param path  The path to the image.
+ * Make sure the filename is appropriately escaped.  You may wish to use
+ * purple_escape_filename().  The PurpleStoredImage's filename will be set
+ * to the given path.
  *
- * @return  The stored image.
+ * The caller owns a reference to this image and must dereference it with
+ * purple_imgstore_unref() for it to be freed.
+ *
+ * @param path The path to the image.
+ *
+ * @return The image, or NULL if the image could not be created (because of
+ *         empty data or size).
  */
 PurpleStoredImage *
 purple_imgstore_new_from_file(const char *path);
 
 /**
- * Add an image to the store, allocating an ID.
- *
- * The caller owns a reference to the image in the store, and must dereference
- * the image with purple_imgstore_unref_by_id() or purple_imgstore_unref()
- * for it to be freed.
+ * Create a PurpleStoredImage using purple_imgstore_new() and add the
+ * image to the image store.  A unique ID will be assigned to the image.
  *
- * @param data		Pointer to the image data, which the imgstore will take
- *                      ownership of and free as appropriate.  If you want a
- *                      copy of the data, make it before calling this function.
- * @param size		Image data's size.
- * @param filename	Filename associated with image.  This is for your
+ * The caller owns a reference to the image and must dereference it with
+ * purple_imgstore_unref() or purple_imgstore_unref_by_id() for it to be
+ * freed.
+ *
+ * @param data      Pointer to the image data, which the imgstore will take
+ *                  ownership of and free as appropriate.  If you want a
+ *                  copy of the data, make it before calling this function.
+ * @param size      Image data's size.
+ * @param filename  Filename associated with image.  This is for your
  *                  convenience.  It could be the full path to the
  *                  image or, more commonly, the filename of the image
  *                  without any directory information.  It can also be
  *                  NULL, if you don't need to keep track of a filename.
-
+ *                  If you intend to use this filename to write the file to
+ *                  disk, make sure the filename is appropriately escaped.
+ *                  You may wish to use purple_escape_filename()
+ *
  * @return ID for the image.  This is a unique number that can be used
- *         within libpurple to reference the image.
+ *         within libpurple to reference the image.  0 is returned if the
+ *         image could not be created (because of empty data or size).
  */
-int purple_imgstore_add_with_id(gpointer data, size_t size, const char *filename);
+int purple_imgstore_new_with_id(gpointer data, size_t size, const char *filename);
 
 /**
  * Retrieve an image from the store. The caller does not own a
  * reference to the image.
  *
- * @param id		The ID for the image.
+ * @param id The ID for the image.
  *
  * @return A pointer to the requested image, or NULL if it was not found.
  */
@@ -107,7 +131,7 @@
 /**
  * Retrieves a pointer to the image's data.
  *
- * @param img	The Image
+ * @param img The Image.
  *
  * @return A pointer to the data, which must not
  *         be freed or modified.
@@ -117,7 +141,7 @@
 /**
  * Retrieves the length of the image's data.
  *
- * @param img	The Image
+ * @param img The Image.
  *
  * @return The size of the data that the pointer returned by
  *         purple_imgstore_get_data points to.
@@ -125,9 +149,12 @@
 size_t purple_imgstore_get_size(PurpleStoredImage *img);
 
 /**
- * Retrieves a pointer to the image's filename.
+ * Retrieves a pointer to the image's filename.  If you intend to use this
+ * filename to write the file to disk, make sure the filename was
+ * appropriately escaped when you created the PurpleStoredImage.  You may
+ * wish to use purple_escape_filename().
  *
- * @param img	The image
+ * @param img The image.
  *
  * @return A pointer to the filename, which must not
  *         be freed or modified.
@@ -138,7 +165,7 @@
  * Looks at the magic numbers of the image data (the first few bytes)
  * and returns an extension corresponding to the image's file type.
  *
- * @param img  The image.
+ * @param img The image.
  *
  * @return The image's extension (for example "png") or "icon"
  *         if unknown.
@@ -174,7 +201,7 @@
  * purple_imgstore_ref(), so if you have a PurpleStoredImage, it'll
  * be more efficient to call purple_imgstore_ref() directly.
  *
- * @param id		The ID for the image.
+ * @param id The ID for the image.
  */
 void purple_imgstore_ref_by_id(int id);
 
@@ -185,7 +212,7 @@
  * purple_imgstore_unref(), so if you have a PurpleStoredImage, it'll
  * be more efficient to call purple_imgstore_unref() directly.
  *
- * @param id		The ID for the image.
+ * @param id The ID for the image.
  */
 void purple_imgstore_unref_by_id(int id);
 
--- a/libpurple/log.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/log.c	Sat Feb 02 21:20:08 2013 +0100
@@ -835,7 +835,10 @@
 						fclose(image_file);
 
 						/* Attempt to not leave half-written files around. */
-						unlink(path);
+						if (g_unlink(path)) {
+							purple_debug_error("log", "Error deleting partial "
+									"file %s: %s\n", path, g_strerror(errno));
+						}
 					}
 					else
 					{
@@ -1763,7 +1766,7 @@
 	index_tmp = g_strdup_printf("%s.XXXXXX", pathstr);
 	if ((index_fd = g_mkstemp(index_tmp)) == -1) {
 		purple_debug_error("log", "Failed to open index temp file: %s\n",
-		                 g_strerror(errno));
+		                   g_strerror(errno));
 		g_free(pathstr);
 		g_free(index_tmp);
 		index = NULL;
@@ -1771,7 +1774,7 @@
 		if ((index = fdopen(index_fd, "wb")) == NULL)
 		{
 			purple_debug_error("log", "Failed to fdopen() index temp file: %s\n",
-			                 g_strerror(errno));
+			                   g_strerror(errno));
 			close(index_fd);
 			if (index_tmp != NULL)
 			{
@@ -1827,7 +1830,6 @@
 					log->logger_data = data;
 					list = g_list_prepend(list, log);
 
-					/* XXX: There is apparently Is there a proper way to print a time_t? */
 					if (index != NULL)
 						fprintf(index, "%d\t%d\t%lu\n", data->offset, data->length, (unsigned long)log->time);
 				}
@@ -1887,9 +1889,8 @@
 			log->logger_data = data;
 			list = g_list_prepend(list, log);
 
-			/* XXX: Is there a proper way to print a time_t? */
 			if (index != NULL)
-				fprintf(index, "%d\t%d\t%d\n", data->offset, data->length, (int)log->time);
+				fprintf(index, "%d\t%d\t%lu\n", data->offset, data->length, (unsigned long)log->time);
 		}
 	}
 
@@ -2022,7 +2023,7 @@
 		/* Search the buddy list to find the account and to determine if this is a buddy. */
 		for (gnode = purple_blist_get_root();
 		     !found && gnode != NULL;
-			 gnode = purple_blist_node_get_sibling_next(gnode))
+		     gnode = purple_blist_node_get_sibling_next(gnode))
 		{
 			if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 				continue;
@@ -2036,7 +2037,7 @@
 
 				for (bnode = purple_blist_node_get_first_child(cnode);
 				     !found && bnode != NULL;
-					 bnode = purple_blist_node_get_sibling_next(bnode))
+				     bnode = purple_blist_node_get_sibling_next(bnode))
 				{
 					PurpleBuddy *buddy = (PurpleBuddy *)bnode;
 
--- a/libpurple/media/backend-fs2.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/media/backend-fs2.c	Sat Feb 02 21:20:08 2013 +0100
@@ -41,6 +41,7 @@
 #include <farstream/fs-conference.h>
 #include <farstream/fs-element-added-notifier.h>
 #include <farstream/fs-utils.h>
+#include <gst/gststructure.h>
 #endif
 
 /** @copydoc _PurpleMediaBackendFs2Class */
@@ -2366,14 +2367,44 @@
 	return TRUE;
 }
 
+static const gchar **
+purple_media_backend_fs2_get_available_params(void)
+{
+	static const gchar *supported_params[] = {
+		"sdes-cname", "sdes-email", "sdes-location", "sdes-name", "sdes-note",
+		"sdes-phone", "sdes-tool", NULL
+	};
+
+	return supported_params;
+}
+
+static const gchar*
+param_to_sdes_type(const gchar *param)
+{
+	const gchar **supported = purple_media_backend_fs2_get_available_params();
+	static const gchar *sdes_types[] = {
+		"cname", "email", "location", "name", "note", "phone", "tool", NULL
+	};
+	guint i;
+
+	for (i = 0; supported[i] != NULL; ++i) {
+		if (!strcmp(param, supported[i])) {
+			return sdes_types[i];
+		}
+	}
+
+	return NULL;
+}
+
 static void
 purple_media_backend_fs2_set_params(PurpleMediaBackend *self,
 		guint num_params, GParameter *params)
 {
 	PurpleMediaBackendFs2Private *priv;
-	const gchar **supported = purple_media_backend_fs2_get_available_params();
-	const gchar **p;
 	guint i;
+#ifndef HAVE_FARSIGHT
+	GstStructure *sdes;
+#endif
 
 	g_return_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self));
 
@@ -2386,27 +2417,30 @@
 		return;
 	}
 
+#ifdef HAVE_FARSIGHT
 	for (i = 0; i != num_params; ++i) {
-		for (p = supported; *p != NULL; ++p) {
-			if (!strcmp(params[i].name, *p)) {
-				g_object_set(priv->conference,
-						params[i].name, g_value_get_string(&params[i].value),
-						NULL);
-				break;
-			}
+		if (param_to_sdes_type(params[i].name)) {
+			g_object_set(priv->conference,
+			             params[i].name, g_value_get_string(&params[i].value),
+			             NULL);
 		}
 	}
-}
-
-static const gchar **
-purple_media_backend_fs2_get_available_params(void)
-{
-	static const gchar *supported_params[] = {
-		"sdes-cname", "sdes-email", "sdes-location", "sdes-name", "sdes-note",
-		"sdes-phone", "sdes-tool", NULL
-	};
-
-	return supported_params;
+#else
+	g_object_get(G_OBJECT(priv->conference), "sdes", &sdes, NULL);
+
+	for (i = 0; i != num_params; ++i) {
+		const gchar *sdes_type = param_to_sdes_type(params[i].name);
+		if (!sdes_type)
+			continue;
+
+		gst_structure_set(sdes, sdes_type,
+		                  G_TYPE_STRING, g_value_get_string(&params[i].value),
+		                  NULL);
+	}
+
+	g_object_set(G_OBJECT(priv->conference), "sdes", sdes, NULL);
+	gst_structure_free(sdes);
+#endif /* HAVE_FARSIGHT */
 }
 #else
 GType
--- a/libpurple/ntlm.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/ntlm.c	Sat Feb 02 21:20:08 2013 +0100
@@ -220,16 +220,39 @@
 	des_ecb_encrypt(plaintext, results + 16, key);
 }
 
+/*
+ * TODO: We think we should be using cryptographically secure random numbers
+ *       here.  We think the rand() function is probably bad.  We think
+ *       /dev/urandom is a step up, but using a random function from an SSL
+ *       library would probably be best.  In Windows we could possibly also
+ *       use CryptGenRandom.
+ */
 static void
-gensesskey(char *buffer, const char *oldkey)
+gensesskey(char *buffer)
 {
-	int i = 0;
-	if(oldkey == NULL) {
-		for(i=0; i<16; i++) {
-			buffer[i] = (char)(rand() & 0xff);
+	int fd;
+	int i;
+	ssize_t red = 0;
+
+	fd = open("/dev/urandom", O_RDONLY);
+	if (fd >= 0) {
+		red = read(fd, buffer, 16);
+		if (red < 0) {
+			purple_debug_warning("ntlm", "Error reading from /dev/urandom: %s."
+					"  Falling back to inferior method.\n", g_strerror(errno));
+			red = 0;
+		} else if (red < 16) {
+			purple_debug_warning("ntlm", "Tried reading 16 bytes from "
+					"/dev/urandom but only got %zd.  Falling back to "
+					"inferior method\n", red);
 		}
 	} else {
-		memcpy(buffer, oldkey, 16);
+		purple_debug_warning("ntlm", "Error opening /dev/urandom: %s."
+				"  Falling back to inferior method.\n", g_strerror(errno));
+	}
+
+	for (i = red; i < 16; i++) {
+		buffer[i] = (char)(rand() & 0xff);
 	}
 }
 
@@ -366,7 +389,7 @@
 	/* LCS Stuff */
 	if (flags) {
 		tmsg->flags = GUINT32_TO_LE(0x409082d4);
-		gensesskey(sesskey, NULL);
+		gensesskey(sesskey);
 		memcpy(tmp, sesskey, 0x10);
 	}
 
--- a/libpurple/obsolete.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/obsolete.c	Sat Feb 02 21:20:08 2013 +0100
@@ -80,12 +80,15 @@
 	PurpleHttpResponse *response, gpointer _wrap_data)
 {
 	PurpleUtilLegacyWrapData *wrap_data = _wrap_data;
+	const char *data = NULL;
+	size_t len;
 
-	if (wrap_data->cb && !wrap_data->url_data->cancelled)
-		wrap_data->cb(wrap_data->url_data, wrap_data->user_data,
-			purple_http_response_get_data(response),
-			purple_http_response_get_data_len(response),
+	if (wrap_data->cb && !wrap_data->url_data->cancelled) {
+		data = purple_http_response_get_data(response, &len);
+
+		wrap_data->cb(wrap_data->url_data, wrap_data->user_data, data, len,
 			purple_http_response_get_error(response));
+	}
 
 	g_free(wrap_data->url_data);
 	g_free(wrap_data);
--- a/libpurple/plugins/log_reader.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/plugins/log_reader.c	Sat Feb 02 21:20:08 2013 +0100
@@ -921,7 +921,6 @@
 		xmlnode *to;
 		enum name_guesses name_guessed = NAME_GUESS_UNKNOWN;
 		const char *their_name;
-		time_t time_unix;
 		struct tm *tm;
 		char *timestamp;
 		char *tmp;
@@ -1101,7 +1100,7 @@
 			text = g_string_append(text, ";\">");
 		}
 
-		time_unix = msn_logger_parse_timestamp(message, &tm);
+		msn_logger_parse_timestamp(message, &tm);
 
 		timestamp = g_strdup_printf("<font size=\"2\">(%02u:%02u:%02u)</font> ",
 				tm->tm_hour, tm->tm_min, tm->tm_sec);
@@ -2581,7 +2580,7 @@
 		/* Read talk.ini file to find the log directory. */
 		GError *error = NULL;
 
-#if 0 && GLIB_CHECK_VERSION(2,6,0) /* FIXME: Not tested yet. */
+#if 0 /* FIXME: Not tested yet. */
 		GKeyFile *key_file;
 
 		purple_debug_info("Trillian talk.ini read", "Reading %s\n", path);
@@ -2608,7 +2607,7 @@
 
 			g_key_file_free(key_file);
 		}
-#else /* !GLIB_CHECK_VERSION(2,6,0) */
+#else
 		gchar *contents = NULL;
 
 		purple_debug_info("Trillian talk.ini read",
@@ -2644,7 +2643,7 @@
 			g_free(contents);
 		}
 		g_free(path);
-#endif /* !GLIB_CHECK_VERSION(2,6,0) */
+#endif
 	} /* path */
 
 	if (!found) {
--- a/libpurple/plugins/perl/common/BuddyIcon.xs	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/plugins/perl/common/BuddyIcon.xs	Sat Feb 02 21:20:08 2013 +0100
@@ -7,7 +7,7 @@
 purple_buddy_icon_ref(icon)
 	Purple::Buddy::Icon icon
 
-Purple::Buddy::Icon
+void
 purple_buddy_icon_unref(icon)
 	Purple::Buddy::Icon icon
 
--- a/libpurple/plugins/perl/common/BuddyList.xs	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/plugins/perl/common/BuddyList.xs	Sat Feb 02 21:20:08 2013 +0100
@@ -35,10 +35,6 @@
 Purple::BuddyList
 purple_get_blist()
 
-void
-purple_set_blist(blist)
-	Purple::BuddyList blist
-
 MODULE = Purple::BuddyList  PACKAGE = Purple::Find  PREFIX = purple_find_
 PROTOTYPES: ENABLE
 
@@ -176,9 +172,6 @@
 	Purple::BuddyList::Group  group
 	Purple::BuddyList::Node node
 
-Purple::BuddyList
-purple_blist_new()
-
 void
 purple_blist_show()
 
@@ -237,9 +230,6 @@
 	Purple::BuddyList::Group  group
 
 void
-purple_blist_load()
-
-void
 purple_blist_schedule_save()
 
 void
--- a/libpurple/plugins/perl/common/Certificate.xs	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/plugins/perl/common/Certificate.xs	Sat Feb 02 21:20:08 2013 +0100
@@ -43,8 +43,20 @@
 
 	static const constiv *civ, const_iv[] = {
 #define const_iv(name) {#name, (IV)PURPLE_CERTIFICATE_##name}
-		const_iv(INVALID),
+		const_iv(UNKNOWN_ERROR),
 		const_iv(VALID),
+		const_iv(NON_FATALS_MASK),
+		const_iv(SELF_SIGNED),
+		const_iv(CA_UNKNOWN),
+		const_iv(NOT_ACTIVATED),
+		const_iv(EXPIRED),
+		const_iv(NAME_MISMATCH),
+		const_iv(NO_CA_POOL),
+		const_iv(FATALS_MASK),
+		const_iv(INVALID_CHAIN),
+		const_iv(REVOKED),
+		const_iv(REJECTED),
+		const_iv(LAST),
 	};
 
 	for (civ = const_iv + sizeof(const_iv) / sizeof(const_iv[0]); civ-- > const_iv; )
--- a/libpurple/plugins/perl/common/ImgStore.xs	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/plugins/perl/common/ImgStore.xs	Sat Feb 02 21:20:08 2013 +0100
@@ -4,13 +4,13 @@
 PROTOTYPES: ENABLE
 
 Purple::StoredImage
-purple_imgstore_add(data, size, filename)
+purple_imgstore_new(data, size, filename)
 	void *data
 	size_t size
 	const char *filename
 
 int
-purple_imgstore_add_with_id(data, size, filename)
+purple_imgstore_new_with_id(data, size, filename)
 	void *data
 	size_t size
 	const char *filename
--- a/libpurple/plugins/perl/common/Makefile.mingw	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/plugins/perl/common/Makefile.mingw	Sat Feb 02 21:20:08 2013 +0100
@@ -112,7 +112,7 @@
 	$(PERL) -MAutoSplit -e 'autosplit("lib/Purple.pm")'
 
 $(TARGET).dll: $(PURPLE_DLL).a $(PURPLE_PERL_DLL).a $(FALLBACKS) $(OBJECTS)
-	$(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) -o $(TARGET).dll
+	$(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -o $(TARGET).dll
 
 ##
 ## CLEAN
--- a/libpurple/plugins/perl/common/Pounce.xs	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/plugins/perl/common/Pounce.xs	Sat Feb 02 21:20:08 2013 +0100
@@ -121,9 +121,6 @@
 Purple::Handle
 purple_pounces_get_handle()
 
-gboolean
-purple_pounces_load()
-
 void
 purple_pounces_unregister_handler(ui)
 	const char *ui
--- a/libpurple/plugins/signals-test.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/plugins/signals-test.c	Sat Feb 02 21:20:08 2013 +0100
@@ -78,25 +78,25 @@
 }
 
 static int
-account_authorization_requested_cb(PurpleAccount *account, const char *user, gpointer data)
+account_authorization_requested_cb(PurpleAccount *account, const char *user, const char *message, char *response, gpointer data)
 {
-	purple_debug_misc("signals test", "account-authorization-requested (%s, %s)\n",
-			purple_account_get_username(account), user);
-	return 0;
+	purple_debug_misc("signals test", "account-authorization-requested (%s, %s, %s)\n",
+			purple_account_get_username(account), user, message);
+	return PURPLE_ACCOUNT_RESPONSE_PASS;
 }
 
 static void
-account_authorization_granted_cb(PurpleAccount *account, const char *user, gpointer data)
+account_authorization_granted_cb(PurpleAccount *account, const char *user, const char *message, gpointer data)
 {
-	purple_debug_misc("signals test", "account-authorization-granted (%s, %s)\n",
-			purple_account_get_username(account), user);
+	purple_debug_misc("signals test", "account-authorization-granted (%s, %s, %s)\n",
+			purple_account_get_username(account), user, message);
 }
 
 static void
-account_authorization_denied_cb(PurpleAccount *account, const char *user, gpointer data)
+account_authorization_denied_cb(PurpleAccount *account, const char *user, const char *message, gpointer data)
 {
-	purple_debug_misc("signals test", "account-authorization-denied (%s, %s)\n",
-			purple_account_get_username(account), user);
+	purple_debug_misc("signals test", "account-authorization-denied (%s, %s, %s)\n",
+			purple_account_get_username(account), user, message);
 }
 
 /**************************************************************************
--- a/libpurple/plugins/ssl/Makefile.mingw	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/plugins/ssl/Makefile.mingw	Sat Feb 02 21:20:08 2013 +0100
@@ -19,7 +19,6 @@
 			$(NSS_TOP)/lib/libplc4.dll \
 			$(NSS_TOP)/lib/libplds4.dll \
 			$(NSS_TOP)/lib/nss3.dll \
-			$(NSS_TOP)/lib/nssckbi.dll \
 			$(NSS_TOP)/lib/nssutil3.dll \
 			$(NSS_TOP)/lib/smime3.dll \
 			$(NSS_TOP)/lib/softokn3.dll \
--- a/libpurple/plugins/ssl/ssl-nss.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/plugins/ssl/ssl-nss.c	Sat Feb 02 21:20:08 2013 +0100
@@ -125,18 +125,8 @@
 static void
 ssl_nss_init_nss(void)
 {
-	char *lib;
 	PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
 	NSS_NoDB_Init(".");
-
-	/* TODO: Fix this so autoconf does the work trying to find this lib. */
-#ifndef _WIN32
-	lib = g_strdup(LIBDIR "/libnssckbi.so");
-#else
-	lib = g_strdup("nssckbi.dll");
-#endif
-	SECMOD_AddNewModule("Builtins", lib, 0, 0);
-	g_free(lib);
 	NSS_SetDomesticPolicy();
 
 	SSL_CipherPrefSetDefault(TLS_DHE_RSA_WITH_AES_256_CBC_SHA, 1);
--- a/libpurple/plugins/tcl/signal-test.tcl	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/plugins/tcl/signal-test.tcl	Sat Feb 02 21:20:08 2013 +0100
@@ -108,7 +108,7 @@
 	purple::debug -info "tcl signal" "plugin-unload [list $args]"
 }
 
-purple::signal connect [purple::savedstatuses handle] savedstatus-changed args {
+purple::signal connect [purple::savedstatus handle] savedstatus-changed args {
 	purple::debug -info "tcl signal" "savedstatus-changed [list $args]"
 	purple::debug -info "tcl signal" "purple::savedstatus current = [purple::savedstatus current]"
 }
--- a/libpurple/plugins/tcl/tcl.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/plugins/tcl/tcl.c	Sat Feb 02 21:20:08 2013 +0100
@@ -174,37 +174,17 @@
 	Tcl_Interp *interp;
 	Tcl_Parse parse;
 	Tcl_Obj *result, **listitems;
-	struct stat st;
-	FILE *fp;
-	char *buf, *cur;
+	char *buf;
 	const char *next;
-	int len, found = 0, err = 0, nelems;
+	int found = 0, err = 0, nelems;
+	gsize len;
 	gboolean status = FALSE;
-	if ((fp = g_fopen(plugin->path, "r")) == NULL)
-		return FALSE;
-	if (fstat(fileno(fp), &st)) {
-		fclose(fp);
+
+	if (!g_file_get_contents(plugin->path, &buf, &len, NULL)) {
+		purple_debug(PURPLE_DEBUG_INFO, "tcl", "Error opening plugin %s\n",
+			     plugin->path);
 		return FALSE;
 	}
-	len = st.st_size;
-
-	buf = g_malloc(len + 1);
-
-	cur = buf;
-	while (fgets(cur, GPOINTER_TO_INT(buf) - (buf - cur), fp)) {
-		cur += strlen(cur);
-		if (feof(fp))
-			break;
-	}
-
-	if (ferror(fp)) {
-		purple_debug(PURPLE_DEBUG_ERROR, "tcl", "error reading %s (%s)\n", plugin->path, g_strerror(errno));
-		g_free(buf);
-		fclose(fp);
-		return FALSE;
-	}
-
-	fclose(fp);
 
 	if ((interp = tcl_create_interp()) == NULL) {
 		return FALSE;
--- a/libpurple/pounce.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/pounce.c	Sat Feb 02 21:20:08 2013 +0100
@@ -572,7 +572,7 @@
 	NULL
 };
 
-gboolean
+static gboolean
 purple_pounces_load(void)
 {
 	gchar *filename = g_build_filename(purple_user_dir(), "pounces.xml", NULL);
@@ -1190,6 +1190,8 @@
 
 	purple_signal_connect(conv_handle, "received-im-msg",
 						handle, PURPLE_CALLBACK(received_message_cb), NULL);
+
+	purple_pounces_load();
 }
 
 void
--- a/libpurple/pounce.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/pounce.h	Sat Feb 02 21:20:08 2013 +0100
@@ -289,14 +289,6 @@
 PurplePounce *purple_find_pounce(const PurpleAccount *pouncer,
 							 const char *pouncee, PurplePounceEvent events);
 
-
-/**
- * Loads the pounces.
- *
- * @return @c TRUE if the pounces could be loaded.
- */
-gboolean purple_pounces_load(void);
-
 /**
  * Registers a pounce handler for a UI.
  *
--- a/libpurple/protocols/bonjour/bonjour_ft.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/bonjour/bonjour_ft.c	Sat Feb 02 21:20:08 2013 +0100
@@ -33,7 +33,7 @@
 static void
 bonjour_bytestreams_init(PurpleXfer *xfer);
 static void
-bonjour_bytestreams_connect(PurpleXfer *xfer, PurpleBuddy *pb);
+bonjour_bytestreams_connect(PurpleXfer *xfer);
 static void
 bonjour_xfer_init(PurpleXfer *xfer);
 static void
@@ -280,6 +280,25 @@
 	xep_iq_send_and_free(iq);
 }
 
+/**
+ * Frees the whole tree of an xml node
+ *
+ * First determines the root of the xml tree and then frees the whole tree
+ * from there.
+ *
+ * @param node	The node to free the tree from
+ */
+static void
+xmlnode_free_tree(xmlnode *node)
+{
+	g_return_if_fail(node != NULL);
+
+	while(xmlnode_get_parent(node))
+		node = xmlnode_get_parent(node);
+
+	xmlnode_free(node);
+}
+
 static void
 bonjour_free_xfer(PurpleXfer *xfer)
 {
@@ -310,6 +329,9 @@
 		g_free(xf->proxy_host);
 		g_free(xf->buddy_ip);
 		g_free(xf->sid);
+
+		xmlnode_free_tree(xf->streamhost);
+
 		g_free(xf);
 		purple_xfer_set_protocol_data(xfer, NULL);
 	}
@@ -441,7 +463,7 @@
 		if (si && (profile = xmlnode_get_attrib(si, "profile"))
 				&& !strcmp(profile, "http://jabber.org/protocol/si/profile/file-transfer")) {
 			const char *filename = NULL, *filesize_str = NULL;
-			int filesize = 0;
+			goffset filesize = 0;
 			xmlnode *file;
 
 			const char *sid = xmlnode_get_attrib(si, "id");
@@ -449,7 +471,7 @@
 			if ((file = xmlnode_get_child(si, "file"))) {
 				filename = xmlnode_get_attrib(file, "name");
 				if((filesize_str = xmlnode_get_attrib(file, "size")))
-					filesize = atoi(filesize_str);
+					filesize = g_ascii_strtoll(filesize_str, NULL, 10);
 			}
 
 			/* TODO: Make sure that it is advertising a bytestreams transfer */
@@ -547,19 +569,97 @@
 	return !strcmp(host, buddy_ip);
 }
 
+static inline gint
+xep_addr_differ(const char *buddy_ip, const char *host)
+{
+	return !xep_cmp_addr(host, buddy_ip);
+}
+
+/**
+ * Create and insert an identical twin
+ *
+ * Creates a copy of the specified node and inserts it right after
+ * this original node.
+ *
+ * @param node	The node to clone
+ * @return	A pointer to the new, cloned twin if successful
+ *		or NULL otherwise.
+ */
+static xmlnode *
+xmlnode_insert_twin_copy(xmlnode *node) {
+	xmlnode *copy;
+
+	g_return_val_if_fail(node != NULL, NULL);
+
+	copy = xmlnode_copy(node);
+	g_return_val_if_fail(copy != NULL, NULL);
+
+	copy->next = node->next;
+	node->next = copy;
+
+	return copy;
+}
+
+/**
+ * Tries to append an interface scope to an IPv6 link local address.
+ *
+ * If the given address is a link local IPv6 address (with no
+ * interface scope) then we try to determine all fitting interfaces
+ * from our Bonjour IP address list.
+ *
+ * For any such found matches we insert a copy of our current xml
+ * streamhost entry right after this streamhost entry and append
+ * the determined interface to the host address of this copy.
+ *
+ * @param cur_streamhost	The XML streamhost node we examine
+ * @param host	The host address to examine in text form
+ * @param pb	Buddy to get the list of link local IPv6 addresses
+ *		and their interface from
+ * @return	Returns TRUE if the specified 'host' address is a
+ *		link local IPv6 address with no interface scope.
+ *		Otherwise returns FALSE.
+ */
 static gboolean
-__xep_bytestreams_parse(PurpleBuddy *pb, PurpleXfer *xfer, xmlnode *query,
+add_ipv6_link_local_ifaces(xmlnode *cur_streamhost, const char *host,
+			   const PurpleBuddy *pb) {
+	xmlnode *new_streamhost = NULL;
+	struct in6_addr in6_addr;
+	BonjourBuddy *bb;
+	GSList *ip_elem;
+
+	if (inet_pton(AF_INET6, host, &in6_addr) != 1 ||
+	    !IN6_IS_ADDR_LINKLOCAL(&in6_addr) ||
+	    strchr(host, '%'))
+		return FALSE;
+
+	bb = purple_buddy_get_protocol_data(pb);
+
+	for (ip_elem = bb->ips;
+	     (ip_elem = g_slist_find_custom(ip_elem, host, (GCompareFunc)&xep_addr_differ));
+	     ip_elem = ip_elem->next) {
+		purple_debug_info("bonjour", "Inserting an xmlnode twin copy for %s with new host address %s\n",
+				  host, (char*)ip_elem->data);
+		new_streamhost = xmlnode_insert_twin_copy(cur_streamhost);
+		xmlnode_set_attrib(new_streamhost, "host", ip_elem->data);
+	}
+
+	if (!new_streamhost)
+		purple_debug_info("bonjour", "No interface for this IPv6 link local address found: %s\n",
+				  host);
+
+	return TRUE;
+}
+
+static gboolean
+__xep_bytestreams_parse(PurpleBuddy *pb, PurpleXfer *xfer, xmlnode *streamhost,
 			const char *iq_id)
 {
+	char *tmp_iq_id;
 	const char *jid, *host, *port;
 	int portnum;
-	xmlnode *streamhost;
 	XepXfer *xf = purple_xfer_get_protocol_data(xfer);
 
-	for(streamhost = xmlnode_get_child(query, "streamhost");
-			streamhost;
-			streamhost = xmlnode_get_next_twin(streamhost)) {
-
+	for(; streamhost; streamhost = xmlnode_get_next_twin(streamhost)) {
 		if(!(jid = xmlnode_get_attrib(streamhost, "jid")) ||
 		   !(host = xmlnode_get_attrib(streamhost, "host")) ||
 		   !(port = xmlnode_get_attrib(streamhost, "port")) ||
@@ -568,29 +668,36 @@
 			continue;
 		}
 
-		if(!xep_cmp_addr(host, xf->buddy_ip))
+		/* skip IPv6 link local addresses with no interface scope
+		 * (but try to add a new one with an interface scope then) */
+		if(add_ipv6_link_local_ifaces(streamhost, host, pb))
 			continue;
 
+		tmp_iq_id = g_strdup(iq_id);
 		g_free(xf->iq_id);
-		xf->iq_id = g_strdup(iq_id);
+		g_free(xf->jid);
+		g_free(xf->proxy_host);
+
+		xf->iq_id = tmp_iq_id;
 		xf->jid = g_strdup(jid);
-		xf->proxy_host = g_strdup(xf->buddy_ip);
+		xf->proxy_host = g_strdup(host);
 		xf->proxy_port = portnum;
+		xf->streamhost = streamhost;
+		xf->pb = pb;
 		purple_debug_info("bonjour", "bytestream offer parse"
 				  "jid=%s host=%s port=%d.\n", jid, host, portnum);
-		bonjour_bytestreams_connect(xfer, pb);
+		bonjour_bytestreams_connect(xfer);
 		return TRUE;
 	}
 
 	return FALSE;
 }
 
-
 void
 xep_bytestreams_parse(PurpleConnection *pc, xmlnode *packet, PurpleBuddy *pb)
 {
 	const char *type, *from, *iq_id, *sid;
-	xmlnode *query;
+	xmlnode *query, *streamhost;
 	BonjourData *bd;
 	PurpleXfer *xfer;
 
@@ -610,6 +717,10 @@
 	if(!type)
 		return;
 
+	query = xmlnode_copy(query);
+	if (!query)
+		return;
+
 	if(strcmp(type, "set")) {
 		purple_debug_info("bonjour", "bytestream offer Message type - Unknown-%s.\n", type);
 		return;
@@ -621,7 +732,9 @@
 
 	sid = xmlnode_get_attrib(query, "sid");
 	xfer = bonjour_si_xfer_find(bd, sid, from);
-	if(xfer && __xep_bytestreams_parse(pb, xfer, query, iq_id))
+	streamhost = xmlnode_get_child(query, "streamhost");
+
+	if(xfer && streamhost && __xep_bytestreams_parse(pb, xfer, streamhost, iq_id))
 		return; /* success */
 
 	purple_debug_error("bonjour", "Didn't find an acceptable streamhost.\n");
@@ -864,15 +977,22 @@
 	XepIq *iq;
 	xmlnode *q_node, *tmp_node;
 	BonjourData *bd;
+	gboolean ret = FALSE;
 
 	xf->proxy_connection = NULL;
 
 	if(source < 0) {
-		purple_debug_error("bonjour", "Error connecting via SOCKS5 - %s\n",
-			error_message ? error_message : "(null)");
-		xep_ft_si_reject(xf->data, xf->iq_id, purple_xfer_get_remote_user(xfer), "404", "cancel");
-		/* Cancel the connection */
-		purple_xfer_cancel_local(xfer);
+		purple_debug_error("bonjour", "Error connecting via SOCKS5 to %s - %s\n",
+			xf->proxy_host, error_message ? error_message : "(null)");
+
+		tmp_node = xmlnode_get_next_twin(xf->streamhost);
+		ret = __xep_bytestreams_parse(xf->pb, xfer, tmp_node, xf->iq_id);
+
+		if (!ret) {
+			xep_ft_si_reject(xf->data, xf->iq_id, purple_xfer_get_remote_user(xfer), "404", "cancel");
+			/* Cancel the connection */
+			purple_xfer_cancel_local(xfer);
+		}
 		return;
 	}
 
@@ -894,8 +1014,9 @@
 }
 
 static void
-bonjour_bytestreams_connect(PurpleXfer *xfer, PurpleBuddy *pb)
+bonjour_bytestreams_connect(PurpleXfer *xfer)
 {
+	PurpleBuddy *pb;
 	PurpleAccount *account = NULL;
 	XepXfer *xf;
 	char dstaddr[41];
@@ -913,6 +1034,7 @@
 	if(!xf)
 		return;
 
+	pb = xf->pb;
 	name = purple_buddy_get_name(pb);
 	account = purple_buddy_get_account(pb);
 
--- a/libpurple/protocols/bonjour/bonjour_ft.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/bonjour/bonjour_ft.h	Sat Feb 02 21:20:08 2013 +0100
@@ -50,6 +50,8 @@
 	char *jid;
 	char *proxy_host;
 	int proxy_port;
+	xmlnode *streamhost;
+	PurpleBuddy *pb;
 };
 
 /**
--- a/libpurple/protocols/gg/image.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/gg/image.c	Sat Feb 02 21:20:08 2013 +0100
@@ -175,7 +175,7 @@
 	GList *it;
 	uint64_t id;
 	
-	stored_id = purple_imgstore_add_with_id(
+	stored_id = purple_imgstore_new_with_id(
 		g_memdup(image_reply->image, image_reply->size),
 		image_reply->size,
 		image_reply->filename);
--- a/libpurple/protocols/gg/lib/common.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/gg/lib/common.c	Sat Feb 02 21:20:08 2013 +0100
@@ -78,7 +78,7 @@
 		size = 128;
 		do {
 			size *= 2;
-			if (!(tmp = realloc(buf, size))) {
+			if (!(tmp = realloc(buf, size + 1))) {
 				free(buf);
 				return NULL;
 			}
@@ -268,6 +268,7 @@
 		}
 	}
 
+	memset(&sin, 0, sizeof(sin));
 	sin.sin_port = htons(port);
 	sin.sin_family = AF_INET;
 	sin.sin_addr.s_addr = a->s_addr;
--- a/libpurple/protocols/gg/lib/dcc.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/gg/lib/dcc.c	Sat Feb 02 21:20:08 2013 +0100
@@ -419,6 +419,7 @@
 		port = GG_DEFAULT_DCC_PORT;
 
 	while (!bound) {
+		memset(&sin, 0, sizeof(sin));
 		sin.sin_family = AF_INET;
 		sin.sin_addr.s_addr = INADDR_ANY;
 		sin.sin_port = htons(port);
--- a/libpurple/protocols/gg/lib/dcc7.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/gg/lib/dcc7.c	Sat Feb 02 21:20:08 2013 +0100
@@ -140,7 +140,7 @@
 
 	for (tmp = sess->dcc7_list; tmp; tmp = tmp->next) {
 		if (empty) {
-			if (tmp->peer_uin == uin && !tmp->state == GG_STATE_WAITING_FOR_ACCEPT)
+			if (tmp->peer_uin == uin /*&& tmp->state != GG_STATE_WAITING_FOR_ACCEPT*/)
 				return tmp;
 		} else {
 			if (!memcmp(&tmp->cid, &id, sizeof(id)))
@@ -239,6 +239,7 @@
 		return -1;
 	}
 
+	memset(&sin, 0, sizeof(sin));
 	sin.sin_family = AF_INET;
 	sin.sin_addr.s_addr = addr;
 	sin.sin_port = htons(port);
@@ -649,7 +650,7 @@
 				s.uin_to = gg_fix32(tmp->peer_uin);
 				s.size = gg_fix32(tmp->size);
 
-				strncpy((char*) s.filename, (char*) tmp->filename, GG_DCC7_FILENAME_LEN);
+				memcpy((char*) s.filename, (char*) tmp->filename, GG_DCC7_FILENAME_LEN);
 
 				tmp->state = GG_STATE_WAITING_FOR_ACCEPT;
 				tmp->timeout = GG_DCC7_TIMEOUT_FILE_ACK;
--- a/libpurple/protocols/gg/lib/libgadu.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/gg/lib/libgadu.c	Sat Feb 02 21:20:08 2013 +0100
@@ -509,7 +509,7 @@
 		while (sess->header_done < sizeof(h)) {
 			ret = gg_read(sess, (char*) &h + sess->header_done, sizeof(h) - sess->header_done);
 
-			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv(%d,%p,%d) = %d\n", sess->fd, &h + sess->header_done, sizeof(h) - sess->header_done, ret);
+			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv(%d,%p,%d) = %d\n", sess->fd, (char*)&h + sess->header_done, sizeof(h) - sess->header_done, ret);
 
 			if (!ret) {
 				errno = ECONNRESET;
--- a/libpurple/protocols/irc/Makefile.mingw	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/irc/Makefile.mingw	Sat Feb 02 21:20:08 2013 +0100
@@ -54,6 +54,13 @@
 			-lintl \
 			-lpurple
 
+
+ifeq ($(CYRUS_SASL), 1)
+INCLUDE_PATHS += -I$(CYRUS_SASL_TOP)/include
+LIB_PATHS += -L$(CYRUS_SASL_TOP)/bin
+LIBS += -llibsasl
+endif
+
 include $(PIDGIN_COMMON_RULES)
 
 ##
--- a/libpurple/protocols/irc/irc.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/irc/irc.c	Sat Feb 02 21:20:08 2013 +0100
@@ -155,6 +155,7 @@
  	char *tosend= g_strdup(buf);
 
 	purple_signal_emit(_irc_plugin, "irc-sending-text", purple_account_get_connection(irc->account), &tosend);
+	
 	if (tosend == NULL)
 		return 0;
 
@@ -393,9 +394,17 @@
 	const char *username, *realname;
 	struct irc_conn *irc = purple_connection_get_protocol_data(gc);
 	const char *pass = purple_connection_get_password(gc);
+#ifdef HAVE_CYRUS_SASL
+	const gboolean use_sasl = purple_account_get_bool(irc->account, "sasl", FALSE);
+#endif
 
 	if (pass && *pass) {
-		buf = irc_format(irc, "v:", "PASS", pass);
+#ifdef HAVE_CYRUS_SASL
+		if (use_sasl)
+			buf = irc_format(irc, "vv:", "CAP", "REQ", "sasl");
+		else /* intended to fall through */
+#endif
+			buf = irc_format(irc, "v:", "PASS", pass);
 		if (irc_send(irc, buf) < 0) {
 			g_free(buf);
 			return FALSE;
@@ -529,6 +538,17 @@
 	g_free(irc->mode_chars);
 	g_free(irc->reqnick);
 
+#ifdef HAVE_CYRUS_SASL
+	if (irc->sasl_conn) {
+		sasl_dispose(&irc->sasl_conn);
+		irc->sasl_conn = NULL;
+	}
+	g_free(irc->sasl_cb);
+	if(irc->sasl_mechs)
+		g_string_free(irc->sasl_mechs, TRUE);
+#endif
+
+
 	g_free(irc);
 }
 
@@ -1047,6 +1067,16 @@
 	option = purple_account_option_bool_new(_("Use SSL"), "ssl", FALSE);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
 
+#ifdef HAVE_CYRUS_SASL
+	option = purple_account_option_bool_new(_("Authenticate with SASL"), "sasl", FALSE);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+	option = purple_account_option_bool_new(
+						_("Allow plaintext SASL auth over unencrypted connection"),
+						"auth_plain_in_clear", FALSE);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+#endif
+
 	_irc_plugin = plugin;
 
 	purple_prefs_remove("/plugins/prpl/irc/quitmsg");
--- a/libpurple/protocols/irc/irc.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/irc/irc.h	Sat Feb 02 21:20:08 2013 +0100
@@ -25,6 +25,10 @@
 
 #include <glib.h>
 
+#ifdef HAVE_CYRUS_SASL
+#include <sasl/sasl.h>
+#endif
+
 #include "circbuffer.h"
 #include "ft.h"
 #include "roomlist.h"
@@ -93,6 +97,13 @@
 	char *mode_chars;
 	char *reqnick;
 	gboolean nickused;
+#ifdef HAVE_CYRUS_SASL
+	sasl_conn_t *sasl_conn;
+	const char *current_mech;
+	GString *sasl_mechs;
+	gboolean mech_works;
+	sasl_callback_t *sasl_cb;
+#endif
 };
 
 struct irc_buddy {
@@ -163,11 +174,19 @@
 void irc_msg_regonly(struct irc_conn *irc, const char *name, const char *from, char **args);
 void irc_msg_time(struct irc_conn *irc, const char *name, const char *from, char **args);
 void irc_msg_topic(struct irc_conn *irc, const char *name, const char *from, char **args);
+void irc_msg_topicinfo(struct irc_conn *irc, const char *name, const char *from, char **args);
 void irc_msg_unavailable(struct irc_conn *irc, const char *name, const char *from, char **args);
 void irc_msg_unknown(struct irc_conn *irc, const char *name, const char *from, char **args);
 void irc_msg_wallops(struct irc_conn *irc, const char *name, const char *from, char **args);
 void irc_msg_whois(struct irc_conn *irc, const char *name, const char *from, char **args);
 void irc_msg_who(struct irc_conn *irc, const char *name, const char *from, char **args);
+#ifdef HAVE_CYRUS_SASL
+void irc_msg_cap(struct irc_conn *irc, const char *name, const char *from, char **args);
+void irc_msg_auth(struct irc_conn *irc, char *arg);
+void irc_msg_authok(struct irc_conn *irc, const char *name, const char *from, char **args);
+void irc_msg_authtryagain(struct irc_conn *irc, const char *name, const char *from, char **args);
+void irc_msg_authfail(struct irc_conn *irc, const char *name, const char *from, char **args);
+#endif
 
 void irc_msg_ignore(struct irc_conn *irc, const char *name, const char *from, char **args);
 
--- a/libpurple/protocols/irc/msgs.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/irc/msgs.c	Sat Feb 02 21:20:08 2013 +0100
@@ -32,6 +32,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#ifdef HAVE_CYRUS_SASL
+#include <sasl/sasl.h>
+#endif
+
 static char *irc_mask_nick(const char *mask);
 static char *irc_mask_userhost(const char *mask);
 static void irc_chat_remove_buddy(PurpleConversation *convo, char *data[2]);
@@ -42,6 +46,10 @@
                                    const char *from, const char *to,
                                    const char *rawmsg, gboolean notice);
 
+#ifdef HAVE_CYRUS_SASL
+static void irc_sasl_finish(struct irc_conn *irc);
+#endif
+
 static char *irc_mask_nick(const char *mask)
 {
 	char *end, *buf;
@@ -634,6 +642,38 @@
 	g_free(topic);
 }
 
+void irc_msg_topicinfo(struct irc_conn *irc, const char *name, const char *from, char **args)
+{
+	PurpleConversation *convo;
+	struct tm *tm;
+	time_t t;
+	char *msg, *timestamp, *datestamp;
+	
+	if (!args || !args[1] || !args[2] || !args[3])
+		return;
+
+	convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[1], irc->account);
+	if (!convo) {
+		purple_debug(PURPLE_DEBUG_ERROR, "irc", "Got topic info for %s, which doesn't exist\n", args[1]);
+		return;
+	}
+
+	t = (time_t)atol(args[3]);
+	if (t == 0) {
+		purple_debug(PURPLE_DEBUG_ERROR, "irc", "Got apparently nonsensical topic timestamp %s\n", args[3]);
+		return;
+	}
+	tm = localtime(&t);
+
+	timestamp = g_strdup(purple_time_format(tm));
+	datestamp = g_strdup(purple_date_format_short(tm));
+	msg = g_strdup_printf("Topic for %s set by %s at %s on %s", args[1], args[2], timestamp, datestamp);
+	purple_conv_chat_write(PURPLE_CONV_CHAT(convo), "", msg, PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LINKIFY, time(NULL));
+	g_free(timestamp);
+	g_free(datestamp);
+	g_free(msg);
+}
+
 void irc_msg_unknown(struct irc_conn *irc, const char *name, const char *from, char **args)
 {
 	PurpleConnection *gc = purple_account_get_connection(irc->account);
@@ -1422,6 +1462,379 @@
 	g_free(msg);
 }
 
+#ifdef HAVE_CYRUS_SASL
+static int
+irc_sasl_cb_secret(sasl_conn_t *conn, void *ctx, int id, sasl_secret_t **secret)
+{
+	struct irc_conn *irc = ctx;
+	sasl_secret_t *sasl_secret;
+	const char *pw;
+	size_t len;
+
+	pw = purple_account_get_password(irc->account);
+
+	if (!conn || !secret || id != SASL_CB_PASS)
+		return SASL_BADPARAM;
+
+	len = strlen(pw);
+	/* Not an off-by-one because sasl_secret_t defines char data[1] */
+	/* TODO: This can probably be moved to glib's allocator */
+	sasl_secret = malloc(sizeof(sasl_secret_t) + len);
+	if (!sasl_secret)
+		return SASL_NOMEM;
+
+	sasl_secret->len = len;
+	strcpy((char*)sasl_secret->data, pw);
+
+	*secret = sasl_secret;
+	return SASL_OK;
+}
+
+static int
+irc_sasl_cb_log(void *context, int level, const char *message)
+{
+	if(level <= SASL_LOG_TRACE)
+		purple_debug_info("sasl", "%s\n", message);
+
+	return SASL_OK;
+}
+
+static int
+irc_sasl_cb_simple(void *ctx, int id, const char **res, unsigned *len)
+{
+	struct irc_conn *irc = ctx;
+	PurpleConnection *gc = purple_account_get_connection(irc->account);
+
+	switch(id) {
+		case SASL_CB_AUTHNAME:
+			*res = purple_connection_get_display_name(gc);
+			break;
+		case SASL_CB_USER:
+			*res = "";
+			break;
+		default:
+			return SASL_BADPARAM;
+	}
+	if (len) *len = strlen((char *)*res);
+	return SASL_OK;
+}
+
+static void
+irc_auth_start_cyrus(struct irc_conn *irc)
+{
+	int ret = 0;
+	char *buf;
+	sasl_security_properties_t secprops;
+	PurpleAccount *account = irc->account;
+	PurpleConnection *gc = purple_account_get_connection(account);
+
+	gboolean plaintext;
+	gboolean again = FALSE;
+
+	/* Set up security properties and options */
+	secprops.min_ssf = 0;
+	secprops.security_flags = SASL_SEC_NOANONYMOUS;
+
+	if (!irc->gsc) {
+		secprops.max_ssf = -1;
+		secprops.maxbufsize = 4096;
+		plaintext = purple_account_get_bool(account, "auth_plain_in_clear", FALSE);
+		if (!plaintext)
+			secprops.security_flags |= SASL_SEC_NOPLAINTEXT;
+	} else {
+		secprops.max_ssf = 0;
+		secprops.maxbufsize = 0;
+		plaintext = TRUE;
+	}
+
+	secprops.property_names = 0;
+	secprops.property_values = 0;
+
+	do {
+		gchar *tmp = NULL;
+		again = FALSE;
+
+		ret = sasl_client_new("irc", irc->server, NULL, NULL, irc->sasl_cb, 0, &irc->sasl_conn);
+
+		if (ret != SASL_OK) {
+			purple_debug_error("irc", "sasl_client_new failed: %d\n", ret);
+			tmp = g_strdup_printf(_("Failed to initialize SASL authentication: %s"),
+				sasl_errdetail(irc->sasl_conn));
+			purple_connection_error_reason (gc,
+				PURPLE_CONNECTION_ERROR_OTHER_ERROR, tmp);
+			g_free(tmp);
+			return;
+		}
+
+		sasl_setprop(irc->sasl_conn, SASL_AUTH_EXTERNAL, irc->account->username);
+		sasl_setprop(irc->sasl_conn, SASL_SEC_PROPS, &secprops);
+
+		ret = sasl_client_start(irc->sasl_conn, irc->sasl_mechs->str, NULL, NULL, NULL, &irc->current_mech);
+
+		switch (ret) {
+			case SASL_OK:
+			case SASL_CONTINUE:
+				irc->mech_works = FALSE;
+				break;
+			case SASL_NOMECH:
+				purple_connection_error_reason (gc,
+					PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
+					_("SASL authentication failed: No worthy authentication mechanisms found."));
+
+				irc_sasl_finish(irc);
+				return;
+			case SASL_BADPARAM:
+			case SASL_NOMEM:
+				tmp = g_strdup_printf(_("SASL authentication failed: %s"), sasl_errdetail(irc->sasl_conn));
+				purple_connection_error_reason (gc,
+					PURPLE_CONNECTION_ERROR_OTHER_ERROR, tmp);
+				g_free(tmp);
+
+				irc_sasl_finish(irc);
+				return;
+			default:
+				purple_debug_error("irc", "sasl_client_start failed: %s\n", sasl_errdetail(irc->sasl_conn));
+
+				if (irc->current_mech && *irc->current_mech) {
+					char *pos;
+					if ((pos = strstr(irc->sasl_mechs->str, irc->current_mech))) {
+						size_t index = pos - irc->sasl_mechs->str;
+						g_string_erase(irc->sasl_mechs, index, strlen(irc->current_mech));
+
+						/* Remove space which separated this mech from the next */
+						if ((irc->sasl_mechs->str)[index] == ' ') {
+							g_string_erase(irc->sasl_mechs, index, 1);
+						}
+					}
+
+					again = TRUE;
+				}
+				irc_sasl_finish(irc);
+		}
+	} while (again);
+
+	purple_debug_info("irc", "Using SASL: %s\n", irc->current_mech);
+
+	buf = irc_format(irc, "vv", "AUTHENTICATE", irc->current_mech);
+	irc_send(irc, buf);
+	g_free(buf);
+}
+
+/* SASL authentication */
+void
+irc_msg_cap(struct irc_conn *irc, const char *name, const char *from, char **args)
+{
+	int ret = 0;
+	int id = 0;
+	PurpleConnection *gc = purple_account_get_connection(irc->account);
+	const char *mech_list = NULL;
+
+	if (!args[1] || !args[2] || strncmp(args[2], "sasl ", 6))
+		return;
+	if (strncmp(args[1], "ACK", 4)) {
+		const char *tmp = _("SASL authentication failed: Server does not support SASL authentication.");
+		purple_connection_error_reason (gc,
+			PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, tmp);
+
+		irc_sasl_finish(irc);
+		return;
+	}
+
+	if ((ret = sasl_client_init(NULL)) != SASL_OK) {
+		const char *tmp = _("SASL authentication failed: Initializing SASL failed.");
+		purple_connection_error_reason (gc,
+			PURPLE_CONNECTION_ERROR_OTHER_ERROR, tmp);
+		return;
+	}
+
+	irc->sasl_cb = g_new0(sasl_callback_t, 5);
+
+	irc->sasl_cb[id].id = SASL_CB_AUTHNAME;
+	irc->sasl_cb[id].proc = irc_sasl_cb_simple;
+	irc->sasl_cb[id].context = (void *)irc;
+	id++;
+
+	irc->sasl_cb[id].id = SASL_CB_USER;
+	irc->sasl_cb[id].proc = irc_sasl_cb_simple;
+	irc->sasl_cb[id].context = (void *)irc;
+	id++;
+
+	irc->sasl_cb[id].id = SASL_CB_PASS;
+	irc->sasl_cb[id].proc = irc_sasl_cb_secret;
+	irc->sasl_cb[id].context = (void *)irc;
+	id++;
+
+	irc->sasl_cb[id].id = SASL_CB_LOG;
+	irc->sasl_cb[id].proc = irc_sasl_cb_log;
+	irc->sasl_cb[id].context = (void *)irc;
+	id++;
+
+	irc->sasl_cb[id].id = SASL_CB_LIST_END;
+
+	/* We need to do this to be able to list the mechanisms. */
+	ret = sasl_client_new("irc", irc->server, NULL, NULL, irc->sasl_cb, 0, &irc->sasl_conn);
+
+	sasl_listmech(irc->sasl_conn, NULL, "", " ", "", &mech_list, NULL, NULL);
+	purple_debug_info("irc", "SASL: we have available: %s\n", mech_list);
+
+	if (ret != SASL_OK) {
+		gchar *tmp;
+
+		purple_debug_error("irc", "sasl_client_new failed: %d\n", ret);
+		tmp = g_strdup_printf(_("Failed to initialize SASL authentication: %s"),
+			sasl_errdetail(irc->sasl_conn));
+		purple_connection_error_reason (gc,
+			PURPLE_CONNECTION_ERROR_OTHER_ERROR, tmp);
+		g_free(tmp);
+
+		return;
+	}
+
+	irc->sasl_mechs = g_string_new(mech_list);
+
+	irc_auth_start_cyrus(irc);
+}
+
+void
+irc_msg_auth(struct irc_conn *irc, char *arg)
+{
+	PurpleConnection *gc = purple_account_get_connection(irc->account);
+	char *buf, *authinfo;
+	char *serverin = NULL;
+	unsigned serverinlen = 0;
+	const gchar *c_out;
+	unsigned int clen;
+	int ret;
+
+	irc->mech_works = TRUE;
+
+	if (!arg)
+		return;
+
+	if (arg[0] != '+') {
+		serverin = arg;
+		serverinlen = strlen(serverin);
+	}
+
+	ret = sasl_client_step(irc->sasl_conn, serverin, serverinlen,
+		NULL, &c_out, &clen);
+
+	if (ret != SASL_OK && ret != SASL_CONTINUE) {
+
+		gchar *tmp = g_strdup_printf(_("SASL authentication failed: %s"),
+			sasl_errdetail(irc->sasl_conn));
+		purple_connection_error_reason (gc,
+			PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, tmp);
+		g_free(tmp);
+
+		irc_sasl_finish(irc);
+
+		return;
+	}
+
+	authinfo = purple_base64_encode((const guchar*)c_out, clen);
+
+	buf = irc_format(irc, "vv", "AUTHENTICATE", authinfo);
+	irc_send(irc, buf);
+	g_free(buf);
+	g_free(authinfo);
+}
+
+void
+irc_msg_authok(struct irc_conn *irc, const char *name, const char *from, char **args)
+{
+	char *buf;
+
+	sasl_dispose(&irc->sasl_conn);
+	irc->sasl_conn = NULL;
+	purple_debug_info("irc", "Succesfully authenticated using SASL.\n");
+
+	/* Finish auth session */
+	buf = irc_format(irc, "vv", "CAP", "END");
+	irc_send(irc, buf);
+	g_free(buf);
+}
+
+void
+irc_msg_authtryagain(struct irc_conn *irc, const char *name, const char *from, char **args)
+{
+	PurpleConnection *gc = purple_account_get_connection(irc->account);
+
+	/* We already received at least one AUTHENTICATE reply from the
+	 * server. This suggests it supports this mechanism, but the
+	 * password was incorrect. It would be better to abort and inform
+	 * the user than to try again with a different mechanism, so they
+	 * aren't told the server supports no worthy mechanisms.
+	 */
+	if (irc->mech_works) {
+		purple_connection_error_reason (gc,
+			PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Incorrect Password"));
+
+		irc_sasl_finish(irc);
+
+		return;
+	}
+
+	if (irc->current_mech) {
+		char *pos;
+		if ((pos = strstr(irc->sasl_mechs->str, irc->current_mech))) {
+			size_t index = pos - irc->sasl_mechs->str;
+			g_string_erase(irc->sasl_mechs, index, strlen(irc->current_mech));
+
+			/* Remove space which separated this mech from the next */
+			if ((irc->sasl_mechs->str)[index] == ' ') {
+				g_string_erase(irc->sasl_mechs, index, 1);
+			}
+		}
+	}
+	if (*irc->sasl_mechs->str) {
+		sasl_dispose(&irc->sasl_conn);
+
+		purple_debug_info("irc", "Now trying with %s\n", irc->sasl_mechs->str);
+		irc_auth_start_cyrus(irc);
+	} else {
+		purple_connection_error_reason (gc,
+			PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
+			_("SASL authentication failed: No worthy mechanisms found"));
+
+		irc_sasl_finish(irc);
+	}
+}
+
+void
+irc_msg_authfail(struct irc_conn *irc, const char *name, const char *from, char **args)
+{
+	PurpleConnection *gc = purple_account_get_connection(irc->account);
+
+	/* Only show an error if we did not abort ourselves. */
+	if (irc->sasl_conn) {
+		purple_debug_info("irc", "SASL authentication failed: %s", sasl_errdetail(irc->sasl_conn));
+
+		purple_connection_error_reason (gc,
+			PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Incorrect Password"));
+	}
+
+	irc_sasl_finish(irc);
+}
+
+static void
+irc_sasl_finish(struct irc_conn *irc)
+{
+	char *buf;
+
+	sasl_dispose(&irc->sasl_conn);
+	irc->sasl_conn = NULL;
+
+	g_free(irc->sasl_cb);
+	irc->sasl_cb = NULL;
+
+	/* Auth failed, abort */
+	buf = irc_format(irc, "vv", "CAP", "END");
+	irc_send(irc, buf);
+	g_free(buf);
+}
+#endif
+
 void irc_msg_ignore(struct irc_conn *irc, const char *name, const char *from, char **args)
 {
 	return;
--- a/libpurple/protocols/irc/parse.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/irc/parse.c	Sat Feb 02 21:20:08 2013 +0100
@@ -73,7 +73,7 @@
 	{ "324", "ncv:", irc_msg_chanmode },	/* Channel modes		*/
 	{ "331", "nc:",	irc_msg_topic },	/* No channel topic		*/
 	{ "332", "nc:", irc_msg_topic },	/* Channel topic		*/
-	{ "333", "*", irc_msg_ignore },		/* Topic setter stuff		*/
+	{ "333", "ncvv", irc_msg_topicinfo },	/* Topic setter stuff		*/
 	{ "352", "ncvvvnv:", irc_msg_who },	/* Channel WHO			*/
 	{ "353", "nvc:", irc_msg_names },	/* Names list			*/
 	{ "366", "nc:", irc_msg_names },	/* End of names			*/
@@ -102,6 +102,14 @@
 	{ "501", "n:", irc_msg_badmode },	/* Unknown mode flag		*/
 	{ "506", "nc:", irc_msg_nosend },	/* Must identify to send	*/
 	{ "515", "nc:", irc_msg_regonly },	/* Registration required	*/
+#ifdef HAVE_CYRUS_SASL
+	{ "903", "*", irc_msg_authok},		/* SASL auth successful		*/
+	{ "904", "*", irc_msg_authtryagain },	/* SASL auth failed, can recover		*/
+	{ "905", "*", irc_msg_authfail },	/* SASL auth failed		*/
+	{ "906", "*", irc_msg_authfail },	/* SASL auth failed		*/
+	{ "907", "*", irc_msg_authfail },	/* SASL auth failed		*/
+	{ "cap", "vv:", irc_msg_cap },		/* SASL capable			*/
+#endif
 	{ "invite", "n:", irc_msg_invite },	/* Invited			*/
 	{ "join", ":", irc_msg_join },		/* Joined a channel		*/
 	{ "kick", "cn:", irc_msg_kick },	/* KICK				*/
@@ -678,6 +686,11 @@
 				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
 				_("Disconnected."));
 		return;
+#ifdef HAVE_CYRUS_SASL
+	} else if (!strncmp(input, "AUTHENTICATE ", 13)) {
+		irc_msg_auth(irc, input + 13);
+		return;
+#endif
 	}
 
 	if (input[0] != ':' || (cur = strchr(input, ' ')) == NULL) {
--- a/libpurple/protocols/jabber/Makefile.am	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/Makefile.am	Sat Feb 02 21:20:08 2013 +0100
@@ -31,6 +31,8 @@
 			  google/gmail.h \
 			  google/google.c \
 			  google/google.h \
+			  google/google_p2p.c \
+			  google/google_p2p.h \
 			  google/google_presence.c \
 			  google/google_presence.h \
 			  google/google_roster.c \
--- a/libpurple/protocols/jabber/Makefile.mingw	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/Makefile.mingw	Sat Feb 02 21:20:08 2013 +0100
@@ -113,21 +113,9 @@
 			-lpurple
 
 ifeq ($(CYRUS_SASL), 1)
-CYRUS_SASL_TOP := $(WIN32_DEV_TOP)/cyrus-sasl-2.1.25
 INCLUDE_PATHS += -I$(CYRUS_SASL_TOP)/include
 LIB_PATHS += -L$(CYRUS_SASL_TOP)/bin
 LIBS += -llibsasl
-CYRUS_SASL_DLLS = \
-			$(CYRUS_SASL_TOP)/bin/libsasl.dll
-
-CYRUS_SASL_PLUGINS = \
-			$(CYRUS_SASL_TOP)/bin/sasl2/saslANONYMOUS.dll \
-			$(CYRUS_SASL_TOP)/bin/sasl2/saslCRAMMD5.dll \
-			$(CYRUS_SASL_TOP)/bin/sasl2/saslDIGESTMD5.dll \
-			$(CYRUS_SASL_TOP)/bin/sasl2/saslGSSAPI.dll \
-			$(CYRUS_SASL_TOP)/bin/sasl2/saslLOGIN.dll \
-			$(CYRUS_SASL_TOP)/bin/sasl2/saslPLAIN.dll
-
 endif
 
 include $(PIDGIN_COMMON_RULES)
@@ -144,11 +132,6 @@
 	cp $(GTALK_TARGET).dll $(DLL_INSTALL_DIR)
 	cp $(XMPP_TARGET).dll $(DLL_INSTALL_DIR)
 	cp $(TARGET).dll $(PURPLE_INSTALL_DIR)
-ifeq ($(CYRUS_SASL), 1)
-	mkdir -p $(PURPLE_INSTALL_DIR)/sasl2
-	cp $(CYRUS_SASL_DLLS) $(PURPLE_INSTALL_DIR)
-	cp $(CYRUS_SASL_PLUGINS) $(PURPLE_INSTALL_DIR)/sasl2
-endif
 
 $(OBJECTS): $(PURPLE_CONFIG_H)
 
--- a/libpurple/protocols/jabber/auth_scram.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/auth_scram.c	Sat Feb 02 21:20:08 2013 +0100
@@ -168,11 +168,6 @@
 	guchar *salted_password;
 	guchar *client_key, *stored_key, *client_signature, *server_key;
 
-	client_key = g_new0(guchar, hash_len);
-	stored_key = g_new0(guchar, hash_len);
-	client_signature = g_new0(guchar, hash_len);
-	server_key = g_new0(guchar, hash_len);
-
 	data->client_proof = g_string_sized_new(hash_len);
 	data->client_proof->len = hash_len;
 	data->server_signature = g_string_sized_new(hash_len);
@@ -186,6 +181,11 @@
 	if (!salted_password)
 		return FALSE;
 
+	client_key = g_new0(guchar, hash_len);
+	stored_key = g_new0(guchar, hash_len);
+	client_signature = g_new0(guchar, hash_len);
+	server_key = g_new0(guchar, hash_len);
+
 	/* client_key = HMAC(salted_password, "Client Key") */
 	hmac(data->hash, client_key, salted_password, "Client Key");
 	/* server_key = HMAC(salted_password, "Server Key") */
--- a/libpurple/protocols/jabber/buddy.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/buddy.c	Sat Feb 02 21:20:08 2013 +0100
@@ -1203,7 +1203,7 @@
 						char *img_text;
 						char *hash;
 
-						jbi->vcard_imgids = g_slist_prepend(jbi->vcard_imgids, GINT_TO_POINTER(purple_imgstore_add_with_id(g_memdup(data, size), size, "logo.png")));
+						jbi->vcard_imgids = g_slist_prepend(jbi->vcard_imgids, GINT_TO_POINTER(purple_imgstore_new_with_id(g_memdup(data, size), size, "logo.png")));
 						img_text = g_strdup_printf("<img src='" PURPLE_STORED_IMAGE_PROTOCOL "%d'>",
 						                           GPOINTER_TO_INT(jbi->vcard_imgids->data));
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google_p2p.c	Sat Feb 02 21:20:08 2013 +0100
@@ -0,0 +1,442 @@
+/**
+ * @file google_p2p.c
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "internal.h"
+
+#include "google_p2p.h"
+#include "jingle/jingle.h"
+#include "debug.h"
+
+#include <string.h>
+
+struct _JingleGoogleP2PPrivate
+{
+	GList *local_candidates;
+	GList *remote_candidates;
+};
+
+#define JINGLE_GOOGLE_P2P_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), JINGLE_TYPE_GOOGLE_P2P, JingleGoogleP2PPrivate))
+
+static void jingle_google_p2p_class_init (JingleGoogleP2PClass *klass);
+static void jingle_google_p2p_init (JingleGoogleP2P *google_p2p);
+static void jingle_google_p2p_finalize (GObject *object);
+static void jingle_google_p2p_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+static void jingle_google_p2p_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static JingleTransport *jingle_google_p2p_parse_internal(xmlnode *google_p2p);
+static xmlnode *jingle_google_p2p_to_xml_internal(JingleTransport *transport, xmlnode *content, JingleActionType action);
+static void jingle_google_p2p_add_local_candidate(JingleTransport *transport, const gchar *id, guint generation, PurpleMediaCandidate *candidate);
+static GList *jingle_google_p2p_get_remote_candidates(JingleTransport *transport);
+
+static JingleTransportClass *parent_class = NULL;
+
+enum {
+	PROP_0,
+	PROP_LOCAL_CANDIDATES,
+	PROP_REMOTE_CANDIDATES,
+};
+
+static JingleGoogleP2PCandidate *
+jingle_google_p2p_candidate_copy(JingleGoogleP2PCandidate *candidate)
+{
+	JingleGoogleP2PCandidate *new_candidate = g_new0(JingleGoogleP2PCandidate, 1);
+	new_candidate->id = g_strdup(candidate->id);
+	new_candidate->address = g_strdup(candidate->address);
+	new_candidate->port = candidate->port;
+	new_candidate->preference = candidate->preference;
+	new_candidate->type = g_strdup(candidate->type);
+	new_candidate->protocol = g_strdup(candidate->protocol);
+	new_candidate->username = g_strdup(candidate->username);
+	new_candidate->password = g_strdup(candidate->password);
+	new_candidate->generation = candidate->generation;
+
+	new_candidate->rem_known = candidate->rem_known;
+
+	return new_candidate;
+}
+
+static void
+jingle_google_p2p_candidate_free(JingleGoogleP2PCandidate *candidate)
+{
+	g_free(candidate->id);
+	g_free(candidate->address);
+	g_free(candidate->type);
+	g_free(candidate->protocol);
+	g_free(candidate->username);
+	g_free(candidate->password);
+}
+
+GType
+jingle_google_p2p_candidate_get_type(void)
+{
+	static GType type = 0;
+
+	if (type == 0) {
+		type = g_boxed_type_register_static("JingleGoogleP2PCandidate",
+				(GBoxedCopyFunc)jingle_google_p2p_candidate_copy,
+				(GBoxedFreeFunc)jingle_google_p2p_candidate_free);
+	}
+	return type;
+}
+
+JingleGoogleP2PCandidate *
+jingle_google_p2p_candidate_new(const gchar *id, guint generation,
+		const gchar *address, guint port, guint preference,
+		const gchar *type, const gchar *protocol,
+		const gchar *username, const gchar *password)
+{
+	JingleGoogleP2PCandidate *candidate = g_new0(JingleGoogleP2PCandidate, 1);
+	candidate->id = g_strdup(id);
+	candidate->address = g_strdup(address);
+	candidate->port = port;
+	candidate->preference = preference;
+	candidate->type = g_strdup(type);
+	candidate->protocol = g_strdup(protocol);
+	candidate->username = g_strdup(username);
+	candidate->password = g_strdup(password);
+	candidate->generation = generation;
+
+	candidate->rem_known = FALSE;
+	return candidate;
+}
+
+GType
+jingle_google_p2p_get_type(void)
+{
+	static GType type = 0;
+
+	if (type == 0) {
+		static const GTypeInfo info = {
+			sizeof(JingleGoogleP2PClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) jingle_google_p2p_class_init,
+			NULL,
+			NULL,
+			sizeof(JingleGoogleP2P),
+			0,
+			(GInstanceInitFunc) jingle_google_p2p_init,
+			NULL
+		};
+		type = g_type_register_static(JINGLE_TYPE_TRANSPORT, "JingleGoogleP2P", &info, 0);
+	}
+	return type;
+}
+
+static void
+jingle_google_p2p_class_init(JingleGoogleP2PClass *klass)
+{
+	GObjectClass *gobject_class = (GObjectClass *)klass;
+	parent_class = g_type_class_peek_parent(klass);
+
+	gobject_class->finalize = jingle_google_p2p_finalize;
+	gobject_class->set_property = jingle_google_p2p_set_property;
+	gobject_class->get_property = jingle_google_p2p_get_property;
+	klass->parent_class.to_xml = jingle_google_p2p_to_xml_internal;
+	klass->parent_class.parse = jingle_google_p2p_parse_internal;
+	klass->parent_class.transport_type = NS_GOOGLE_TRANSPORT_P2P;
+	klass->parent_class.add_local_candidate = jingle_google_p2p_add_local_candidate;
+	klass->parent_class.get_remote_candidates = jingle_google_p2p_get_remote_candidates;
+
+	g_object_class_install_property(gobject_class, PROP_LOCAL_CANDIDATES,
+			g_param_spec_pointer("local-candidates",
+			"Local candidates",
+			"The local candidates for this transport.",
+			G_PARAM_READABLE));
+
+	g_object_class_install_property(gobject_class, PROP_REMOTE_CANDIDATES,
+			g_param_spec_pointer("remote-candidates",
+			"Remote candidates",
+			"The remote candidates for this transport.",
+			G_PARAM_READABLE));
+
+	g_type_class_add_private(klass, sizeof(JingleGoogleP2PPrivate));
+}
+
+static void
+jingle_google_p2p_init(JingleGoogleP2P *google_p2p)
+{
+	google_p2p->priv = JINGLE_GOOGLE_P2P_GET_PRIVATE(google_p2p);
+	google_p2p->priv->local_candidates = NULL;
+	google_p2p->priv->remote_candidates = NULL;
+}
+
+static void
+jingle_google_p2p_finalize(GObject *google_p2p)
+{
+/*	JingleGoogleP2PPrivate *priv = JINGLE_GOOGLE_P2P_GET_PRIVATE(google_p2p); */
+	purple_debug_info("jingle","jingle_google_p2p_finalize\n");
+
+	G_OBJECT_CLASS(parent_class)->finalize(google_p2p);
+}
+
+static void
+jingle_google_p2p_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+	JingleGoogleP2P *google_p2p;
+
+	g_return_if_fail(object != NULL);
+	g_return_if_fail(JINGLE_IS_GOOGLE_P2P(object));
+
+	google_p2p = JINGLE_GOOGLE_P2P(object);
+
+	switch (prop_id) {
+		case PROP_LOCAL_CANDIDATES:
+			google_p2p->priv->local_candidates = g_value_get_pointer(value);
+			break;
+		case PROP_REMOTE_CANDIDATES:
+			google_p2p->priv->remote_candidates = g_value_get_pointer(value);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+jingle_google_p2p_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+	JingleGoogleP2P *google_p2p;
+
+	g_return_if_fail(object != NULL);
+	g_return_if_fail(JINGLE_IS_GOOGLE_P2P(object));
+
+	google_p2p = JINGLE_GOOGLE_P2P(object);
+
+	switch (prop_id) {
+		case PROP_LOCAL_CANDIDATES:
+			g_value_set_pointer(value, google_p2p->priv->local_candidates);
+			break;
+		case PROP_REMOTE_CANDIDATES:
+			g_value_set_pointer(value, google_p2p->priv->remote_candidates);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+jingle_google_p2p_add_local_candidate(JingleTransport *transport, const gchar *id,
+                                      guint generation, PurpleMediaCandidate *candidate)
+{
+	JingleGoogleP2P *google_p2p = JINGLE_GOOGLE_P2P(transport);
+	JingleGoogleP2PCandidate *google_p2p_candidate;
+	gchar *ip;
+	gchar *username;
+	gchar *password;
+	PurpleMediaCandidateType type;
+	PurpleMediaNetworkProtocol protocol;
+	GList *iter;
+
+	ip = purple_media_candidate_get_ip(candidate);
+	username = purple_media_candidate_get_username(candidate);
+	password = purple_media_candidate_get_password(candidate);
+	type = purple_media_candidate_get_candidate_type(candidate);
+	protocol = purple_media_candidate_get_protocol(candidate);
+
+	google_p2p_candidate = jingle_google_p2p_candidate_new(id, generation,
+			ip, purple_media_candidate_get_port(candidate),
+			purple_media_candidate_get_priority(candidate),
+			type == PURPLE_MEDIA_CANDIDATE_TYPE_HOST ? "host" :
+			type == PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX ? "srflx" :
+			type == PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX ? "prflx" :
+			type == PURPLE_MEDIA_CANDIDATE_TYPE_RELAY ? "relay" :
+			"",
+			protocol == PURPLE_MEDIA_NETWORK_PROTOCOL_UDP ? "udp" : "tcp",
+			username, password);
+
+	g_free(password);
+	g_free(username);
+	g_free(ip);
+
+	for (iter = google_p2p->priv->local_candidates; iter; iter = g_list_next(iter)) {
+		JingleGoogleP2PCandidate *c = iter->data;
+		if (!strcmp(c->id, id)) {
+			generation = c->generation + 1;
+
+			g_boxed_free(JINGLE_TYPE_GOOGLE_P2P_CANDIDATE, c);
+			google_p2p->priv->local_candidates = g_list_delete_link(
+					google_p2p->priv->local_candidates, iter);
+
+			google_p2p_candidate->generation = generation;
+
+			google_p2p->priv->local_candidates = g_list_append(
+					google_p2p->priv->local_candidates, candidate);
+			return;
+		}
+	}
+
+	google_p2p->priv->local_candidates = g_list_append(
+			google_p2p->priv->local_candidates, google_p2p_candidate);
+}
+
+static GList *
+jingle_google_p2p_get_remote_candidates(JingleTransport *transport)
+{
+	JingleGoogleP2P *google_p2p = JINGLE_GOOGLE_P2P(transport);
+	GList *candidates = google_p2p->priv->remote_candidates;
+	GList *ret = NULL;
+
+	for (; candidates; candidates = g_list_next(candidates)) {
+		JingleGoogleP2PCandidate *candidate = candidates->data;
+		PurpleMediaCandidate *new_candidate = purple_media_candidate_new("", 0,
+				!strcmp(candidate->type, "host") ?
+					PURPLE_MEDIA_CANDIDATE_TYPE_HOST :
+					!strcmp(candidate->type, "srflx") ?
+						PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX :
+						!strcmp(candidate->type, "prflx") ?
+							PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX :
+							!strcmp(candidate->type, "relay") ?
+								PURPLE_MEDIA_CANDIDATE_TYPE_RELAY : 0,
+				!strcmp(candidate->protocol, "udp") ?
+					PURPLE_MEDIA_NETWORK_PROTOCOL_UDP :
+					PURPLE_MEDIA_NETWORK_PROTOCOL_TCP,
+				candidate->address, candidate->port);
+		g_object_set(new_candidate,
+		             "username", candidate->username,
+		             "password", candidate->password,
+		             "priority", candidate->preference,
+		             NULL);
+		ret = g_list_append(ret, new_candidate);
+	}
+
+	return ret;
+}
+
+static JingleGoogleP2PCandidate *
+jingle_google_p2p_get_remote_candidate_by_id(JingleGoogleP2P *google_p2p,
+		const gchar *id)
+{
+	GList *iter = google_p2p->priv->remote_candidates;
+	for (; iter; iter = g_list_next(iter)) {
+		JingleGoogleP2PCandidate *candidate = iter->data;
+		if (!strcmp(candidate->id, id)) {
+			return candidate;
+		}
+	}
+	return NULL;
+}
+
+static void
+jingle_google_p2p_add_remote_candidate(JingleGoogleP2P *google_p2p, JingleGoogleP2PCandidate *candidate)
+{
+	JingleGoogleP2PPrivate *priv = JINGLE_GOOGLE_P2P_GET_PRIVATE(google_p2p);
+	JingleGoogleP2PCandidate *google_p2p_candidate =
+			jingle_google_p2p_get_remote_candidate_by_id(google_p2p,
+					candidate->id);
+	if (google_p2p_candidate != NULL) {
+		priv->remote_candidates = g_list_remove(priv->remote_candidates,
+		                                        google_p2p_candidate);
+		g_boxed_free(JINGLE_TYPE_GOOGLE_P2P_CANDIDATE, google_p2p_candidate);
+	}
+	priv->remote_candidates = g_list_append(priv->remote_candidates, candidate);
+}
+
+static JingleTransport *
+jingle_google_p2p_parse_internal(xmlnode *google_p2p)
+{
+	JingleTransport *transport = parent_class->parse(google_p2p);
+	xmlnode *candidate = xmlnode_get_child(google_p2p, "candidate");
+	JingleGoogleP2PCandidate *google_p2p_candidate = NULL;
+
+	for (; candidate; candidate = xmlnode_get_next_twin(candidate)) {
+		const gchar *generation = xmlnode_get_attrib(candidate, "generation");
+		const gchar *id = xmlnode_get_attrib(candidate, "name");
+		const gchar *address = xmlnode_get_attrib(candidate, "address");
+		const gchar *port = xmlnode_get_attrib(candidate, "port");
+		const gchar *preference = xmlnode_get_attrib(candidate, "preference");
+		const gchar *type = xmlnode_get_attrib(candidate, "type");
+		const gchar *protocol = xmlnode_get_attrib(candidate, "protocol");
+		const gchar *username = xmlnode_get_attrib(candidate, "username");
+		const gchar *password = xmlnode_get_attrib(candidate, "password");
+
+		if (!generation || !id || !address || !port || !preference ||
+				!type || !protocol || !username || !password)
+			continue;
+
+		google_p2p_candidate = jingle_google_p2p_candidate_new(id,
+				atoi(generation),
+				address,
+				atoi(port),
+				atoi(preference),
+				type,
+				protocol,
+				username, password);
+		google_p2p_candidate->rem_known = TRUE;
+		jingle_google_p2p_add_remote_candidate(JINGLE_GOOGLE_P2P(transport), google_p2p_candidate);
+	}
+
+	return transport;
+}
+
+static xmlnode *
+jingle_google_p2p_to_xml_internal(JingleTransport *transport, xmlnode *content, JingleActionType action)
+{
+	xmlnode *node = parent_class->to_xml(transport, content, action);
+
+	if (action == JINGLE_SESSION_INITIATE ||
+			action == JINGLE_SESSION_ACCEPT ||
+			action == JINGLE_TRANSPORT_INFO ||
+			action == JINGLE_CONTENT_ADD ||
+			action == JINGLE_TRANSPORT_REPLACE) {
+		JingleGoogleP2PPrivate *priv = JINGLE_GOOGLE_P2P_GET_PRIVATE(transport);
+		GList *iter = priv->local_candidates;
+
+		for (; iter; iter = g_list_next(iter)) {
+			JingleGoogleP2PCandidate *candidate = iter->data;
+			xmlnode *xmltransport;
+			gchar *generation, *network, *port, *preference;
+
+			if (candidate->rem_known == TRUE)
+				continue;
+
+			candidate->rem_known = TRUE;
+
+			xmltransport = xmlnode_new_child(node, "candidate");
+			generation = g_strdup_printf("%d", candidate->generation);
+			network = g_strdup_printf("%d", candidate->network);
+			port = g_strdup_printf("%d", candidate->port);
+			preference = g_strdup_printf("%d", candidate->preference);
+
+			xmlnode_set_attrib(xmltransport, "generation", generation);
+			xmlnode_set_attrib(xmltransport, "name", candidate->id);
+			xmlnode_set_attrib(xmltransport, "address", candidate->address);
+			xmlnode_set_attrib(xmltransport, "network", network);
+			xmlnode_set_attrib(xmltransport, "port", port);
+			xmlnode_set_attrib(xmltransport, "preference", preference);
+			xmlnode_set_attrib(xmltransport, "protocol", candidate->protocol);
+			xmlnode_set_attrib(xmltransport, "type", candidate->type);
+			xmlnode_set_attrib(xmltransport, "username", candidate->username);
+			xmlnode_set_attrib(xmltransport, "password", candidate->password);
+
+			g_free(generation);
+			g_free(network);
+			g_free(port);
+			g_free(preference);
+		}
+	}
+
+	return node;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google_p2p.h	Sat Feb 02 21:20:08 2013 +0100
@@ -0,0 +1,102 @@
+/**
+ * @file google_p2p.h
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef PURPLE_JABBER_JINGLE_GOOGLE_P2P_H
+#define PURPLE_JABBER_JINGLE_GOOGLE_P2P_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "jingle/transport.h"
+
+G_BEGIN_DECLS
+
+#define JINGLE_TYPE_GOOGLE_P2P            (jingle_google_p2p_get_type())
+#define JINGLE_TYPE_GOOGLE_P2P_CANDIDATE  (jingle_google_p2p_candidate_get_type())
+#define JINGLE_GOOGLE_P2P(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), JINGLE_TYPE_GOOGLE_P2P, JingleGoogleP2P))
+#define JINGLE_GOOGLE_P2P_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), JINGLE_TYPE_GOOGLE_P2P, JingleGoogleP2PClass))
+#define JINGLE_IS_GOOGLE_P2P(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), JINGLE_TYPE_GOOGLE_P2P))
+#define JINGLE_IS_GOOGLE_P2P_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), JINGLE_TYPE_GOOGLE_P2P))
+#define JINGLE_GOOGLE_P2P_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), JINGLE_TYPE_GOOGLE_P2P, JingleGoogleP2PClass))
+
+/** @copydoc _JingleGoogleP2P */
+typedef struct _JingleGoogleP2P JingleGoogleP2P;
+/** @copydoc _JingleGoogleP2PClass */
+typedef struct _JingleGoogleP2PClass JingleGoogleP2PClass;
+/** @copydoc _JingleGoogleP2PPrivate */
+typedef struct _JingleGoogleP2PPrivate JingleGoogleP2PPrivate;
+/** @copydoc _JingleGoogleP2PCandidate */
+typedef struct _JingleGoogleP2PCandidate JingleGoogleP2PCandidate;
+
+/** The Google P2P class */
+struct _JingleGoogleP2PClass
+{
+	JingleTransportClass parent_class;  /**< The parent class. */
+
+	xmlnode *(*to_xml) (JingleTransport *transport, xmlnode *content, JingleActionType action);
+	JingleTransport *(*parse) (xmlnode *transport);
+};
+
+/** The Google P2P class's private data */
+struct _JingleGoogleP2P
+{
+	JingleTransport parent;         /**< The parent of this object. */
+	JingleGoogleP2PPrivate *priv;   /**< The private data of this object. */
+};
+
+struct _JingleGoogleP2PCandidate
+{
+	gchar *id;
+	gchar *address;
+	guint port;
+	guint preference;
+	gchar *type;
+	gchar *protocol;
+	guint network;
+	gchar *username;
+	gchar *password;
+	guint generation;
+
+	gboolean rem_known; /* TRUE if the remote side knows
+	                     * about this candidate */
+};
+
+GType jingle_google_p2p_candidate_get_type(void);
+
+/**
+ * Gets the Google P2P class's GType
+ *
+ * @return The Google P2P class's GType.
+ */
+GType jingle_google_p2p_get_type(void);
+
+JingleGoogleP2PCandidate *jingle_google_p2p_candidate_new(const gchar *id,
+		guint generation, const gchar *address, guint port, guint preference,
+		const gchar *type, const gchar *protocol,
+		const gchar *username, const gchar *password);
+
+G_END_DECLS
+
+#endif /* PURPLE_JABBER_JINGLE_GOOGLE_P2P_H */
+
--- a/libpurple/protocols/jabber/jingle/content.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/jingle/content.h	Sat Feb 02 21:20:08 2013 +0100
@@ -68,10 +68,6 @@
 	JingleContentPrivate *priv;      /**< The private data of this object. */
 };
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /**
  * Gets the content class's GType
  *
@@ -111,10 +107,6 @@
 xmlnode *jingle_content_to_xml(JingleContent *content, xmlnode *jingle, JingleActionType action);
 void jingle_content_handle_action(JingleContent *content, xmlnode *xmlcontent, JingleActionType action);
 
-#ifdef __cplusplus
-}
-#endif
-
 G_END_DECLS
 
 #endif /* PURPLE_JABBER_JINGLE_CONTENT_H */
--- a/libpurple/protocols/jabber/jingle/iceudp.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/jingle/iceudp.c	Sat Feb 02 21:20:08 2013 +0100
@@ -45,6 +45,8 @@
 static void jingle_iceudp_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
 static JingleTransport *jingle_iceudp_parse_internal(xmlnode *iceudp);
 static xmlnode *jingle_iceudp_to_xml_internal(JingleTransport *transport, xmlnode *content, JingleActionType action);
+static void jingle_iceudp_add_local_candidate(JingleTransport *transport, const gchar *id, guint generation, PurpleMediaCandidate *candidate);
+static GList *jingle_iceudp_get_remote_candidates(JingleTransport *transport);
 
 static JingleTransportClass *parent_class = NULL;
 
@@ -58,10 +60,10 @@
 jingle_iceudp_candidate_copy(JingleIceUdpCandidate *candidate)
 {
 	JingleIceUdpCandidate *new_candidate = g_new0(JingleIceUdpCandidate, 1);
+	new_candidate->id = g_strdup(candidate->id);
 	new_candidate->component = candidate->component;
 	new_candidate->foundation = g_strdup(candidate->foundation);
 	new_candidate->generation = candidate->generation;
-	new_candidate->id = g_strdup(candidate->id);
 	new_candidate->ip = g_strdup(candidate->ip);
 	new_candidate->network = candidate->network;
 	new_candidate->port = candidate->port;
@@ -105,17 +107,18 @@
 }
 
 JingleIceUdpCandidate *
-jingle_iceudp_candidate_new(guint component, const gchar *foundation,
-		guint generation, const gchar *id, const gchar *ip,
+jingle_iceudp_candidate_new(const gchar *id,
+		guint component, const gchar *foundation,
+		guint generation, const gchar *ip,
 		guint network, guint port, guint priority,
 		const gchar *protocol, const gchar *type,
 		const gchar *username, const gchar *password)
 {
 	JingleIceUdpCandidate *candidate = g_new0(JingleIceUdpCandidate, 1);
+	candidate->id = g_strdup(id);
 	candidate->component = component;
 	candidate->foundation = g_strdup(foundation);
 	candidate->generation = generation;
-	candidate->id = g_strdup(id);
 	candidate->ip = g_strdup(ip);
 	candidate->network = network;
 	candidate->port = port;
@@ -165,6 +168,8 @@
 	klass->parent_class.to_xml = jingle_iceudp_to_xml_internal;
 	klass->parent_class.parse = jingle_iceudp_parse_internal;
 	klass->parent_class.transport_type = JINGLE_TRANSPORT_ICEUDP;
+	klass->parent_class.add_local_candidate = jingle_iceudp_add_local_candidate;
+	klass->parent_class.get_remote_candidates = jingle_iceudp_get_remote_candidates;
 
 	g_object_class_install_property(gobject_class, PROP_LOCAL_CANDIDATES,
 			g_param_spec_pointer("local-candidates",
@@ -246,36 +251,93 @@
 	}
 }
 
-void
-jingle_iceudp_add_local_candidate(JingleIceUdp *iceudp, JingleIceUdpCandidate *candidate)
+static void
+jingle_iceudp_add_local_candidate(JingleTransport *transport, const gchar *id, guint generation, PurpleMediaCandidate *candidate)
 {
-	GList *iter = iceudp->priv->local_candidates;
+	JingleIceUdp *iceudp = JINGLE_ICEUDP(transport);
+	PurpleMediaCandidateType type;
+	gchar *ip;
+	gchar *username;
+	gchar *password;
+	JingleIceUdpCandidate *iceudp_candidate;
+	GList *iter;
+
+	ip = purple_media_candidate_get_ip(candidate);
+	username = purple_media_candidate_get_username(candidate);
+	password = purple_media_candidate_get_password(candidate);
+	type = purple_media_candidate_get_candidate_type(candidate);
 
-	for (; iter; iter = g_list_next(iter)) {
+	iceudp_candidate = jingle_iceudp_candidate_new(id,
+			purple_media_candidate_get_component_id(candidate),
+			purple_media_candidate_get_foundation(candidate),
+			generation, ip, 0,
+			purple_media_candidate_get_port(candidate),
+			purple_media_candidate_get_priority(candidate), "udp",
+			type == PURPLE_MEDIA_CANDIDATE_TYPE_HOST ? "host" :
+			type == PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX ? "srflx" :
+			type == PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX ? "prflx" :
+			type == PURPLE_MEDIA_CANDIDATE_TYPE_RELAY ? "relay" :
+			"", username, password);
+	iceudp_candidate->reladdr = purple_media_candidate_get_base_ip(candidate);
+	iceudp_candidate->relport = purple_media_candidate_get_base_port(candidate);
+
+	g_free(password);
+	g_free(username);
+	g_free(ip);
+
+	for (iter = iceudp->priv->local_candidates; iter; iter = g_list_next(iter)) {
 		JingleIceUdpCandidate *c = iter->data;
-		if (!strcmp(c->id, candidate->id)) {
-			guint generation = c->generation + 1;
+		if (!strcmp(c->id, id)) {
+			generation = c->generation + 1;
 
 			g_boxed_free(JINGLE_TYPE_ICEUDP_CANDIDATE, c);
 			iceudp->priv->local_candidates = g_list_delete_link(
 					iceudp->priv->local_candidates, iter);
 
-			candidate->generation = generation;
+			iceudp_candidate->generation = generation;
 
 			iceudp->priv->local_candidates = g_list_append(
-					iceudp->priv->local_candidates, candidate);
+					iceudp->priv->local_candidates, iceudp_candidate);
 			return;
 		}
 	}
 
 	iceudp->priv->local_candidates = g_list_append(
-			iceudp->priv->local_candidates, candidate);
+			iceudp->priv->local_candidates, iceudp_candidate);
 }
 
-GList *
-jingle_iceudp_get_remote_candidates(JingleIceUdp *iceudp)
+static GList *
+jingle_iceudp_get_remote_candidates(JingleTransport *transport)
 {
-	return g_list_copy(iceudp->priv->remote_candidates);
+	JingleIceUdp *iceudp = JINGLE_ICEUDP(transport);
+	GList *candidates = iceudp->priv->remote_candidates;
+	GList *ret = NULL;
+
+	for (; candidates; candidates = g_list_next(candidates)) {
+		JingleIceUdpCandidate *candidate = candidates->data;
+		PurpleMediaCandidate *new_candidate = purple_media_candidate_new(
+					candidate->foundation, candidate->component,
+					!strcmp(candidate->type, "host") ?
+						PURPLE_MEDIA_CANDIDATE_TYPE_HOST :
+						!strcmp(candidate->type, "srflx") ?
+							PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX :
+							!strcmp(candidate->type, "prflx") ?
+								PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX :
+								!strcmp(candidate->type, "relay") ?
+									PURPLE_MEDIA_CANDIDATE_TYPE_RELAY : 0,
+					PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
+					candidate->ip, candidate->port);
+		g_object_set(new_candidate,
+		             "base-ip", candidate->reladdr,
+		             "base-port", candidate->relport,
+		             "username", candidate->username,
+		             "password", candidate->password,
+		             "priority", candidate->priority,
+		             NULL);
+		ret = g_list_append(ret, new_candidate);
+	}
+
+	return ret;
 }
 
 static JingleIceUdpCandidate *
@@ -335,10 +397,10 @@
 			continue;
 
 		iceudp_candidate = jingle_iceudp_candidate_new(
+				id,
 				atoi(component),
 				foundation,
 				atoi(generation),
-				id,
 				ip,
 				atoi(network),
 				atoi(port),
--- a/libpurple/protocols/jabber/jingle/iceudp.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/jingle/iceudp.h	Sat Feb 02 21:20:08 2013 +0100
@@ -67,10 +67,10 @@
 
 struct _JingleIceUdpCandidate
 {
+	gchar *id;
 	guint component;
 	gchar *foundation;
 	guint generation;
-	gchar *id;
 	gchar *ip;
 	guint network;
 	guint port;
@@ -87,10 +87,6 @@
 				 * about this candidate */
 };
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 GType jingle_iceudp_candidate_get_type(void);
 
 /**
@@ -100,17 +96,11 @@
  */
 GType jingle_iceudp_get_type(void);
 
-JingleIceUdpCandidate *jingle_iceudp_candidate_new(guint component,
-		const gchar *foundation, guint generation, const gchar *id,
+JingleIceUdpCandidate *jingle_iceudp_candidate_new(const gchar *id,
+		guint component, const gchar *foundation, guint generation,
 		const gchar *ip, guint network, guint port, guint priority,
 		const gchar *protocol, const gchar *type,
 		const gchar *username, const gchar *password);
-void jingle_iceudp_add_local_candidate(JingleIceUdp *iceudp, JingleIceUdpCandidate *candidate);
-GList *jingle_iceudp_get_remote_candidates(JingleIceUdp *iceudp);
-
-#ifdef __cplusplus
-}
-#endif
 
 G_END_DECLS
 
--- a/libpurple/protocols/jabber/jingle/jingle.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/jingle/jingle.c	Sat Feb 02 21:20:08 2013 +0100
@@ -29,6 +29,7 @@
 #include "content.h"
 #include "debug.h"
 #include "jingle.h"
+#include "google/google_p2p.h"
 #include "session.h"
 #include "iceudp.h"
 #include "rawudp.h"
@@ -58,6 +59,8 @@
 #ifdef USE_VV
 	else if (!strcmp(type, JINGLE_APP_RTP))
 		return JINGLE_TYPE_RTP;
+	else if (!strcmp(type, NS_GOOGLE_TRANSPORT_P2P))
+		return JINGLE_TYPE_GOOGLE_P2P;
 #endif
 #if 0
 	else if (!strcmp(type, JINGLE_APP_FT))
--- a/libpurple/protocols/jabber/jingle/jingle.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/jingle/jingle.h	Sat Feb 02 21:20:08 2013 +0100
@@ -30,10 +30,6 @@
 
 G_BEGIN_DECLS
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #define JINGLE "urn:xmpp:jingle:1"
 #define JINGLE_ERROR "urn:xmpp:jingle:errors:0"
 #define JINGLE_APP_FT "urn:xmpp:jingle:apps:file-transfer:1"
@@ -86,10 +82,6 @@
     const gchar *relay_username, const gchar *relay_password, guint *num_params);
 #endif
 
-#ifdef __cplusplus
-}
-#endif
-
 G_END_DECLS
 
 #endif /* PURPLE_JABBER_JINGLE_H */
--- a/libpurple/protocols/jabber/jingle/rawudp.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/jingle/rawudp.c	Sat Feb 02 21:20:08 2013 +0100
@@ -45,6 +45,8 @@
 static void jingle_rawudp_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
 static JingleTransport *jingle_rawudp_parse_internal(xmlnode *rawudp);
 static xmlnode *jingle_rawudp_to_xml_internal(JingleTransport *transport, xmlnode *content, JingleActionType action);
+static void jingle_rawudp_add_local_candidate(JingleTransport *transport, const gchar *id, guint generation, PurpleMediaCandidate *candidate);
+static GList *jingle_rawudp_get_remote_candidates(JingleTransport *transport);
 
 static JingleTransportClass *parent_class = NULL;
 
@@ -137,6 +139,8 @@
 	klass->parent_class.to_xml = jingle_rawudp_to_xml_internal;
 	klass->parent_class.parse = jingle_rawudp_parse_internal;
 	klass->parent_class.transport_type = JINGLE_TRANSPORT_RAWUDP;
+	klass->parent_class.add_local_candidate = jingle_rawudp_add_local_candidate;
+	klass->parent_class.get_remote_candidates = jingle_rawudp_get_remote_candidates;
 
 	g_object_class_install_property(gobject_class, PROP_LOCAL_CANDIDATES,
 			g_param_spec_pointer("local-candidates",
@@ -218,36 +222,58 @@
 	}
 }
 
-void
-jingle_rawudp_add_local_candidate(JingleRawUdp *rawudp, JingleRawUdpCandidate *candidate)
+static void
+jingle_rawudp_add_local_candidate(JingleTransport *transport, const gchar *id, guint generation, PurpleMediaCandidate *candidate)
 {
-	GList *iter = rawudp->priv->local_candidates;
+	JingleRawUdp *rawudp = JINGLE_RAWUDP(transport);
+	gchar *ip;
+	JingleRawUdpCandidate *rawudp_candidate;
+	GList *iter;
 
-	for (; iter; iter = g_list_next(iter)) {
+	ip = purple_media_candidate_get_ip(candidate);
+	rawudp_candidate = jingle_rawudp_candidate_new(id, generation,
+			purple_media_candidate_get_component_id(candidate),
+			ip, purple_media_candidate_get_port(candidate));
+	g_free(ip);
+
+	for (iter = rawudp->priv->local_candidates; iter; iter = g_list_next(iter)) {
 		JingleRawUdpCandidate *c = iter->data;
-		if (!strcmp(c->id, candidate->id)) {
-			guint generation = c->generation + 1;
+		if (!strcmp(c->id, id)) {
+			generation = c->generation + 1;
 
 			g_boxed_free(JINGLE_TYPE_RAWUDP_CANDIDATE, c);
 			rawudp->priv->local_candidates = g_list_delete_link(
 					rawudp->priv->local_candidates, iter);
 
-			candidate->generation = generation;
+			rawudp_candidate->generation = generation;
 
 			rawudp->priv->local_candidates = g_list_append(
-					rawudp->priv->local_candidates, candidate);
+					rawudp->priv->local_candidates, rawudp_candidate);
 			return;
 		}
 	}
 
 	rawudp->priv->local_candidates = g_list_append(
-			rawudp->priv->local_candidates, candidate);
+			rawudp->priv->local_candidates, rawudp_candidate);
 }
 
-GList *
-jingle_rawudp_get_remote_candidates(JingleRawUdp *rawudp)
+static GList *
+jingle_rawudp_get_remote_candidates(JingleTransport *transport)
 {
-	return g_list_copy(rawudp->priv->remote_candidates);
+	JingleRawUdp *rawudp = JINGLE_RAWUDP(transport);
+	GList *candidates = rawudp->priv->remote_candidates;
+	GList *ret = NULL;
+
+	for (; candidates; candidates = g_list_next(candidates)) {
+		JingleRawUdpCandidate *candidate = candidates->data;
+		ret = g_list_append(ret, purple_media_candidate_new("",
+					candidate->component,
+					PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX,
+					PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
+					candidate->ip, candidate->port));
+	}
+
+	return ret;
 }
 
 static JingleRawUdpCandidate *
--- a/libpurple/protocols/jabber/jingle/rawudp.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/jingle/rawudp.h	Sat Feb 02 21:20:08 2013 +0100
@@ -77,10 +77,6 @@
 				 * about this candidate */
 };
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 GType jingle_rawudp_candidate_get_type(void);
 
 /**
@@ -92,12 +88,6 @@
 
 JingleRawUdpCandidate *jingle_rawudp_candidate_new(const gchar *id,
 		guint generation, guint component, const gchar *ip, guint port);
-void jingle_rawudp_add_local_candidate(JingleRawUdp *rawudp, JingleRawUdpCandidate *candidate);
-GList *jingle_rawudp_get_remote_candidates(JingleRawUdp *rawudp);
-
-#ifdef __cplusplus
-}
-#endif
 
 G_END_DECLS
 
--- a/libpurple/protocols/jabber/jingle/rtp.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/jingle/rtp.c	Sat Feb 02 21:20:08 2013 +0100
@@ -28,6 +28,7 @@
 
 #include "jabber.h"
 #include "jingle.h"
+#include "google/google_p2p.h"
 #include "media.h"
 #include "mediamanager.h"
 #include "iceudp.h"
@@ -226,134 +227,23 @@
 	return media;
 }
 
-static JingleRawUdpCandidate *
-jingle_rtp_candidate_to_rawudp(JingleSession *session, guint generation,
-		PurpleMediaCandidate *candidate)
-{
-	gchar *id = jabber_get_next_id(jingle_session_get_js(session));
-	gchar *ip = purple_media_candidate_get_ip(candidate);
-	JingleRawUdpCandidate *rawudp_candidate =
-			jingle_rawudp_candidate_new(id, generation,
-			purple_media_candidate_get_component_id(candidate),
-			ip, purple_media_candidate_get_port(candidate));
-	g_free(ip);
-	g_free(id);
-	return rawudp_candidate;
-}
-
-static JingleIceUdpCandidate *
-jingle_rtp_candidate_to_iceudp(JingleSession *session, guint generation,
-		PurpleMediaCandidate *candidate)
-{
-	gchar *id = jabber_get_next_id(jingle_session_get_js(session));
-	gchar *ip = purple_media_candidate_get_ip(candidate);
-	gchar *username = purple_media_candidate_get_username(candidate);
-	gchar *password = purple_media_candidate_get_password(candidate);
-	PurpleMediaCandidateType type =
-			purple_media_candidate_get_candidate_type(candidate);
-
-	JingleIceUdpCandidate *iceudp_candidate = jingle_iceudp_candidate_new(
-			purple_media_candidate_get_component_id(candidate),
-			purple_media_candidate_get_foundation(candidate),
-			generation, id, ip, 0,
-			purple_media_candidate_get_port(candidate),
-			purple_media_candidate_get_priority(candidate), "udp",
-			type == PURPLE_MEDIA_CANDIDATE_TYPE_HOST ? "host" :
-			type == PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX ? "srflx" :
-			type == PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX ? "prflx" :
-			type == PURPLE_MEDIA_CANDIDATE_TYPE_RELAY ? "relay" :
-			"", username, password);
-	iceudp_candidate->reladdr =
-			purple_media_candidate_get_base_ip(candidate);
-	iceudp_candidate->relport =
-			purple_media_candidate_get_base_port(candidate);
-	g_free(password);
-	g_free(username);
-	g_free(ip);
-	g_free(id);
-	return iceudp_candidate;
-}
-
 static JingleTransport *
-jingle_rtp_candidates_to_transport(JingleSession *session, GType type, guint generation, GList *candidates)
+jingle_rtp_candidates_to_transport(JingleSession *session, const gchar *type, guint generation, GList *candidates)
 {
-	if (type == JINGLE_TYPE_RAWUDP) {
-		JingleTransport *transport = jingle_transport_create(JINGLE_TRANSPORT_RAWUDP);
-		JingleRawUdpCandidate *rawudp_candidate;
-		for (; candidates; candidates = g_list_next(candidates)) {
-			PurpleMediaCandidate *candidate = candidates->data;
-			rawudp_candidate = jingle_rtp_candidate_to_rawudp(
-					session, generation, candidate);
-			jingle_rawudp_add_local_candidate(
-					JINGLE_RAWUDP(transport),
-					rawudp_candidate);
-		}
-		return transport;
-	} else if (type == JINGLE_TYPE_ICEUDP) {
-		JingleTransport *transport = jingle_transport_create(JINGLE_TRANSPORT_ICEUDP);
-		JingleIceUdpCandidate *iceudp_candidate;
-		for (; candidates; candidates = g_list_next(candidates)) {
-			PurpleMediaCandidate *candidate = candidates->data;
-			iceudp_candidate = jingle_rtp_candidate_to_iceudp(
-					session, generation, candidate);
-			jingle_iceudp_add_local_candidate(
-					JINGLE_ICEUDP(transport),
-					iceudp_candidate);
-		}
-		return transport;
-	} else {
+	JingleTransport *transport;
+
+	transport = jingle_transport_create(type);
+	if (!transport)
 		return NULL;
-	}
-}
-
-static GList *
-jingle_rtp_transport_to_candidates(JingleTransport *transport)
-{
-	const gchar *type = jingle_transport_get_transport_type(transport);
-	GList *ret = NULL;
-	if (!strcmp(type, JINGLE_TRANSPORT_RAWUDP)) {
-		GList *candidates = jingle_rawudp_get_remote_candidates(JINGLE_RAWUDP(transport));
 
-		for (; candidates; candidates = g_list_delete_link(candidates, candidates)) {
-			JingleRawUdpCandidate *candidate = candidates->data;
-			ret = g_list_append(ret, purple_media_candidate_new(
-					"", candidate->component,
-					PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX,
-					PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
-					candidate->ip, candidate->port));
-		}
-
-		return ret;
-	} else if (!strcmp(type, JINGLE_TRANSPORT_ICEUDP)) {
-		GList *candidates = jingle_iceudp_get_remote_candidates(JINGLE_ICEUDP(transport));
+	for (; candidates; candidates = g_list_next(candidates)) {
+		PurpleMediaCandidate *candidate = candidates->data;
+		gchar *id = jabber_get_next_id(jingle_session_get_js(session));
+		jingle_transport_add_local_candidate(transport, id, generation, candidate);
+		g_free(id);
+	}
 
-		for (; candidates; candidates = g_list_delete_link(candidates, candidates)) {
-			JingleIceUdpCandidate *candidate = candidates->data;
-			PurpleMediaCandidate *new_candidate = purple_media_candidate_new(
-					candidate->foundation, candidate->component,
-					!strcmp(candidate->type, "host") ?
-					PURPLE_MEDIA_CANDIDATE_TYPE_HOST :
-					!strcmp(candidate->type, "srflx") ?
-					PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX :
-					!strcmp(candidate->type, "prflx") ?
-					PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX :
-					!strcmp(candidate->type, "relay") ?
-					PURPLE_MEDIA_CANDIDATE_TYPE_RELAY : 0,
-					PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
-					candidate->ip, candidate->port);
-			g_object_set(new_candidate,
-					"base-ip", candidate->reladdr,
-					"base-port", candidate->relport,
-					"username", candidate->username,
-					"password", candidate->password,
-					"priority", candidate->priority, NULL);
-			ret = g_list_append(ret, new_candidate);
-		}
-
-		return ret;
-	} else {
-		return NULL;
-	}
+	return transport;
 }
 
 static void jingle_rtp_ready(JingleSession *session);
@@ -378,10 +268,9 @@
 
 	oldtransport = jingle_content_get_transport(content);
 	candidates = purple_media_get_local_candidates(media, sid, name);
-	transport = JINGLE_TRANSPORT(jingle_rtp_candidates_to_transport(
-			session, JINGLE_IS_RAWUDP(oldtransport) ?
-				JINGLE_TYPE_RAWUDP : JINGLE_TYPE_ICEUDP,
-			0, candidates));
+	transport = jingle_rtp_candidates_to_transport(
+			session, jingle_transport_get_transport_type(oldtransport),
+			0, candidates);
 
 	g_list_free(candidates);
 	g_object_unref(oldtransport);
@@ -404,9 +293,9 @@
 static void
 jingle_rtp_new_candidate_cb(PurpleMedia *media, gchar *sid, gchar *name, PurpleMediaCandidate *candidate, JingleSession *session)
 {
-	JingleContent *content = jingle_session_find_content(
-			session, sid, NULL);
+	JingleContent *content = jingle_session_find_content(session, sid, NULL);
 	JingleTransport *transport;
+	gchar *id;
 
 	purple_debug_info("jingle-rtp", "jingle_rtp_new_candidate_cb\n");
 
@@ -419,19 +308,13 @@
 
 	transport = jingle_content_get_transport(content);
 
-	if (JINGLE_IS_ICEUDP(transport))
-		jingle_iceudp_add_local_candidate(JINGLE_ICEUDP(transport),
-				jingle_rtp_candidate_to_iceudp(
-				session, 1, candidate));
-	else if (JINGLE_IS_RAWUDP(transport))
-		jingle_rawudp_add_local_candidate(JINGLE_RAWUDP(transport),
-				jingle_rtp_candidate_to_rawudp(
-				session, 1, candidate));
+	id = jabber_get_next_id(jingle_session_get_js(session));
+	jingle_transport_add_local_candidate(transport, id, 1, candidate);
+	g_free(id);
 
 	g_object_unref(transport);
 
-	jabber_iq_send(jingle_session_to_packet(session,
-			JINGLE_TRANSPORT_INFO));
+	jabber_iq_send(jingle_session_to_packet(session, JINGLE_TRANSPORT_INFO));
 }
 
 static void
@@ -604,6 +487,8 @@
 		transmitter = "rawudp";
 	else if (JINGLE_IS_ICEUDP(transport))
 		transmitter = "nice";
+	else if (JINGLE_IS_GOOGLE_P2P(transport))
+		transmitter = "nice";
 	else
 		transmitter = "notransmitter";
 	g_object_unref(transport);
@@ -827,7 +712,7 @@
 			transport = jingle_transport_parse(
 					xmlnode_get_child(xmlcontent, "transport"));
 			description = xmlnode_get_child(xmlcontent, "description");
-			candidates = jingle_rtp_transport_to_candidates(transport);
+			candidates = jingle_transport_get_remote_candidates(transport);
 			codecs = jingle_rtp_parse_codecs(description);
 			name = jingle_content_get_name(content);
 			remote_jid = jingle_session_get_remote_jid(session);
@@ -863,7 +748,7 @@
 			JingleSession *session = jingle_content_get_session(content);
 			JingleTransport *transport = jingle_transport_parse(
 					xmlnode_get_child(xmlcontent, "transport"));
-			GList *candidates = jingle_rtp_transport_to_candidates(transport);
+			GList *candidates = jingle_transport_get_remote_candidates(transport);
 			gchar *name = jingle_content_get_name(content);
 			gchar *remote_jid =
 					jingle_session_get_remote_jid(session);
@@ -973,6 +858,8 @@
 		transport_type = JINGLE_TRANSPORT_ICEUDP;
 	} else if (jabber_resource_has_capability(jbr, JINGLE_TRANSPORT_RAWUDP)) {
 		transport_type = JINGLE_TRANSPORT_RAWUDP;
+	} else if (jabber_resource_has_capability(jbr, NS_GOOGLE_TRANSPORT_P2P)) {
+		transport_type = NS_GOOGLE_TRANSPORT_P2P;
 	} else {
 		purple_debug_error("jingle-rtp", "Resource doesn't support "
 				"the same transport types\n");
--- a/libpurple/protocols/jabber/jingle/rtp.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/jingle/rtp.h	Sat Feb 02 21:20:08 2013 +0100
@@ -65,10 +65,6 @@
 	JingleRtpPrivate *priv;      /**< The private data of this object. */
 };
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /**
  * Gets the rtp class's GType
  *
@@ -84,10 +80,6 @@
 				   PurpleMediaSessionType type);
 void jingle_rtp_terminate_session(JabberStream *js, const gchar *who);
 
-#ifdef __cplusplus
-}
-#endif
-
 G_END_DECLS
 
 #endif /* USE_VV */
--- a/libpurple/protocols/jabber/jingle/session.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/jingle/session.h	Sat Feb 02 21:20:08 2013 +0100
@@ -62,10 +62,6 @@
 
 struct _JingleContent;
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /**
  * Gets the session class's GType
  *
@@ -109,10 +105,6 @@
 JabberIq *jingle_session_terminate_packet(JingleSession *session, const gchar *reason);
 JabberIq *jingle_session_redirect_packet(JingleSession *session, const gchar *sid);
 
-#ifdef __cplusplus
-}
-#endif
-
 G_END_DECLS
 
 #endif /* PURPLE_JABBER_JINGLE_SESSION_H */
--- a/libpurple/protocols/jabber/jingle/transport.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/jingle/transport.c	Sat Feb 02 21:20:08 2013 +0100
@@ -44,6 +44,8 @@
 static void jingle_transport_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
 JingleTransport *jingle_transport_parse_internal(xmlnode *transport);
 xmlnode *jingle_transport_to_xml_internal(JingleTransport *transport, xmlnode *content, JingleActionType action);
+static void jingle_transport_add_local_candidate_internal(JingleTransport *transport, const gchar *id, guint generation, PurpleMediaCandidate *candidate);
+static GList *jingle_transport_get_remote_candidates_internal(JingleTransport *transport);
 
 static GObjectClass *parent_class = NULL;
 
@@ -85,6 +87,8 @@
 	gobject_class->get_property = jingle_transport_get_property;
 	klass->to_xml = jingle_transport_to_xml_internal;
 	klass->parse = jingle_transport_parse_internal;
+	klass->add_local_candidate = jingle_transport_add_local_candidate_internal;
+	klass->get_remote_candidates = jingle_transport_get_remote_candidates_internal;
 
 	g_type_class_add_private(klass, sizeof(JingleTransportPrivate));
 }
@@ -143,6 +147,32 @@
 	return JINGLE_TRANSPORT_GET_CLASS(transport)->transport_type;
 }
 
+void
+jingle_transport_add_local_candidate(JingleTransport *transport, const gchar *id,
+                                     guint generation, PurpleMediaCandidate *candidate)
+{
+	JINGLE_TRANSPORT_GET_CLASS(transport)->add_local_candidate(transport, id,
+	                                                           generation, candidate);
+}
+
+void
+jingle_transport_add_local_candidate_internal(JingleTransport *transport, const gchar *id, guint generation, PurpleMediaCandidate *candidate)
+{
+	/* Nothing to do */
+}
+
+GList *
+jingle_transport_get_remote_candidates(JingleTransport *transport)
+{
+	return JINGLE_TRANSPORT_GET_CLASS(transport)->get_remote_candidates(transport);
+}
+
+static GList *
+jingle_transport_get_remote_candidates_internal(JingleTransport *transport)
+{
+	return NULL;
+}
+
 JingleTransport *
 jingle_transport_parse_internal(xmlnode *transport)
 {
--- a/libpurple/protocols/jabber/jingle/transport.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/jingle/transport.h	Sat Feb 02 21:20:08 2013 +0100
@@ -55,6 +55,8 @@
 	const gchar *transport_type;
 	xmlnode *(*to_xml) (JingleTransport *transport, xmlnode *content, JingleActionType action);
 	JingleTransport *(*parse) (xmlnode *transport);
+	void (*add_local_candidate) (JingleTransport *transport, const gchar *id, guint generation, PurpleMediaCandidate *candidate);
+	GList *(*get_remote_candidates) (JingleTransport *transport);
 };
 
 /** The transport class's private data */
@@ -64,10 +66,6 @@
 	JingleTransportPrivate *priv;      /**< The private data of this object. */
 };
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /**
  * Gets the transport class's GType
  *
@@ -77,15 +75,13 @@
 
 JingleTransport *jingle_transport_create(const gchar *type);
 const gchar *jingle_transport_get_transport_type(JingleTransport *transport);
-void jingle_transport_add_candidate();
+
+void jingle_transport_add_local_candidate(JingleTransport *transport, const gchar *id, guint generation, PurpleMediaCandidate *candidate);
+GList *jingle_transport_get_remote_candidates(JingleTransport *transport);
 
 JingleTransport *jingle_transport_parse(xmlnode *transport);
 xmlnode *jingle_transport_to_xml(JingleTransport *transport, xmlnode *content, JingleActionType action);
 
-#ifdef __cplusplus
-}
-#endif
-
 G_END_DECLS
 
 #endif /* PURPLE_JABBER_JINGLE_TRANSPORT_H */
--- a/libpurple/protocols/jabber/message.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/message.c	Sat Feb 02 21:20:08 2013 +0100
@@ -219,6 +219,7 @@
 {
 	JabberID *jid = jabber_id_new(jm->from);
 	JabberChat *chat;
+	PurpleMessageFlags messageFlags = 0;
 
 	if(!jid)
 		return;
@@ -231,6 +232,7 @@
 	if(jm->subject) {
 		purple_conv_chat_set_topic(PURPLE_CONV_CHAT(chat->conv), jid->resource,
 				jm->subject);
+		messageFlags |= PURPLE_MESSAGE_NO_LOG;
 		if(!jm->xhtml && !jm->body) {
 			char *msg, *tmp, *tmp2;
 			tmp = g_markup_escape_text(jm->subject, -1);
@@ -239,7 +241,7 @@
 				msg = g_strdup_printf(_("%s has set the topic to: %s"), jid->resource, tmp2);
 			else
 				msg = g_strdup_printf(_("The topic is: %s"), tmp2);
-			purple_conv_chat_write(PURPLE_CONV_CHAT(chat->conv), "", msg, PURPLE_MESSAGE_SYSTEM, jm->sent);
+			purple_conv_chat_write(PURPLE_CONV_CHAT(chat->conv), "", msg, messageFlags | PURPLE_MESSAGE_SYSTEM, jm->sent);
 			g_free(tmp);
 			g_free(tmp2);
 			g_free(msg);
@@ -249,12 +251,12 @@
 	if(jm->xhtml || jm->body) {
 		if(jid->resource)
 			serv_got_chat_in(jm->js->gc, chat->id, jid->resource,
-							jm->delayed ? PURPLE_MESSAGE_DELAYED : 0,
+							messageFlags | (jm->delayed ? PURPLE_MESSAGE_DELAYED : 0),
 							jm->xhtml ? jm->xhtml : jm->body, jm->sent);
 		else if(chat->muc)
 			purple_conv_chat_write(PURPLE_CONV_CHAT(chat->conv), "",
 							jm->xhtml ? jm->xhtml : jm->body,
-							PURPLE_MESSAGE_SYSTEM, jm->sent);
+							messageFlags | PURPLE_MESSAGE_SYSTEM, jm->sent);
 	}
 
 	jabber_id_free(jid);
--- a/libpurple/protocols/jabber/namespaces.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/namespaces.h	Sat Feb 02 21:20:08 2013 +0100
@@ -109,6 +109,8 @@
 #define NS_GOOGLE_SESSION_PHONE "http://www.google.com/session/phone"
 #define NS_GOOGLE_SESSION_VIDEO "http://www.google.com/session/video"
 
+#define NS_GOOGLE_TRANSPORT_P2P "http://www.google.com/transport/p2p"
+
 /* Apple extension(s) */
 #define NS_APPLE_IDLE "http://www.apple.com/xmpp/idle"
 
--- a/libpurple/protocols/jabber/oob.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/oob.c	Sat Feb 02 21:20:08 2013 +0100
@@ -211,6 +211,7 @@
 	jox = g_new0(JabberOOBXfer, 1);
 	if (!purple_url_parse(url, &jox->address, &jox->port, &jox->page, NULL, NULL)) {
 		g_free(url);
+		g_free(jox);
 		return;
 	}
 	g_free(url);
--- a/libpurple/protocols/jabber/presence.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/jabber/presence.c	Sat Feb 02 21:20:08 2013 +0100
@@ -384,7 +384,7 @@
 	char *who;
 };
 
-static void authorize_add_cb(gpointer data)
+static void authorize_add_cb(const char *message, gpointer data)
 {
 	struct _jabber_add_permit *jap = data;
 	if(PURPLE_CONNECTION_IS_VALID(jap->gc))
@@ -394,7 +394,7 @@
 	g_free(jap);
 }
 
-static void deny_add_cb(gpointer data)
+static void deny_add_cb(const char *message, gpointer data)
 {
 	struct _jabber_add_permit *jap = data;
 	if(PURPLE_CONNECTION_IS_VALID(jap->gc))
--- a/libpurple/protocols/msn/msn.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/msn/msn.c	Sat Feb 02 21:20:08 2013 +0100
@@ -2783,7 +2783,7 @@
 		{
 			char buf[1024];
 			purple_debug_info("msn", "%s is %" G_GSIZE_FORMAT " bytes\n", photo_url_text, len);
-			id = purple_imgstore_add_with_id(g_memdup(url_text, len), len, NULL);
+			id = purple_imgstore_new_with_id(g_memdup(url_text, len), len, NULL);
 			g_snprintf(buf, sizeof(buf), "<img id=\"%d\"><br>", id);
 			purple_notify_user_info_prepend_pair_html(user_info, NULL, buf);
 		}
--- a/libpurple/protocols/msn/notification.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/msn/notification.c	Sat Feb 02 21:20:08 2013 +0100
@@ -1592,7 +1592,7 @@
 		/* Disconnect others, if MPOP is disabled */
 		if (is_me
 		 && !session->enable_mpop
-		 && strncasecmp(id + 1, session->guid, 36) != 0) {
+		 && g_ascii_strncasecmp(id + 1, session->guid, 36) != 0) {
 			purple_debug_info("msn", "Disconnecting Endpoint %s\n", id);
 
 			tmp = g_strdup_printf("%s;%s", user->passport, id);
--- a/libpurple/protocols/msn/switchboard.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/msn/switchboard.c	Sat Feb 02 21:20:08 2013 +0100
@@ -827,7 +827,7 @@
 		return;
 	}
 
-	imgid = purple_imgstore_add_with_id(image_data, image_len, NULL);
+	imgid = purple_imgstore_new_with_id(image_data, image_len, NULL);
 	image_msg = g_strdup_printf("<IMG SRC='" PURPLE_STORED_IMAGE_PROTOCOL "%d'>",
 	                            imgid);
 
--- a/libpurple/protocols/msn/user.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/msn/user.c	Sat Feb 02 21:20:08 2013 +0100
@@ -761,17 +761,7 @@
 	str = purple_normalize_nocase(NULL, msn_user_get_passport(user));
 	pass = g_strdup(str);
 
-#if GLIB_CHECK_VERSION(2,16,0)
 	result = g_strcmp0(pass, purple_normalize_nocase(NULL, passport));
-#else
-	str = purple_normalize_nocase(NULL, passport);
-	if (!pass)
-		result = -(pass != str);
-	else if (!str)
-		result = pass != str;
-	else
-		result = strcmp(pass, str);
-#endif /* GLIB < 2.16.0 */
 
 	g_free(pass);
 
--- a/libpurple/protocols/msn/userlist.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/msn/userlist.c	Sat Feb 02 21:20:08 2013 +0100
@@ -46,7 +46,7 @@
  * Callbacks
  **************************************************************************/
 static void
-msn_accept_add_cb(gpointer data)
+msn_accept_add_cb(const char *message, gpointer data)
 {
 	MsnPermitAdd *pa = data;
 
@@ -71,7 +71,7 @@
 }
 
 static void
-msn_cancel_add_cb(gpointer data)
+msn_cancel_add_cb(const char *message, gpointer data)
 {
 	MsnPermitAdd *pa = data;
 
--- a/libpurple/protocols/mxit/actions.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/mxit/actions.c	Sat Feb 02 21:20:08 2013 +0100
@@ -43,11 +43,12 @@
  */
 static void mxit_profile_cb( PurpleConnection* gc, PurpleRequestFields* fields )
 {
-	struct MXitSession*		session	= purple_connection_get_protocol_data( gc ) ;
+	struct MXitSession*		session	= purple_connection_get_protocol_data( gc );
 	PurpleRequestField*		field	= NULL;
 	const char*				name	= NULL;
 	const char*				bday	= NULL;
 	const char*				err		= NULL;
+	GList*					entry	= NULL;
 
 	purple_debug_info( MXIT_PLUGIN_ID, "mxit_profile_cb\n" );
 
@@ -166,6 +167,14 @@
 		g_string_append( attributes, attrib );
 		acount++;
 
+		/* relationship status */
+		field = purple_request_fields_get_field( fields, "relationship" );
+		entry = g_list_first( purple_request_field_list_get_selected( field ) );
+		profile->relationship = atoi( purple_request_field_list_get_data( field, entry->data ) );
+		g_snprintf( attrib, sizeof( attrib ), "\01%s\01%i\01%i", CP_PROFILE_RELATIONSHIP, CP_PROFILE_TYPE_SHORT, profile->relationship );
+		g_string_append( attributes, attrib );
+		acount++;
+
 		/* update flags */
 		field = purple_request_fields_get_field( fields, "searchable" );
 		if ( purple_request_field_bool_get_value( field ) )		/* is searchable -> clear not-searchable flag */
@@ -253,6 +262,22 @@
 		field = purple_request_field_string_new( "whereami", _( "Where I Live" ), profile->whereami, FALSE);
 		purple_request_field_group_add_field( public_group, field );
 
+		/* relationship status */
+		field = purple_request_field_list_new( "relationship", _( "Relationship Status" ) );
+		purple_request_field_list_set_multi_select( field, FALSE );
+		purple_request_field_list_add_icon( field, mxit_relationship_to_name( MXIT_RELATIONSHIP_UNKNOWN ), NULL, g_strdup_printf( "%i", MXIT_RELATIONSHIP_UNKNOWN ) );
+		purple_request_field_list_add_icon( field, mxit_relationship_to_name( MXIT_RELATIONSHIP_DONTSAY ), NULL, g_strdup_printf( "%i", MXIT_RELATIONSHIP_DONTSAY ) );
+		purple_request_field_list_add_icon( field, mxit_relationship_to_name( MXIT_RELATIONSHIP_SINGLE ), NULL, g_strdup_printf( "%i", MXIT_RELATIONSHIP_SINGLE ) );
+		purple_request_field_list_add_icon( field, mxit_relationship_to_name( MXIT_RELATIONSHIP_INVOLVED ), NULL, g_strdup_printf( "%i", MXIT_RELATIONSHIP_INVOLVED ) );
+		purple_request_field_list_add_icon( field, mxit_relationship_to_name( MXIT_RELATIONSHIP_ENGAGED ), NULL, g_strdup_printf( "%i", MXIT_RELATIONSHIP_ENGAGED ) );
+		purple_request_field_list_add_icon( field, mxit_relationship_to_name( MXIT_RELATIONSHIP_MARRIED ), NULL, g_strdup_printf( "%i", MXIT_RELATIONSHIP_MARRIED ) );
+		purple_request_field_list_add_icon( field, mxit_relationship_to_name( MXIT_RELATIONSHIP_COMPLICATED ), NULL, g_strdup_printf( "%i", MXIT_RELATIONSHIP_COMPLICATED ) );
+		purple_request_field_list_add_icon( field, mxit_relationship_to_name( MXIT_RELATIONSHIP_WIDOWED ), NULL, g_strdup_printf( "%i", MXIT_RELATIONSHIP_WIDOWED ) );
+		purple_request_field_list_add_icon( field, mxit_relationship_to_name( MXIT_RELATIONSHIP_SEPARATED ), NULL, g_strdup_printf( "%i", MXIT_RELATIONSHIP_SEPARATED ) );
+		purple_request_field_list_add_icon( field, mxit_relationship_to_name( MXIT_RELATIONSHIP_DIVORCED ), NULL, g_strdup_printf( "%i", MXIT_RELATIONSHIP_DIVORCED ) );
+		purple_request_field_list_add_selected( field, mxit_relationship_to_name( profile->relationship ) );
+		purple_request_field_group_add_field( public_group, field );
+
 		purple_request_fields_add_group( fields, public_group );
 	}
 
--- a/libpurple/protocols/mxit/cipher.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/mxit/cipher.c	Sat Feb 02 21:20:08 2013 +0100
@@ -163,6 +163,10 @@
 	/* base64 decode the message */
 	raw_message = purple_base64_decode( message, &raw_len );
 
+	/* AES-encrypted data is always blocks of 16 bytes */
+	if ( ( raw_len == 0 ) || ( raw_len % 16 != 0 ) )
+		return NULL;
+
 	/* build the AES key */
 	ExpandKey( (unsigned char*) transport_layer_key( session ), (unsigned char*) exkey );
 
--- a/libpurple/protocols/mxit/formcmds.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/mxit/formcmds.c	Sat Feb 02 21:20:08 2013 +0100
@@ -107,7 +107,7 @@
 	}
 
 	/* we now have the inline image, store a copy in the imagestore */
-	id = purple_imgstore_add_with_id(g_memdup(url_text, len), len, NULL);
+	id = purple_imgstore_new_with_id(g_memdup(url_text, len), len, NULL);
 
 	/* map the inline image id to purple image id */
 	intptr = g_malloc(sizeof(int));
@@ -335,7 +335,7 @@
 	if (img) {
 		rawimg = purple_base64_decode(img, &rawimglen);
 		//purple_util_write_data_to_file_absolute("/tmp/mxitinline.png", (char*) rawimg, rawimglen);
-		imgid = purple_imgstore_add_with_id(rawimg, rawimglen, NULL);
+		imgid = purple_imgstore_new_with_id(rawimg, rawimglen, NULL);
 		g_string_append_printf(msg,
 		                       "<img src=\"" PURPLE_STORED_IMAGE_PROTOCOL "%i\">",
 		                       imgid);
--- a/libpurple/protocols/mxit/markup.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/mxit/markup.c	Sat Feb 02 21:20:08 2013 +0100
@@ -60,7 +60,9 @@
 };
 
 
-#define		MXIT_VIBE_MSG_COLOR		"#9933FF"
+#define		MXIT_VIBE_MSG_COLOR			"#9933FF"
+#define		MXIT_FAREWELL_MSG_COLOR		"#949494"
+
 
 /* vibes */
 static const char*	vibes[] = {
@@ -594,7 +596,7 @@
 	}
 
 	/* we now have the emoticon, store it in the imagestore */
-	id = purple_imgstore_add_with_id( em_data, em_size, NULL );
+	id = purple_imgstore_new_with_id( em_data, em_size, NULL );
 
 	/* map the mxit emoticon id to purple image id */
 	intptr = g_malloc( sizeof( int ) );
@@ -1004,6 +1006,12 @@
 					break;
 		}
 	}
+
+	if ( msgflags & CP_MSG_FAREWELL ) {
+		/* this is a farewell message */
+		g_string_prepend( mx->msg, "<font color=\""MXIT_FAREWELL_MSG_COLOR"\"><i>" );
+		g_string_append( mx->msg, "</i></font>" );
+	}
 }
 
 
--- a/libpurple/protocols/mxit/multimx.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/mxit/multimx.c	Sat Feb 02 21:20:08 2013 +0100
@@ -514,7 +514,7 @@
 	}
 
 	/* Send Subscription Reject to MXit */
-	mxit_send_deny_sub(session, multimx->roomid);
+	mxit_send_deny_sub(session, multimx->roomid, NULL);
 
 	/* Remove from our list of rooms */
 	room_remove(session, multimx);
--- a/libpurple/protocols/mxit/mxit.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/mxit/mxit.c	Sat Feb 02 21:20:08 2013 +0100
@@ -427,7 +427,7 @@
 	char*					statusmsg2;
 
 	/* Handle mood changes */
-	if ( purple_status_type_get_primitive(purple_status_get_type( status ) ) == PURPLE_STATUS_MOOD ) {
+	if ( purple_status_type_get_primitive( purple_status_get_type( status ) ) == PURPLE_STATUS_MOOD ) {
 		const char* moodid = purple_status_get_attr_string( status, PURPLE_MOOD_NAME );
 		int mood;
 
@@ -669,7 +669,7 @@
 
 static PurplePluginProtocolInfo proto_info = {
 	sizeof( PurplePluginProtocolInfo ),		/* struct_size */
-	OPT_PROTO_REGISTER_NOSCREENNAME | OPT_PROTO_UNIQUE_CHATNAME | OPT_PROTO_IM_IMAGE | OPT_PROTO_INVITE_MESSAGE,			/* options */
+	OPT_PROTO_REGISTER_NOSCREENNAME | OPT_PROTO_UNIQUE_CHATNAME | OPT_PROTO_IM_IMAGE | OPT_PROTO_INVITE_MESSAGE | OPT_PROTO_AUTHORIZATION_DENIED_MESSAGE,	/* options */
 	NULL,					/* user_splits */
 	NULL,					/* protocol_options */
 	{						/* icon_spec */
--- a/libpurple/protocols/mxit/profile.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/mxit/profile.c	Sat Feb 02 21:20:08 2013 +0100
@@ -35,6 +35,40 @@
 
 
 /*------------------------------------------------------------------------
+ * Return the MXit Relationship status as a string.
+ *
+ * @param id		The Relationship status value (see profile.h)
+ * @return			The relationship status as a text string.
+ */
+const char* mxit_relationship_to_name( short id )
+{
+	switch ( id ) {
+		case MXIT_RELATIONSHIP_UNKNOWN :
+			return _( "Unknown" );
+		case MXIT_RELATIONSHIP_DONTSAY :
+			return _( "Don't want to say" );
+		case MXIT_RELATIONSHIP_SINGLE :
+			return _( "Single" );
+		case MXIT_RELATIONSHIP_INVOLVED :
+			return _( "In a relationship" );
+		case MXIT_RELATIONSHIP_ENGAGED :
+			return _( "Engaged" );
+		case MXIT_RELATIONSHIP_MARRIED :
+			return _( "Married" );
+		case MXIT_RELATIONSHIP_COMPLICATED :
+			return _( "It's complicated" );
+		case MXIT_RELATIONSHIP_WIDOWED :
+			return _( "Widowed" );
+		case MXIT_RELATIONSHIP_SEPARATED :
+			return _( "Separated" );
+		case MXIT_RELATIONSHIP_DIVORCED :
+			return _( "Divorced" );
+		default :
+			return "";
+	}
+}
+
+/*------------------------------------------------------------------------
  * Returns true if it is a valid date.
  *
  * @param bday		Date-of-Birth string (YYYY-MM-DD)
@@ -130,7 +164,7 @@
 	age = now.tm_year - bdate.tm_year;
 	if ( now.tm_mon < bdate.tm_mon )		/* is before month of birth */
 		age--;
-	else if ( (now.tm_mon == bdate.tm_mon ) && ( now.tm_mday < bdate.tm_mday ) )	/* before birthday in current month */
+	else if ( ( now.tm_mon == bdate.tm_mon ) && ( now.tm_mday < bdate.tm_mday ) )	/* before birthday in current month */
 		age--;
 
 	return age;
@@ -195,6 +229,8 @@
 	if ( *profile->whereami )
 		purple_notify_user_info_add_pair_plaintext( info, _( "Where I Live" ), profile->whereami );
 
+	purple_notify_user_info_add_pair_plaintext( info, _( "Relationship Status" ), mxit_relationship_to_name( profile->relationship ) );
+
 	purple_notify_user_info_add_section_break( info );
 
 	if ( contact ) {
@@ -236,7 +272,7 @@
 				img_text = g_strdup_printf( "<img src='" PURPLE_STORED_IMAGE_PROTOCOL "%d'>",
 				                            contact->imgid );
 				purple_notify_user_info_add_pair_html( info, _( "Photo" ), img_text );
-				g_free(img_text);
+				g_free( img_text );
 			}
 
 			if ( contact->statusMsg ) {
--- a/libpurple/protocols/mxit/profile.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/mxit/profile.h	Sat Feb 02 21:20:08 2013 +0100
@@ -29,6 +29,18 @@
 #include	<glib.h>
 
 
+/* MXit relationship status types */
+#define MXIT_RELATIONSHIP_UNKNOWN		0
+#define MXIT_RELATIONSHIP_DONTSAY		1
+#define MXIT_RELATIONSHIP_SINGLE		2
+#define MXIT_RELATIONSHIP_INVOLVED		3
+#define MXIT_RELATIONSHIP_ENGAGED		4
+#define MXIT_RELATIONSHIP_MARRIED		5
+#define MXIT_RELATIONSHIP_COMPLICATED	6
+#define MXIT_RELATIONSHIP_WIDOWED		7
+#define MXIT_RELATIONSHIP_SEPARATED		8
+#define MXIT_RELATIONSHIP_DIVORCED		9
+
 struct MXitProfile {
 	/* required */
 	char		loginname[64];						/* name user uses to log into MXit with (aka 'mxitid') */
@@ -47,6 +59,7 @@
 	char		regcountry[3];						/* user's registered country code */
 	char		whereami[51];						/* where am I / where I live */
 	char		aboutme[513];						/* about me */
+	int			relationship;						/* relationship status */
 
 	int			flags;								/* user's profile flags */
 	gint64		lastonline;							/* user's last-online timestamp */
@@ -55,6 +68,7 @@
 struct MXitSession;
 void mxit_show_profile( struct MXitSession* session, const char* username, struct MXitProfile* profile );
 void mxit_show_search_results( struct MXitSession* session, int searchType, int maxResults, GList* entries );
+const char* mxit_relationship_to_name( short id );
 
 gboolean validateDate( const char* bday );
 
--- a/libpurple/protocols/mxit/protocol.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/mxit/protocol.c	Sat Feb 02 21:20:08 2013 +0100
@@ -459,7 +459,7 @@
 	packet->headerlen = 0;
 
 	/* create generic packet header */
-	hlen = snprintf( header, sizeof( header ), "id=%s%c", purple_account_get_username( session->acc), CP_REC_TERM );			/* client msisdn */
+	hlen = snprintf( header, sizeof( header ), "id=%s%c", purple_account_get_username( session->acc ), CP_REC_TERM );			/* client msisdn */
 
 	if ( session->http ) {
 		/* http connection only */
@@ -1065,8 +1065,9 @@
  *
  *  @param session		The MXit session object
  *  @param username		The username of the contact being denied
+ *  @param reason		The message describing the reason for the rejection (can be NULL).
  */
-void mxit_send_deny_sub( struct MXitSession* session, const char* username )
+void mxit_send_deny_sub( struct MXitSession* session, const char* username, const char* reason )
 {
 	char		data[CP_MAX_PACKET];
 	int			datalen;
@@ -1077,6 +1078,10 @@
 								username
 	);
 
+	/* append reason (if one is set) */
+	if ( reason )
+		datalen += sprintf( data + datalen, "%c%s", CP_FLD_TERM, reason );
+
 	/* queue packet for transmission */
 	mxit_queue_packet( session, data, datalen, CP_CMD_DENY );
 }
@@ -1136,7 +1141,7 @@
  *  @param id			The identifier of the event (received in message)
  *  @param event		Identified the type of event
  */
-void mxit_send_msgevent( struct MXitSession* session, const char* to, const char* id, int event)
+void mxit_send_msgevent( struct MXitSession* session, const char* to, const char* id, int event )
 {
 	char		data[CP_MAX_PACKET];
 	int			datalen;
@@ -1451,7 +1456,7 @@
 	const char*		statusmsg;
 	const char*		profilelist[] = { CP_PROFILE_BIRTHDATE, CP_PROFILE_GENDER, CP_PROFILE_FULLNAME,
 									CP_PROFILE_TITLE, CP_PROFILE_FIRSTNAME, CP_PROFILE_LASTNAME, CP_PROFILE_EMAIL,
-									CP_PROFILE_MOBILENR, CP_PROFILE_WHEREAMI, CP_PROFILE_ABOUTME, CP_PROFILE_FLAGS };
+									CP_PROFILE_MOBILENR, CP_PROFILE_WHEREAMI, CP_PROFILE_ABOUTME, CP_PROFILE_RELATIONSHIP, CP_PROFILE_FLAGS };
 
 	purple_account_set_int( session->acc, MXIT_CONFIG_STATE, MXIT_STATE_LOGIN );
 
@@ -1878,6 +1883,10 @@
 			/* about me */
 			g_strlcpy( profile->aboutme, fvalue, sizeof( profile->aboutme ) );
 		}
+		else if ( strcmp( CP_PROFILE_RELATIONSHIP, fname ) == 0) {
+			/* relatinship status */
+			profile->relationship = strtol( fvalue, NULL, 10 );
+		}
 		else {
 			/* invalid profile attribute */
 			purple_debug_error( MXIT_PLUGIN_ID, "Invalid profile attribute received '%s' \n", fname );
@@ -2031,6 +2040,47 @@
 	g_list_foreach( entries, (GFunc)g_free, NULL );
 }
 
+/*------------------------------------------------------------------------
+ * Process a received message event packet.
+ *
+ *  @param session		The MXit session object
+ *  @param records		The packet's data records
+ *  @param rcount		The number of data records
+ */
+static void mxit_parse_cmd_msgevent( struct MXitSession* session, struct record** records, int rcount )
+{
+	int event;
+
+	/*
+	 * contactAddress \1 dateTime \1 id \1 event 
+	 */
+
+	/* strip off dummy domain */
+	mxit_strip_domain( records[0]->fields[0]->data );
+
+	event = atoi( records[0]->fields[3]->data );
+
+	switch ( event ) {
+		case CP_MSGEVENT_TYPING :							/* user is typing */
+		case CP_MSGEVENT_ANGRY :							/* user is typing angrily */
+			serv_got_typing( session->con, records[0]->fields[0]->data, 0, PURPLE_TYPING );
+			break;
+
+		case CP_MSGEVENT_STOPPED :							/* user has stopped typing */
+			serv_got_typing_stopped( session->con, records[0]->fields[0]->data );
+			break;
+
+		case CP_MSGEVENT_ERASING :							/* user is erasing text */
+		case CP_MSGEVENT_DELIVERED :						/* message was delivered */
+		case CP_MSGEVENT_DISPLAYED :						/* message was viewed */
+			/* these are currently not supported by libPurple */
+			break;
+
+		default:
+			purple_debug_error( MXIT_PLUGIN_ID, "Unknown message event received (%i)\n", event );
+	}
+}
+
 
 /*------------------------------------------------------------------------
  * Return the length of a multimedia chunk
@@ -2137,7 +2187,7 @@
 					contact = get_mxit_invite_contact( session, chunk.mxitid );
 					if ( contact ) {
 						/* this is an invite (add image to the internal image store) */
-						contact->imgid = purple_imgstore_add_with_id( g_memdup( chunk.data, chunk.length ), chunk.length, NULL );
+						contact->imgid = purple_imgstore_new_with_id( g_memdup( chunk.data, chunk.length ), chunk.length, NULL );
 						/* show the profile */
 						mxit_show_profile( session, chunk.mxitid, contact->profile );
 					}
@@ -2310,6 +2360,11 @@
 				mxit_parse_cmd_suggestcontacts( session, &packet->records[2], packet->rcount - 2 );
 				break;
 
+		case CP_CMD_GOT_MSGEVENT :
+				/* received message event */
+				mxit_parse_cmd_msgevent( session, &packet->records[2], packet->rcount - 2 );
+				break;
+
 		case CP_CMD_MOOD :
 				/* mood update */
 		case CP_CMD_UPDATE :
--- a/libpurple/protocols/mxit/protocol.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/mxit/protocol.h	Sat Feb 02 21:20:08 2013 +0100
@@ -77,9 +77,12 @@
 #define		MXIT_CF_VOICE			0x1000000
 #define		MXIT_CF_VIDEO			0x2000000
 #define		MXIT_CF_TOUCHSCREEN		0x4000000
+#define		MXIT_CF_SVC_CONNECTION	0x8000000
+#define		MXIT_CF_MXML			0x10000000
+#define		MXIT_CF_TYPING_NOTIFY	0x20000000
 
 /* Client features supported by this implementation */
-#define		MXIT_CP_FEATURES		( MXIT_CF_FILE_TRANSFER | MXIT_CF_FILE_ACCESS | MXIT_CF_AUDIO | MXIT_CF_MARKUP | MXIT_CF_EXT_MARKUP | MXIT_CF_NO_GATEWAYS | MXIT_CF_IMAGES | MXIT_CF_COMMANDS | MXIT_CF_VIBES | MXIT_CF_MIDP2 )
+#define		MXIT_CP_FEATURES		( MXIT_CF_FILE_TRANSFER | MXIT_CF_FILE_ACCESS | MXIT_CF_AUDIO | MXIT_CF_MARKUP | MXIT_CF_EXT_MARKUP | MXIT_CF_NO_GATEWAYS | MXIT_CF_IMAGES | MXIT_CF_COMMANDS | MXIT_CF_VIBES | MXIT_CF_MIDP2 | MXIT_CF_TYPING_NOTIFY )
 
 
 #define		MXIT_PING_INTERVAL		( 5 * 60 )				/* ping the server after X seconds of being idle (5 minutes) */
@@ -132,6 +135,7 @@
 #define		CP_CMD_SPLASHCLICK		0x001F					/* (31) splash-screen clickthrough */
 #define		CP_CMD_STATUS			0x0020					/* (32) set shown presence & status */
 #define		CP_CMD_MSGEVENT			0x0023					/* (35) Raise message event */
+#define		CP_CMD_GOT_MSGEVENT		0x0024					/* (36) Get message event */
 #define		CP_CMD_MOOD				0x0029					/* (41) set mood */
 #define		CP_CMD_KICK				0x002B					/* (43) login kick */
 #define		CP_CMD_GRPCHAT_CREATE	0x002C					/* (44) create new groupchat */
@@ -161,6 +165,7 @@
 #define		CP_MSG_RPLY_TL_ENCRYPT	0x0080					/* reply should be transport encrypted */
 #define		CP_MSG_MARKUP			0x0200					/* message may contain markup */
 #define		CP_MSG_EMOTICON			0x0400					/* message may contain custom emoticons */
+#define		CP_MSG_FAREWELL			0x0800					/* this is a farewell message */
 
 /* redirect types */
 #define		CP_REDIRECT_PERMANENT	1						/* permanent redirect */
@@ -178,6 +183,10 @@
 /* message event types */
 #define		CP_MSGEVENT_DELIVERED	0x02					/* message was delivered */
 #define		CP_MSGEVENT_DISPLAYED	0x04					/* message was viewed */
+#define		CP_MSGEVENT_TYPING		0x10					/* user is typing */
+#define		CP_MSGEVENT_STOPPED		0x20					/* user has stopped typing */
+#define		CP_MSGEVENT_ANGRY		0x40					/* user is typing angrily */
+#define		CP_MSGEVENT_ERASING		0x80					/* user is erasing text */
 
 /* extended profile attribute fields */
 #define		CP_PROFILE_BIRTHDATE	"birthdate"				/* Birthdate (String - ISO 8601 format) */
@@ -198,9 +207,11 @@
 #define		CP_PROFILE_LASTSEEN		"lastseen"				/* Last-Online timestamp */
 #define		CP_PROFILE_WHEREAMI		"whereami"				/* Where am I / Where I live */
 #define		CP_PROFILE_ABOUTME		"aboutme"				/* About me */
+#define		CP_PROFILE_RELATIONSHIP	"relationship"			/* Relationship Status */
 
 /* extended profile field types */
 #define		CP_PROFILE_TYPE_BOOL	0x02					/* boolean (0 or 1) */
+#define		CP_PROFILE_TYPE_SHORT	0x04					/* short (16-bit) */
 #define		CP_PROFILE_TYPE_INT		0x05					/* integer (32-bit) */
 #define		CP_PROFILE_TYPE_LONG	0x06					/* long (64-bit) */
 #define		CP_PROFILE_TYPE_UTF8	0x0A					/* UTF8 string */
@@ -315,7 +326,7 @@
 void mxit_send_invite( struct MXitSession* session, const char* username, gboolean mxitid, const char* alias, const char* groupname, const char* message );
 void mxit_send_remove( struct MXitSession* session, const char* username );
 void mxit_send_allow_sub( struct MXitSession* session, const char* username, const char* alias );
-void mxit_send_deny_sub( struct MXitSession* session, const char* username );
+void mxit_send_deny_sub( struct MXitSession* session, const char* username, const char* reason );
 void mxit_send_update_contact( struct MXitSession* session, const char* username, const char* alias, const char* groupname );
 void mxit_send_splashclick( struct MXitSession* session, const char* splashid );
 void mxit_send_msgevent( struct MXitSession* session, const char* to, const char* id, int event);
--- a/libpurple/protocols/mxit/roster.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/mxit/roster.c	Sat Feb 02 21:20:08 2013 +0100
@@ -583,7 +583,7 @@
  *
  *  @param user_data	Object associated with the invite
  */
-static void mxit_cb_buddy_auth( gpointer user_data )
+static void mxit_cb_buddy_auth( const char *message, gpointer user_data )
 {
 	struct contact_invite*	invite	= (struct contact_invite*) user_data;
 
@@ -612,14 +612,14 @@
  *
  *  @param user_data	Object associated with the invite
  */
-static void mxit_cb_buddy_deny( gpointer user_data )
+static void mxit_cb_buddy_deny( const char *message, gpointer user_data )
 {
 	struct contact_invite*	invite	= (struct contact_invite*) user_data;
 
 	purple_debug_info( MXIT_PLUGIN_ID, "mxit_cb_buddy_deny '%s'\n", invite->contact->username );
 
 	/* send a deny subscription packet to MXit */
-	mxit_send_deny_sub( invite->session, invite->contact->username );
+	mxit_send_deny_sub( invite->session, invite->contact->username, message );
 
 	/* remove the invite from our internal invites list */
 	invite->session->invites = g_list_remove( invite->session->invites, invite->contact );
--- a/libpurple/protocols/mxit/roster.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/mxit/roster.h	Sat Feb 02 21:20:08 2013 +0100
@@ -82,6 +82,7 @@
 /* MXit presence flags */
 #define		MXIT_PFLAG_VOICE			0x1
 #define		MXIT_PFLAG_VIDEO			0x2
+#define		MXIT_PFLAG_TYPING			0x4
 
 
 /* Subscription types */
--- a/libpurple/protocols/mxit/splashscreen.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/mxit/splashscreen.c	Sat Feb 02 21:20:08 2013 +0100
@@ -184,7 +184,7 @@
 		char buf[128];
 
 		/* Add splash-image to imagestore */
-		imgid = purple_imgstore_add_with_id(g_memdup(imgdata, imglen), imglen, NULL);
+		imgid = purple_imgstore_new_with_id(g_memdup(imgdata, imglen), imglen, NULL);
 
 		/* Generate and display message */
 		g_snprintf(buf, sizeof(buf),
--- a/libpurple/protocols/myspace/message.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/myspace/message.c	Sat Feb 02 21:20:08 2013 +0100
@@ -129,7 +129,7 @@
  *
  * @param first_key The first argument (a key), or NULL to take all arguments
  *    from argp.
- * @param argp A va_list of variadic arguments, already started with va_start(). Will be va_end()'d.
+ * @param argp A va_list of variadic arguments, already started with va_start().
  * @return New MsimMessage *, must be freed with msim_msg_free().
  *
  * For internal use - users probably want msim_msg_new() or msim_send().
@@ -211,7 +211,6 @@
 				break;
 		}
 	} while(key);
-	va_end(argp);
 
 	return msg;
 }
@@ -227,14 +226,16 @@
 MsimMessage *
 msim_msg_new(gchar *first_key, ...)
 {
+	MsimMessage *ret = NULL;
 	va_list argp;
 
 	if (first_key) {
-	va_start(argp, first_key);
-		return msim_msg_new_v(first_key, argp);
-	} else {
-		return NULL;
+		va_start(argp, first_key);
+		ret = msim_msg_new_v(first_key, argp);
+		va_end(argp);
 	}
+
+	return ret;
 }
 
 /**
@@ -960,6 +961,7 @@
 
 	va_start(argp, session);
 	msg = msim_msg_new_v(NULL, argp);
+	va_end(argp);
 
 	/* Actually send the message. */
 	success = msim_msg_send(session, msg);
--- a/libpurple/protocols/myspace/myspace.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/myspace/myspace.c	Sat Feb 02 21:20:08 2013 +0100
@@ -3577,7 +3577,10 @@
 
 	gc = purple_account_get_connection(account);
 	session = purple_connection_get_protocol_data(gc);
-	g_return_val_if_fail(session != NULL, FALSE);
+	if (session == NULL) {
+		g_free(cid_str);
+		return FALSE;
+	}
 
 	/* Lookup userid to username. TODO: push this down, to IM sending/contact
 	 * adding functions. */
@@ -3595,6 +3598,7 @@
 		return TRUE;
 	}
 
+	g_free(cid_str);
 	return FALSE;
 }
 
--- a/libpurple/protocols/oscar/authorization.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/oscar/authorization.c	Sat Feb 02 21:20:08 2013 +0100
@@ -67,7 +67,7 @@
 }
 
 static void
-oscar_auth_grant(gpointer cbdata)
+oscar_auth_grant(const char *message, gpointer cbdata)
 {
 	struct name_data *data = cbdata;
 	PurpleConnection *gc = data->gc;
@@ -79,8 +79,9 @@
 }
 
 static void
-oscar_auth_dontgrant(struct name_data *data, char *msg)
+oscar_auth_dontgrant(const char *msg, gpointer cbdata)
 {
+	struct name_data *data = cbdata;
 	PurpleConnection *gc = data->gc;
 	OscarData *od = purple_connection_get_protocol_data(gc);
 
@@ -89,18 +90,6 @@
 	oscar_free_name_data(data);
 }
 
-static void
-oscar_auth_dontgrant_msgprompt(gpointer cbdata)
-{
-	struct name_data *data = cbdata;
-	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);
-}
-
 void
 oscar_auth_sendrequest_menu(PurpleBlistNode *node, gpointer ignored)
 {
@@ -127,5 +116,5 @@
 
 	purple_account_request_authorization(account, data->name, NULL, data->nick,
 		reason, purple_find_buddy(account, data->name) != NULL,
-		oscar_auth_grant, oscar_auth_dontgrant_msgprompt, data);
+		oscar_auth_grant, oscar_auth_dontgrant, data);
 }
--- a/libpurple/protocols/oscar/family_feedbag.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/oscar/family_feedbag.c	Sat Feb 02 21:20:08 2013 +0100
@@ -605,9 +605,10 @@
 				if (od->ssi.pending) {
 					for (cur=od->ssi.pending; cur->next; cur=cur->next);
 					cur->next = new;
-				} else
+				} else {
 					od->ssi.pending = new;
-					aim_ssi_item_debug_append(debugstr, "Deleting item ", cur1);
+				}
+				aim_ssi_item_debug_append(debugstr, "Deleting item ", cur1);
 			}
 		}
 	}
@@ -626,9 +627,10 @@
 				if (od->ssi.pending) {
 					for (cur=od->ssi.pending; cur->next; cur=cur->next);
 					cur->next = new;
-				} else
+				} else {
 					od->ssi.pending = new;
-					aim_ssi_item_debug_append(debugstr, "Adding item ", cur1);
+				}
+				aim_ssi_item_debug_append(debugstr, "Adding item ", cur1);
 			}
 		}
 	}
@@ -648,20 +650,23 @@
 				if (od->ssi.pending) {
 					for (cur=od->ssi.pending; cur->next; cur=cur->next);
 					cur->next = new;
-				} else
+				} else {
 					od->ssi.pending = new;
-					aim_ssi_item_debug_append(debugstr, "Modifying item ", cur1);
+				}
+				aim_ssi_item_debug_append(debugstr, "Modifying item ", cur1);
 			}
 		}
 	}
 	if (debugstr->len > 0) {
 		purple_debug_info("oscar", "%s", debugstr->str);
 		if (purple_debug_is_verbose()) {
+			PurpleAccount *account = purple_connection_get_account(od->gc);
 			g_string_truncate(debugstr, 0);
-			for (cur1 = od->ssi.local.data; cur1; cur1 = cur1->next)
+			for (cur1 = od->ssi.local.data; cur1; cur1 = cur1->next) {
 				aim_ssi_item_debug_append(debugstr, "\t", cur1);
+			}
 			purple_debug_misc("oscar", "Dumping item list of account %s:\n%s",
-				purple_account_get_username(purple_connection_get_account(od->gc)), debugstr->str);
+					purple_account_get_username(account), debugstr->str);
 		}
 	}
 	g_string_free(debugstr, TRUE);
--- a/libpurple/protocols/oscar/libaim.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/oscar/libaim.c	Sat Feb 02 21:20:08 2013 +0100
@@ -30,7 +30,7 @@
 static PurplePluginProtocolInfo prpl_info =
 {
 	sizeof(PurplePluginProtocolInfo),       /* struct_size */
-	OPT_PROTO_MAIL_CHECK | OPT_PROTO_IM_IMAGE | OPT_PROTO_INVITE_MESSAGE,
+	OPT_PROTO_MAIL_CHECK | OPT_PROTO_IM_IMAGE | OPT_PROTO_INVITE_MESSAGE | OPT_PROTO_AUTHORIZATION_DENIED_MESSAGE,
 	NULL,					/* user_splits */
 	NULL,					/* protocol_options */
 	{"gif,jpeg,bmp,ico", 0, 0, 64, 64, 7168, PURPLE_ICON_SCALE_SEND | PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */
--- a/libpurple/protocols/oscar/libicq.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/oscar/libicq.c	Sat Feb 02 21:20:08 2013 +0100
@@ -39,7 +39,7 @@
 static PurplePluginProtocolInfo prpl_info =
 {
 	sizeof(PurplePluginProtocolInfo),       /* struct_size */
-	OPT_PROTO_MAIL_CHECK | OPT_PROTO_IM_IMAGE | OPT_PROTO_INVITE_MESSAGE,
+	OPT_PROTO_MAIL_CHECK | OPT_PROTO_IM_IMAGE | OPT_PROTO_INVITE_MESSAGE | OPT_PROTO_AUTHORIZATION_DENIED_MESSAGE,
 	NULL,					/* user_splits */
 	NULL,					/* protocol_options */
 	{"gif,jpeg,bmp,ico", 0, 0, 64, 64, 7168, PURPLE_ICON_SCALE_SEND | PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */
--- a/libpurple/protocols/oscar/odc.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/oscar/odc.c	Sat Feb 02 21:20:08 2013 +0100
@@ -356,7 +356,7 @@
 
 			if ((embedded_data != NULL) && (embedded_data->size == size))
 			{
-				imgid = purple_imgstore_add_with_id(g_memdup(embedded_data->data, size), size, src);
+				imgid = purple_imgstore_new_with_id(g_memdup(embedded_data->data, size), size, src);
 
 				/* Record the image number */
 				images = g_slist_append(images, GINT_TO_POINTER(imgid));
--- a/libpurple/protocols/oscar/oscar.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/oscar/oscar.c	Sat Feb 02 21:20:08 2013 +0100
@@ -633,15 +633,6 @@
 	return subtype1 - subtype2;
 }
 
-#if !GLIB_CHECK_VERSION(2,14,0)
-static void hash_table_get_list_of_keys(gpointer key, gpointer value, gpointer user_data)
-{
-	GList **handlers = (GList **)user_data;
-
-	*handlers = g_list_prepend(*handlers, key);
-}
-#endif /* GLIB < 2.14.0 */
-
 void
 oscar_login(PurpleAccount *account)
 {
@@ -711,12 +702,7 @@
 	oscar_data_addhandler(od, SNAC_FAMILY_USERLOOKUP, 0x0003, purple_parse_searchreply, 0);
 
 	g_string_append(msg, "Registered handlers: ");
-#if GLIB_CHECK_VERSION(2,14,0)
 	handlers = g_hash_table_get_keys(od->handlerlist);
-#else
-	handlers = NULL;
-	g_hash_table_foreach(od->handlerlist, hash_table_get_list_of_keys, &handlers);
-#endif /* GLIB < 2.14.0 */
 	sorted_handlers = g_list_sort(g_list_copy(handlers), compare_handlers);
 	for (cur = sorted_handlers; cur; cur = cur->next) {
 		guint x = GPOINTER_TO_UINT(cur->data);
@@ -2317,6 +2303,7 @@
 	va_list ap;
 	guint16 chan, reason;
 	char *who;
+	int ret = 1;
 
 	va_start(ap, fr);
 	chan = (guint16)va_arg(ap, unsigned int);
@@ -2325,7 +2312,7 @@
 
 	if (chan == 0x0002) { /* File transfer declined */
 		guchar *cookie = va_arg(ap, guchar *);
-		return purple_parse_clientauto_ch2(od, who, reason, cookie);
+		ret = purple_parse_clientauto_ch2(od, who, reason, cookie);
 	} else if (chan == 0x0004) { /* ICQ message */
 		guint32 state = 0;
 		char *msg = NULL;
@@ -2333,12 +2320,12 @@
 			state = va_arg(ap, guint32);
 			msg = va_arg(ap, char *);
 		}
-		return purple_parse_clientauto_ch4(od, who, reason, state, msg);
+		ret = purple_parse_clientauto_ch4(od, who, reason, state, msg);
 	}
 
 	va_end(ap);
 
-	return 1;
+	return ret;
 }
 
 static int purple_parse_genericerr(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
--- a/libpurple/protocols/sametime/sametime.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/sametime/sametime.c	Sat Feb 02 21:20:08 2013 +0100
@@ -2780,7 +2780,7 @@
       cid = make_cid(cid);
 
       /* add image to the purple image store */
-      img = purple_imgstore_add_with_id(d_dat, d_len, cid);
+      img = purple_imgstore_new_with_id(d_dat, d_len, cid);
 
       /* map the cid to the image store identifier */
       g_hash_table_insert(img_by_cid, cid, GINT_TO_POINTER(img));
--- a/libpurple/protocols/silc/ops.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/silc/ops.c	Sat Feb 02 21:20:08 2013 +0100
@@ -207,7 +207,7 @@
 		if (channel && !convo)
 			goto out;
 
-		imgid = purple_imgstore_add_with_id(g_memdup(data, data_len), data_len, "");
+		imgid = purple_imgstore_new_with_id(g_memdup(data, data_len), data_len, "");
 		if (imgid) {
 			cflags |= PURPLE_MESSAGE_IMAGES | PURPLE_MESSAGE_RECV;
 			g_snprintf(tmp, sizeof(tmp),
--- a/libpurple/protocols/silc/util.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/silc/util.c	Sat Feb 02 21:20:08 2013 +0100
@@ -309,6 +309,13 @@
 	if (fd != -1)
 		close(fd);
 
+#ifdef _WIN32
+	/* on win32, we calloc pw so pass it to free
+	 * (see the getpwuid code below)
+	 */
+	free(pw);
+#endif
+
 	return TRUE;
 }
 
--- a/libpurple/protocols/yahoo/libyahoo.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/yahoo/libyahoo.c	Sat Feb 02 21:20:08 2013 +0100
@@ -195,7 +195,7 @@
 static PurplePluginProtocolInfo prpl_info =
 {
 	sizeof(PurplePluginProtocolInfo),       /* struct_size */
-	OPT_PROTO_MAIL_CHECK | OPT_PROTO_CHAT_TOPIC,
+	OPT_PROTO_MAIL_CHECK | OPT_PROTO_CHAT_TOPIC | OPT_PROTO_AUTHORIZATION_DENIED_MESSAGE,
 	NULL, /* user_splits */
 	NULL, /* protocol_options */
 	{"png,gif,jpeg", 96, 96, 96, 96, 0, PURPLE_ICON_SCALE_SEND},
--- a/libpurple/protocols/yahoo/libyahoojp.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/yahoo/libyahoojp.c	Sat Feb 02 21:20:08 2013 +0100
@@ -91,7 +91,7 @@
 static PurplePluginProtocolInfo prpl_info =
 {
 	sizeof(PurplePluginProtocolInfo),       /* struct_size */
-	OPT_PROTO_MAIL_CHECK | OPT_PROTO_CHAT_TOPIC,
+	OPT_PROTO_MAIL_CHECK | OPT_PROTO_CHAT_TOPIC | OPT_PROTO_AUTHORIZATION_DENIED_MESSAGE,
 	NULL, /* user_splits */
 	NULL, /* protocol_options */
 	{"png,gif,jpeg", 96, 96, 96, 96, 0, PURPLE_ICON_SCALE_SEND},
--- a/libpurple/protocols/yahoo/libymsg.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/yahoo/libymsg.c	Sat Feb 02 21:20:08 2013 +0100
@@ -1197,7 +1197,7 @@
 };
 
 static void
-yahoo_buddy_add_authorize_cb(gpointer data)
+yahoo_buddy_add_authorize_cb(const char *message, gpointer data)
 {
 	struct yahoo_add_request *add_req = data;
 	struct yahoo_packet *pkt;
@@ -1230,7 +1230,7 @@
 }
 
 static void
-yahoo_buddy_add_deny_cb(struct yahoo_add_request *add_req, const char *msg)
+yahoo_buddy_add_deny_cb(const char *msg, struct yahoo_add_request *add_req)
 {
 	YahooData *yd = purple_connection_get_protocol_data(add_req->gc);
 	struct yahoo_packet *pkt;
@@ -1274,23 +1274,6 @@
 	g_free(add_req);
 }
 
-static void
-yahoo_buddy_add_deny_noreason_cb(struct yahoo_add_request *add_req, const char*msg)
-{
-	yahoo_buddy_add_deny_cb(add_req, NULL);
-}
-
-static void
-yahoo_buddy_add_deny_reason_cb(gpointer data) {
-	struct yahoo_add_request *add_req = data;
-	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)
 {
 	char *notify_msg;
@@ -1453,7 +1436,7 @@
 					alias, dec_msg,
 					purple_find_buddy(account, add_req->who) != NULL,
 					yahoo_buddy_add_authorize_cb,
-					yahoo_buddy_add_deny_reason_cb,
+					yahoo_buddy_add_deny_cb,
 					add_req);
 			g_free(alias);
 			g_free(dec_msg);
@@ -1518,7 +1501,7 @@
 				NULL, dec_msg,
 				purple_find_buddy(account,add_req->who) != NULL,
 						yahoo_buddy_add_authorize_cb,
-						yahoo_buddy_add_deny_reason_cb, add_req);
+						yahoo_buddy_add_deny_cb, add_req);
 		g_free(dec_msg);
 	} else {
 		g_free(add_req->id);
@@ -2954,7 +2937,7 @@
 			msg = pair->value;
 			break;
 		case 232:
-			/* weird number (md5 hash?), like 8ebab9094156135f5dcbaccbeee662a5c5fd1420 */
+			/* SHA-1 hash of audible SWF file (eg: 4e8691499d9c0fb8374478ff9720f4a9ea4a4915) */
 			break;
 		}
 
@@ -2975,7 +2958,7 @@
 		return;
 	}
 	if (id) {
-		/* "http://us.dl1.yimg.com/download.yahoo.com/dl/aud/"+locale+"/"+id+".swf" */
+		/* "http://l.yimg.com/pu/dl/aud/"+locale+"/"+id+".swf" */
 		char **audible_locale = g_strsplit(id, ".", 0);
 		char *buf = g_strdup_printf(_("[ Audible %s/%s/%s.swf ] %s"), YAHOO_AUDIBLE_URL, audible_locale[1], id, msg);
 		g_strfreev(audible_locale);
--- a/libpurple/protocols/yahoo/libymsg.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/yahoo/libymsg.h	Sat Feb 02 21:20:08 2013 +0100
@@ -61,7 +61,7 @@
 #define YAHOOJP_ROOMLIST_URL "http://insider.msg.yahoo.co.jp/ycontent/"
 #define YAHOOJP_ROOMLIST_LOCALE "ja"
 
-#define YAHOO_AUDIBLE_URL "http://us.dl1.yimg.com/download.yahoo.com/dl/aud"
+#define YAHOO_AUDIBLE_URL "http://l.yimg.com/pu/dl/aud"
 
 #define WEBMESSENGER_URL "http://login.yahoo.com/config/login?.src=pg"
 
@@ -96,6 +96,7 @@
 #define YAHOOJP_CLIENT_VERSION "9.0.0.1727"
 
 #define YAHOO_CLIENT_USERAGENT "Mozilla/5.0"
+#define YAHOO_CLIENT_USERAGENT_ALIAS "Mozilla/4.0 (compatible; MSIE 5.5)"
 
 /* Index into attention types list. */
 #define YAHOO_BUZZ 0
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/yahoo/yahoo_filexfer.c	Sat Feb 02 21:20:08 2013 +0100
@@ -1420,6 +1420,7 @@
 		purple_debug_warning("yahoo","p2p-ft: Wrong HEAD/GET request from peer, disconnecting host\n");
 		purple_input_remove(xd->input_event);
 		purple_xfer_cancel_remote(xfer);
+		g_free(url_get);
 		g_free(url_head);
 		return;
 	}
--- a/libpurple/protocols/yahoo/yahoo_profile.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/yahoo/yahoo_profile.c	Sat Feb 02 21:20:08 2013 +0100
@@ -1046,7 +1046,7 @@
 		} else {
 			purple_debug_info("yahoo", "%s is %" G_GSIZE_FORMAT
 					" bytes\n", photo_url_text, len);
-			id = purple_imgstore_add_with_id(g_memdup(url_text, len), len, NULL);
+			id = purple_imgstore_new_with_id(g_memdup(url_text, len), len, NULL);
 
 			tmp = g_strdup_printf("<img id=\"" PURPLE_STORED_IMAGE_PROTOCOL "%d\"><br>",
 			                      id);
--- a/libpurple/protocols/zephyr/zephyr.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/protocols/zephyr/zephyr.c	Sat Feb 02 21:20:08 2013 +0100
@@ -1501,6 +1501,7 @@
 		}
 		fclose(f);
 	}
+	g_free(fname);
 }
 
 static void process_anyone(PurpleConnection *gc)
@@ -2166,11 +2167,15 @@
 		len = strlen(zsendstr);
 		result = write(zephyr->totzc[ZEPHYR_FD_WRITE], zsendstr, len);
 		if (result != len) {
+			g_free(tzc_sig);
+			g_free(tzc_body);
 			g_free(zsendstr);
 			g_free(html_buf2);
 			g_free(html_buf);
 			return errno;
 		}
+		g_free(tzc_sig);
+		g_free(tzc_body);
 		g_free(zsendstr);
 	} else if (use_zeph02(zephyr)) {
 		ZNotice_t notice;
@@ -2591,6 +2596,7 @@
 				      const char *cmd, char **args, char **error, void *data)
 {
 	char *recipient;
+	PurpleCmdRet ret;
 	PurpleConnection *gc = purple_conversation_get_connection(conv);
 	zephyr_account *zephyr = purple_connection_get_protocol_data(gc);;
 	if (!g_ascii_strcasecmp(args[0],"*"))
@@ -2598,13 +2604,17 @@
 	else
 		recipient = local_zephyr_normalize(zephyr,args[0]);
 
-	if (strlen(recipient) < 1)
+	if (strlen(recipient) < 1) {
+		g_free(recipient);
 		return PURPLE_CMD_RET_FAILED; /* a null recipient is a chat message, not an IM */
+	}
 
 	if (zephyr_send_message(zephyr,"MESSAGE","PERSONAL",recipient,args[1],zephyr_get_signature(),""))
-		return PURPLE_CMD_RET_OK;
+		ret = PURPLE_CMD_RET_OK;
 	else
-		return PURPLE_CMD_RET_FAILED;
+		ret = PURPLE_CMD_RET_FAILED;
+	g_free(recipient);
+	return ret;
 }
 
 static PurpleCmdRet zephyr_purple_cmd_zlocate(PurpleConversation *conv,
@@ -2808,10 +2818,12 @@
 		title = g_strdup_printf("Server subscriptions for %s", zephyr->username);
 
 		if (zephyr->port == 0) {
+			g_free(title);
 			purple_debug_error("zephyr", "error while retrieving port\n");
 			return;
 		}
 		if ((retval = ZRetrieveSubscriptions(zephyr->port,&nsubs)) != ZERR_NONE) {
+			g_free(title);
 			/* XXX better error handling */
 			purple_debug_error("zephyr", "error while retrieving subscriptions from server\n");
 			return;
@@ -2820,6 +2832,7 @@
 			one = 1;
 			if ((retval = ZGetSubscriptions(&subs,&one)) != ZERR_NONE) {
 				/* XXX better error handling */
+				g_free(title);
 				purple_debug_error("zephyr", "error while retrieving individual subscription\n");
 				return;
 			}
@@ -2828,6 +2841,8 @@
 					       subs.zsub_recipient);
 		}
 		purple_notify_formatted(gc, title, title, NULL,  subout->str, NULL, NULL);
+		g_free(title);
+		g_string_free(subout, TRUE);
 	} else {
 		/* XXX fix */
 		purple_notify_error(gc,"","tzc doesn't support this action",NULL);
--- a/libpurple/prpl.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/prpl.h	Sat Feb 02 21:20:08 2013 +0100
@@ -193,7 +193,19 @@
 	 * Indicates that this protocol supports sending a user-supplied message
 	 * along with an invitation.
 	 */
-	OPT_PROTO_INVITE_MESSAGE = 0x00000800
+	OPT_PROTO_INVITE_MESSAGE = 0x00000800,
+
+	/**
+	 * Indicates that this protocol supports sending a user-supplied message
+	 * along with an authorization acceptance.
+	 */
+	OPT_PROTO_AUTHORIZATION_GRANTED_MESSAGE = 0x00001000,
+
+	/**
+	 * Indicates that this protocol supports sending a user-supplied message
+	 * along with an authorization denial.
+	 */
+	OPT_PROTO_AUTHORIZATION_DENIED_MESSAGE = 0x00002000
 
 } PurpleProtocolOptions;
 
@@ -475,7 +487,7 @@
 	 * On the other hand, both of these are invalid for protocols with
 	 * number-based usernames, so function should return NULL in such case.
 	 *
-	 * @param account  The account, that username is related with. Can
+	 * @param account  The account the username is related to. Can
 	 *                 be NULL.
 	 * @param who      The username to convert.
 	 * @return         Normalized username, or NULL, if it's invalid.
--- a/libpurple/smiley.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/smiley.c	Sat Feb 02 21:20:08 2013 +0100
@@ -272,9 +272,8 @@
 		smiley_node = xmlnode_get_child(smileyset_node, XML_SMILEY_TAG);
 		for (; smiley_node != NULL;
 				smiley_node = xmlnode_get_next_twin(smiley_node)) {
-			PurpleSmiley *smiley;
 
-			smiley = parse_smiley(smiley_node);
+			parse_smiley(smiley_node);
 		}
 	}
 
@@ -608,7 +607,7 @@
 		return NULL;
 	}
 
-	stored_img = purple_imgstore_add(smiley_data, smiley_data_len, filename);
+	stored_img = purple_imgstore_new(smiley_data, smiley_data_len, filename);
 
 	g_free(filename);
 
--- a/libpurple/stringref.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/stringref.c	Sat Feb 02 21:20:08 2013 +0100
@@ -73,7 +73,9 @@
 	len = strlen(value);
 
 	newref = g_malloc(sizeof(PurpleStringref) + len);
-	g_strlcpy(newref->value, value, len);
+	/* g_strlcpy() takes the size of the buffer, including the NUL.
+	   strlen() returns the length of the string, without the NUL. */
+	g_strlcpy(newref->value, value, len + 1);
 	newref->ref = 1;
 
 	return newref;
--- a/libpurple/tests/check_libpurple.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/tests/check_libpurple.c	Sat Feb 02 21:20:08 2013 +0100
@@ -25,11 +25,7 @@
 	purple_check_input_add,
 	g_source_remove,
 	NULL, /* input_get_error */
-#if GLIB_CHECK_VERSION(2,14,0)
 	g_timeout_add_seconds,
-#else
-	NULL,
-#endif
 	NULL,
 	NULL,
 	NULL
--- a/libpurple/upnp.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/upnp.c	Sat Feb 02 21:20:08 2013 +0100
@@ -257,9 +257,12 @@
 	}
 
 	/* get the baseURL of the device */
+	baseURL = NULL;
 	if((baseURLNode = xmlnode_get_child(xmlRootNode, "URLBase")) != NULL) {
 		baseURL = xmlnode_get_data(baseURLNode);
-	} else {
+	}
+	/* fixes upnp-descriptions with empty urlbase-element */
+	if(baseURL == NULL){
 		baseURL = g_strdup(httpURL);
 	}
 
--- a/libpurple/util.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/util.c	Sat Feb 02 21:20:08 2013 +0100
@@ -32,6 +32,8 @@
 #include "prefs.h"
 #include "util.h"
 
+#include <json-glib/json-glib.h>
+
 struct _PurpleMenuAction
 {
 	char *label;
@@ -43,6 +45,8 @@
 static char *custom_user_dir = NULL;
 static char *user_dir = NULL;
 
+static JsonNode *escape_js_node = NULL;
+static JsonGenerator *escape_js_gen = NULL;
 
 PurpleMenuAction *
 purple_menu_action_new(const char *label, PurpleCallback callback, gpointer data,
@@ -124,8 +128,8 @@
 void
 purple_util_init(void)
 {
-	/* This does nothing right now.  It exists for symmetry with
-	 * purple_util_uninit() and forwards compatibility. */
+	escape_js_node = json_node_new(JSON_NODE_VALUE);
+	escape_js_gen = json_generator_new();
 }
 
 void
@@ -138,6 +142,12 @@
 
 	g_free(user_dir);
 	user_dir = NULL;
+
+	json_node_free(escape_js_node);
+	escape_js_node = NULL;
+
+	g_object_unref(escape_js_gen);
+	escape_js_gen = NULL;
 }
 
 /**************************************************************************
@@ -2990,6 +3000,15 @@
 		return FALSE;
 	}
 
+#ifndef _WIN32
+	/* Set file permissions */
+	if (fchmod(fileno(file), S_IRUSR | S_IWUSR) == -1)
+	{
+		purple_debug_error("util", "Error setting permissions of %s: %s\n",
+				filename_temp, g_strerror(errno));
+	}
+#endif
+
 	/* Write to file */
 	real_size = (size == -1) ? strlen(data) : (size_t) size;
 	byteswritten = fwrite(data, 1, real_size, file);
@@ -3069,15 +3088,6 @@
 		return FALSE;
 	}
 
-#ifndef _WIN32
-	/* Set file permissions */
-	if (chmod(filename_temp, S_IRUSR | S_IWUSR) == -1)
-	{
-		purple_debug_error("util", "Error setting permissions of file %s: %s\n",
-						 filename_temp, g_strerror(errno));
-	}
-#endif
-
 	/* Rename to the REAL name */
 	if (g_rename(filename_temp, filename_full) == -1)
 	{
@@ -3389,12 +3399,7 @@
 gboolean
 purple_strequal(const gchar *left, const gchar *right)
 {
-#if GLIB_CHECK_VERSION(2,16,0)
 	return (g_strcmp0(left, right) == 0);
-#else
-	return ((left == NULL && right == NULL) ||
-	        (left != NULL && right != NULL && strcmp(left, right) == 0));
-#endif
 }
 
 const char *
@@ -4694,23 +4699,14 @@
 
 gchar * purple_escape_js(const gchar *str)
 {
-	gchar *tmp, *esc;
-
-	esc = tmp = purple_utf8_try_convert(str);
-
-	esc = purple_strreplace(esc, "\\", "\\\\");
-	g_free(tmp); tmp = esc;
-
-	esc = purple_strreplace(esc, "'", "\\'");
-	g_free(tmp); tmp = esc;
-
-	esc = purple_strreplace(esc, "\n", "\\n");
-	g_free(tmp); tmp = esc;
-
-	esc = purple_strreplace(esc, "\r", "");
-	g_free(tmp); tmp = esc;
-
-	return esc;
+	gchar *escaped;
+
+	json_node_set_string(escape_js_node, str);
+	json_generator_set_root(escape_js_gen, escape_js_node);
+	escaped = json_generator_to_data(escape_js_gen, NULL);
+	json_node_set_boolean(escape_js_node, FALSE);
+
+	return escaped;
 }
 
 void purple_restore_default_signal_handlers(void)
--- a/libpurple/win32/global.mak	Sat Feb 02 18:29:35 2013 +0100
+++ b/libpurple/win32/global.mak	Sat Feb 02 21:20:08 2013 +0100
@@ -15,13 +15,15 @@
 GTK_TOP ?= $(WIN32_DEV_TOP)/gtk_2_0-2.14
 GTK_BIN ?= $(GTK_TOP)/bin
 BONJOUR_TOP ?= $(WIN32_DEV_TOP)/Bonjour_SDK
-LIBXML2_TOP ?= $(WIN32_DEV_TOP)/libxml2-2.7.4
-MEANWHILE_TOP ?= $(WIN32_DEV_TOP)/meanwhile-1.0.2_daa2
+LIBXML2_TOP ?= $(WIN32_DEV_TOP)/libxml2-2.9.0
+MEANWHILE_TOP ?= $(WIN32_DEV_TOP)/meanwhile-1.0.2_daa3
 NSS_TOP ?= $(WIN32_DEV_TOP)/nss-3.13.6-nspr-4.9.2
 PERL_LIB_TOP ?= $(WIN32_DEV_TOP)/perl-5.10.0
 SILC_TOOLKIT ?= $(WIN32_DEV_TOP)/silc-toolkit-1.1.10
 TCL_LIB_TOP ?= $(WIN32_DEV_TOP)/tcl-8.4.5
 GSTREAMER_TOP ?= $(WIN32_DEV_TOP)/gstreamer-0.10.13
+GCC_SSP_TOP ?= $(WIN32_DEV_TOP)/gcc-core-4.4.0-mingw32-dll
+CYRUS_SASL_TOP ?= $(WIN32_DEV_TOP)/cyrus-sasl-2.1.25
 
 # Where we installing this stuff to?
 PIDGIN_INSTALL_DIR := $(PIDGIN_TREE_TOP)/win32-install-dir
@@ -57,6 +59,10 @@
 
 GCCWARNINGS ?= -Waggregate-return -Wcast-align -Wdeclaration-after-statement -Werror-implicit-function-declaration -Wextra -Wno-sign-compare -Wno-unused-parameter -Winit-self -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wpointer-arith -Wundef
 
+CC_HARDENING_OPTIONS ?= -Wstack-protector -fwrapv -fno-strict-overflow -Wno-missing-field-initializers -Wformat-security -fstack-protector-all --param ssp-buffer-size=1
+LD_HARDENING_OPTIONS ?= -Wl,--dynamicbase -Wl,--nxcompat
+
+
 # parse the version number from the configure.ac file if it is newer
 #m4_define([purple_major_version], [2])
 #m4_define([purple_minor_version], [0])
@@ -84,17 +90,14 @@
 
 DEFINES += -DHAVE_CONFIG_H -DWIN32_LEAN_AND_MEAN
 
-# Use -g flag when building debug version of Pidgin (including plugins).
-# Use -fnative-struct instead of -mms-bitfields when using mingw 1.1
-# (gcc 2.95)
-CFLAGS += -O2 -Wall $(GCCWARNINGS) -pipe -mno-cygwin -mms-bitfields -g
+CFLAGS += -O2 -Wall $(GCCWARNINGS) $(CC_HARDENING_OPTIONS) -pipe -mms-bitfields -g
 
 # If not specified, dlls are built with the default base address of 0x10000000.
 # When loaded into a process address space a dll will be rebased if its base
 # address colides with the base address of an existing dll.  To avoid rebasing 
 # we do the following.  Rebasing can slow down the load time of dlls and it
 # also renders debug info useless.
-DLL_LD_FLAGS += -Wl,--enable-auto-image-base
+DLL_LD_FLAGS += -Wl,--enable-auto-image-base -Wl,--enable-auto-import $(LD_HARDENING_OPTIONS) -lssp
 
 # Build programs
 ifeq "$(origin CC)" "default"
@@ -106,6 +109,8 @@
 WINDRES ?= windres
 STRIP ?= strip
 INTLTOOL_MERGE ?= $(WIN32_DEV_TOP)/intltool_0.40.4-1_win32/bin/intltool-merge
+MONO_SIGNCODE ?= signcode
+GPG_SIGN ?= gpg
 
 PIDGIN_COMMON_RULES := $(PURPLE_TOP)/win32/rules.mak
 PIDGIN_COMMON_TARGETS := $(PURPLE_TOP)/win32/targets.mak
--- a/pidgin.spec.in	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin.spec.in	Sat Feb 02 21:20:08 2013 +0100
@@ -368,7 +368,7 @@
 %doc ChangeLog
 %doc NEWS
 %doc README
-%doc README.MTN
+%doc README.hg
 %doc doc/the_penguin.txt
 %doc %{_mandir}/man1/pidgin.*
 %doc %{_mandir}/man3*/*
--- a/pidgin/Makefile.mingw	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/Makefile.mingw	Sat Feb 02 21:20:08 2013 +0100
@@ -18,7 +18,7 @@
 
 WINAPP := -mwindows
 
-LDFLAGS := $(WINAPP)
+LDFLAGS := $(WINAPP) $(LD_HARDENING_OPTIONS) -Wl,--enable-auto-import -lssp
 
 ##
 ## INCLUDE PATHS
@@ -163,7 +163,7 @@
 	$(CC) -shared $(PIDGIN_OBJECTS) $(LIB_PATHS) $(PIDGIN_LIBS) $(DLL_LD_FLAGS) -Wl,--output-def,$(PIDGIN_TARGET).def,--out-implib,$(PIDGIN_TARGET).dll.a -o $(PIDGIN_TARGET).dll
 
 $(EXE_TARGET).exe: $(PIDGIN_CONFIG_H) $(PIDGIN_DLL).a $(EXE_OBJECTS) $(PIDGIN_TARGET).dll
-	$(CC) $(LDFLAGS) $(EXE_OBJECTS) -o $(EXE_TARGET).exe
+	$(CC) $(EXE_OBJECTS) $(LDFLAGS) -o $(EXE_TARGET).exe
 
 ##
 ## CLEAN RULES
--- a/pidgin/gtk3compat.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtk3compat.h	Sat Feb 02 21:20:08 2013 +0100
@@ -97,88 +97,6 @@
 		GTK_WIDGET_UNSET_FLAGS(x, GTK_REALIZED); \
 } while(0)
 
-#if !GTK_CHECK_VERSION(2,18,0)
-
-#define gtk_widget_get_state GTK_WIDGET_STATE
-#define gtk_widget_is_drawable GTK_WIDGET_DRAWABLE
-#define gtk_widget_get_visible GTK_WIDGET_VISIBLE
-#define gtk_widget_has_focus GTK_WIDGET_HAS_FOCUS
-#define gtk_widget_is_sensitive GTK_WIDGET_IS_SENSITIVE
-#define gtk_widget_get_has_window(x) !GTK_WIDGET_NO_WINDOW(x)
-#define gtk_widget_set_has_window(x,y) do { \
-	if (!y) \
-		GTK_WIDGET_SET_FLAGS(x, GTK_NO_WINDOW); \
-	else \
-		GTK_WIDGET_UNSET_FLAGS(x, GTK_NO_WINDOW); \
-} while(0)
-#define gtk_widget_get_allocation(x,y) *(y) = (x)->allocation
-#define gtk_widget_set_allocation(x,y) (x)->allocation = *(y)
-#define gtk_widget_set_window(x,y) ((x)->window = (y))
-#define gtk_widget_set_can_default(w,y) do { \
-	if (y) \
-		GTK_WIDGET_SET_FLAGS((w), GTK_CAN_DEFAULT); \
-	else \
-		GTK_WIDGET_UNSET_FLAGS((w), GTK_CAN_DEFAULT); \
-} while (0)
-#define gtk_widget_set_can_focus(x,y) do {\
-	if (y) \
-		GTK_WIDGET_SET_FLAGS(x, GTK_CAN_FOCUS); \
-	else \
-		GTK_WIDGET_UNSET_FLAGS(x, GTK_CAN_FOCUS); \
-} while(0)
-#define gtk_cell_renderer_set_padding(x,y,z) do { \
-	(x)->xpad = (y); \
-	(x)->ypad = (z); \
-} while (0)
-#define gtk_cell_renderer_get_padding(x,y,z) do { \
-	*(y) = (x)->xpad; \
-	*(z) = (x)->ypad; \
-} while (0)
-#define gtk_cell_renderer_get_alignment(x,y,z) do { \
-	*(y) = (x)->xalign; \
-	*(z) = (x)->yalign; \
-} while (0)
-
-#if !GTK_CHECK_VERSION(2,16,0)
-
-#define gtk_status_icon_set_tooltip_text gtk_status_icon_set_tooltip
-
-#if !GTK_CHECK_VERSION(2,14,0)
-
-#define gtk_widget_get_window(x) (x)->window
-#define gtk_widget_set_style(x,y) (x)->style = (y)
-#define gtk_selection_data_get_data(x) (x)->data
-#define gtk_selection_data_get_length(x) (x)->length
-#define gtk_selection_data_get_format(x) (x)->format
-#define gtk_selection_data_get_target(x) (x)->target
-#define gtk_dialog_get_content_area(x) GTK_DIALOG(x)->vbox
-#define gtk_dialog_get_action_area(x) GTK_DIALOG(x)->action_area
-#define gtk_adjustment_get_page_size(x) (x)->page_size
-#define gtk_adjustment_get_lower(x) (x)->lower
-#define gtk_adjustment_get_upper(x) (x)->upper
-#define gtk_font_selection_get_size_entry(x) (x)->size_entry
-#define gtk_font_selection_get_family_list(x) (x)->family_list
-#define gtk_font_selection_dialog_get_ok_button(x) (x)->ok_button
-#define gtk_font_selection_dialog_get_cancel_button(x) (x)->cancel_button
-#define gtk_color_selection_dialog_get_color_selection(x) (x)->colorsel
-#define gtk_menu_item_get_accel_path(x) (x)->accel_path
-
-#if !GTK_CHECK_VERSION(2,12,0)
-
-#ifdef GTK_TOOLTIPS_VAR
-#define gtk_widget_set_tooltip_text(w, t) gtk_tooltips_set_tip(GTK_TOOLTIPS_VAR, (w), (t), NULL)
-#else
-#define gtk_widget_set_tooltip_text(w, t) gtk_tooltips_set_tip(tooltips, (w), (t), NULL)
-#endif
-
-#endif /* 2.12.0 */
-
-#endif /* 2.14.0 */
-
-#endif /* 2.16.0 */
-
-#endif /* 2.18.0 */
-
 #endif /* 2.20.0 */
 
 #endif /* 2.22.0 */
--- a/pidgin/gtkaccount.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkaccount.c	Sat Feb 02 21:20:08 2013 +0100
@@ -119,6 +119,11 @@
 	GtkWidget *protocol_menu;
 	GtkWidget *password_box;
 	GtkWidget *username_entry;
+#if GTK_CHECK_VERSION(3,0,0)
+	GdkRGBA username_entry_hint_color;
+#else
+	GdkColor *username_entry_hint_color;
+#endif
 	GtkWidget *password_entry;
 	GtkWidget *alias_entry;
 	GtkWidget *remember_pass_check;
@@ -184,7 +189,7 @@
 	if (data != NULL)
 	{
 		if (len > 0)
-			dialog->icon_img = purple_imgstore_add(data, len, new_icon_path);
+			dialog->icon_img = purple_imgstore_new(data, len, new_icon_path);
 		else
 			g_free(data);
 	}
@@ -266,30 +271,6 @@
 	}
 }
 
-static gboolean
-username_focus_cb(GtkWidget *widget, GdkEventFocus *event, AccountPrefsDialog *dialog)
-{
-	GHashTable *table;
-	const char *label;
-
-	if (!dialog->prpl_info || ! PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(
-		dialog->prpl_info, get_account_text_table)) {
-		return FALSE;
-	}
-
-	table = dialog->prpl_info->get_account_text_table(NULL);
-	label = g_hash_table_lookup(table, "login_label");
-
-	if(!strcmp(gtk_entry_get_text(GTK_ENTRY(widget)), label)) {
-		gtk_entry_set_text(GTK_ENTRY(widget), "");
-		gtk_widget_modify_text(widget, GTK_STATE_NORMAL,NULL);
-	}
-
-	g_hash_table_destroy(table);
-
-	return FALSE;
-}
-
 static void
 username_changed_cb(GtkEntry *entry, AccountPrefsDialog *dialog)
 {
@@ -317,10 +298,38 @@
 	}
 }
 
+#if !GTK_CHECK_VERSION(3,2,0)
+static gboolean
+username_focus_cb(GtkWidget *widget, GdkEventFocus *event, AccountPrefsDialog *dialog)
+{
+	GHashTable *table;
+	const char *label;
+
+	if (!dialog->prpl_info || ! PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(
+		dialog->prpl_info, get_account_text_table)) {
+		return FALSE;
+	}
+
+	table = dialog->prpl_info->get_account_text_table(NULL);
+	label = g_hash_table_lookup(table, "login_label");
+
+	if(!strcmp(gtk_entry_get_text(GTK_ENTRY(widget)), label)) {
+		gtk_entry_set_text(GTK_ENTRY(widget), "");
+#if GTK_CHECK_VERSION(3,0,0)
+		gtk_widget_override_color(widget, GTK_STATE_NORMAL, NULL);
+#else
+		gtk_widget_modify_text(widget, GTK_STATE_NORMAL,NULL);
+#endif
+	}
+
+	g_hash_table_destroy(table);
+
+	return FALSE;
+}
+
 static gboolean
 username_nofocus_cb(GtkWidget *widget, GdkEventFocus *event, AccountPrefsDialog *dialog)
 {
-	GdkColor color = {0, 34952, 35466, 34181};
 	GHashTable *table = NULL;
 	const char *label = NULL;
 
@@ -336,7 +345,11 @@
 			gtk_entry_set_text(GTK_ENTRY(widget), label);
 			/* Make sure we can hit it again */
 			g_signal_handlers_unblock_by_func(widget, G_CALLBACK(username_changed_cb), dialog);
-			gtk_widget_modify_text(widget, GTK_STATE_NORMAL, &color);
+#if GTK_CHECK_VERSION(3,0,0)
+			gtk_widget_override_color(widget, GTK_STATE_NORMAL, &dialog->username_entry_hint_color);
+#else
+			gtk_widget_modify_text(widget, GTK_STATE_NORMAL, dialog->username_entry_hint_color);
+#endif
 		}
 
 		g_hash_table_destroy(table);
@@ -345,6 +358,84 @@
 	return FALSE;
 }
 
+static gboolean
+username_themechange_cb(GObject *widget, GdkEventFocus *event, AccountPrefsDialog *dialog)
+{
+	GHashTable *table;
+	const char *label, *text;
+	char *temp_text = NULL;
+#if GTK_CHECK_VERSION(3,0,0)
+	GtkStyleContext *context;
+	GtkBorder border;
+#else
+	GtkStyle *style;
+	const GtkBorder *border = NULL;
+#endif
+	gint xsize;
+
+	table = dialog->prpl_info->get_account_text_table(NULL);
+	label = g_hash_table_lookup(table, "login_label");
+	text = gtk_entry_get_text(GTK_ENTRY(widget));
+
+	g_signal_handlers_block_by_func(widget, G_CALLBACK(username_themechange_cb), dialog);
+	g_signal_handlers_block_by_func(widget, G_CALLBACK(username_changed_cb), dialog);
+	if (strcmp(text, label)) {
+		temp_text = g_strdup(text);
+		gtk_entry_set_text(GTK_ENTRY(widget), label);
+#if GTK_CHECK_VERSION(3,0,0)
+		gtk_widget_override_color(GTK_WIDGET(widget), GTK_STATE_NORMAL, NULL);
+#else
+		gtk_widget_modify_text(GTK_WIDGET(widget), GTK_STATE_NORMAL, NULL);
+#endif
+	}
+
+#if GTK_CHECK_VERSION(3,0,0)
+	context = gtk_widget_get_style_context(dialog->username_entry);
+	gtk_style_context_get_color(context, GTK_STATE_FLAG_INSENSITIVE,
+	                            &dialog->username_entry_hint_color);
+#else
+	style = gtk_rc_get_style(dialog->username_entry);
+	dialog->username_entry_hint_color = &(style->fg[GTK_STATE_INSENSITIVE]);
+#endif
+
+	pango_layout_get_pixel_size(gtk_entry_get_layout(GTK_ENTRY(widget)), &xsize, NULL);
+#if GTK_CHECK_VERSION(3,0,0)
+	gtk_style_context_get_margin(context, GTK_STATE_FLAG_NORMAL, &border);
+	xsize += border.left + border.right;
+	gtk_style_context_get_padding(context, GTK_STATE_FLAG_NORMAL, &border);
+	xsize += border.left + border.right;
+#else
+	xsize += 2 * style->xthickness;
+	gtk_style_get(style, GTK_TYPE_ENTRY, "inner-border", &border, NULL);
+	if (border)
+		xsize += border->left + border->right;
+	else
+		xsize += 4; /* 2 * default inner-border */
+#endif
+	gtk_widget_set_size_request(GTK_WIDGET(widget), xsize, -1);
+	if (temp_text) {
+		gtk_entry_set_text(GTK_ENTRY(widget), temp_text);
+		g_free(temp_text);
+#if GTK_CHECK_VERSION(3,0,0)
+		gtk_widget_override_color(GTK_WIDGET(widget), GTK_STATE_NORMAL, NULL);
+#else
+		gtk_widget_modify_text(GTK_WIDGET(widget), GTK_STATE_NORMAL, NULL);
+#endif
+	} else
+#if GTK_CHECK_VERSION(3,0,0)
+		gtk_widget_override_color(GTK_WIDGET(widget), GTK_STATE_NORMAL, &dialog->username_entry_hint_color);
+#else
+		gtk_widget_modify_text(GTK_WIDGET(widget), GTK_STATE_NORMAL, dialog->username_entry_hint_color);
+#endif
+
+	g_signal_handlers_unblock_by_func(widget, G_CALLBACK(username_themechange_cb), dialog);
+	g_signal_handlers_unblock_by_func(widget, G_CALLBACK(username_changed_cb), dialog);
+	g_hash_table_destroy(table);
+
+	return FALSE;
+}
+#endif
+
 static void
 register_button_cb(GtkWidget *checkbox, AccountPrefsDialog *dialog)
 {
@@ -354,8 +445,10 @@
 		(dialog->prpl_info->options & OPT_PROTO_REGISTER_NOSCREENNAME));
 	int register_noscreenname = (opt_noscreenname && register_checked);
 
+#if !GTK_CHECK_VERSION(3,2,0)
 	/* get rid of login_label in username field */
 	username_focus_cb(dialog->username_entry, NULL, dialog);
+#endif
 
 	if (register_noscreenname) {
 		gtk_entry_set_text(GTK_ENTRY(dialog->username_entry), "");
@@ -373,7 +466,9 @@
 				!= '\0');
 	}
 
+#if !GTK_CHECK_VERSION(3,2,0)
 	username_nofocus_cb(dialog->username_entry, NULL, dialog);
+#endif
 }
 
 static void
@@ -531,18 +626,24 @@
 
 	if (!username && dialog->prpl_info
 			&& PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(dialog->prpl_info, get_account_text_table)) {
-		GdkColor color = {0, 34952, 35466, 34181};
 		GHashTable *table;
 		const char *label;
 		table = dialog->prpl_info->get_account_text_table(NULL);
 		label = g_hash_table_lookup(table, "login_label");
 
+#if GTK_CHECK_VERSION(3,2,0)
+		gtk_entry_set_placeholder_text(GTK_ENTRY(dialog->username_entry), label);
+#else
 		gtk_entry_set_text(GTK_ENTRY(dialog->username_entry), label);
+		username_themechange_cb(G_OBJECT(dialog->username_entry), NULL, dialog);
+		g_signal_connect(G_OBJECT(dialog->username_entry), "style-set",
+				G_CALLBACK(username_themechange_cb), dialog);
 		g_signal_connect(G_OBJECT(dialog->username_entry), "focus-in-event",
 				G_CALLBACK(username_focus_cb), dialog);
 		g_signal_connect(G_OBJECT(dialog->username_entry), "focus-out-event",
 				G_CALLBACK(username_nofocus_cb), dialog);
-		gtk_widget_modify_text(dialog->username_entry, GTK_STATE_NORMAL, &color);
+#endif
+
 		g_hash_table_destroy(table);
 	}
 
@@ -617,10 +718,6 @@
 	/* Password */
 	dialog->password_entry = gtk_entry_new();
 	gtk_entry_set_visibility(GTK_ENTRY(dialog->password_entry), FALSE);
-#if !GTK_CHECK_VERSION(2,16,0)
-	if (gtk_entry_get_invisible_char(GTK_ENTRY(dialog->password_entry)) == '*')
-		gtk_entry_set_invisible_char(GTK_ENTRY(dialog->password_entry), PIDGIN_INVISIBLE_CHAR);
-#endif /* Less than GTK+ 2.16 */
 	dialog->password_box = add_pref_box(dialog, vbox, _("_Password:"),
 										  dialog->password_entry);
 
@@ -935,10 +1032,6 @@
 				else if (purple_account_option_string_get_masked(option))
 				{
 					gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
-#if !GTK_CHECK_VERSION(2,16,0)
-					if (gtk_entry_get_invisible_char(GTK_ENTRY(entry)) == '*')
-						gtk_entry_set_invisible_char(GTK_ENTRY(entry), PIDGIN_INVISIBLE_CHAR);
-#endif /* Less than GTK+ 2.16 */
 				}
 
 				if (str_value != NULL && str_hints)
@@ -1176,10 +1269,6 @@
 	/* Password */
 	dialog->proxy_pass_entry = gtk_entry_new();
 	gtk_entry_set_visibility(GTK_ENTRY(dialog->proxy_pass_entry), FALSE);
-#if !GTK_CHECK_VERSION(2,16,0)
-	if (gtk_entry_get_invisible_char(GTK_ENTRY(dialog->proxy_pass_entry)) == '*')
-		gtk_entry_set_invisible_char(GTK_ENTRY(dialog->proxy_pass_entry), PIDGIN_INVISIBLE_CHAR);
-#endif /* Less than GTK+ 2.16 */
 	add_pref_box(dialog, vbox2, _("Pa_ssword:"), dialog->proxy_pass_entry);
 
 	if (dialog->account != NULL &&
@@ -2583,18 +2672,93 @@
 }
 
 static void
-authorize_and_add_cb(struct auth_request *ar)
+authorize_and_add_cb(struct auth_request *ar, const char *message)
 {
-	ar->auth_cb(ar->data);
+	ar->auth_cb(message, ar->data);
 	if (ar->add_buddy_after_auth) {
 		purple_blist_request_add_buddy(ar->account, ar->username, NULL, ar->alias);
 	}
 }
 
 static void
-deny_no_add_cb(struct auth_request *ar)
+authorize_noreason_cb(struct auth_request *ar)
+{
+	authorize_and_add_cb(ar, NULL);
+}
+
+static void
+authorize_reason_cb(struct auth_request *ar)
 {
-	ar->deny_cb(ar->data);
+	const char *protocol_id;
+	PurplePlugin *plugin;
+	PurplePluginProtocolInfo *prpl_info = NULL;
+
+	protocol_id = purple_account_get_protocol_id(ar->account);
+	if ((plugin = purple_find_prpl(protocol_id)) != NULL)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
+
+	if (prpl_info && (prpl_info->options & OPT_PROTO_AUTHORIZATION_GRANTED_MESSAGE)) {
+		/* Duplicate information because ar is freed by closing minidialog */
+		struct auth_request *aa = g_new0(struct auth_request, 1);
+		aa->auth_cb = ar->auth_cb;
+		aa->deny_cb = ar->deny_cb;
+		aa->data = ar->data;
+		aa->account = ar->account;
+		aa->username = g_strdup(ar->username);
+		aa->alias = g_strdup(ar->alias);
+		aa->add_buddy_after_auth = ar->add_buddy_after_auth;
+		purple_request_input(ar->account, NULL, _("Authorization acceptance message:"),
+		                     NULL, _("No reason given."), TRUE, FALSE, NULL,
+		                     _("OK"), G_CALLBACK(authorize_and_add_cb),
+		                     _("Cancel"), G_CALLBACK(authorize_noreason_cb),
+		                     ar->account, ar->username, NULL,
+		                     aa);
+		/* FIXME: aa is going to leak now. */
+	} else {
+		authorize_noreason_cb(ar);
+	}
+}
+
+static void
+deny_no_add_cb(struct auth_request *ar, const char *message)
+{
+	ar->deny_cb(message, ar->data);
+}
+
+static void
+deny_noreason_cb(struct auth_request *ar)
+{
+	ar->deny_cb(NULL, ar->data);
+}
+
+static void
+deny_reason_cb(struct auth_request *ar)
+{
+	const char *protocol_id;
+	PurplePlugin *plugin;
+	PurplePluginProtocolInfo *prpl_info = NULL;
+
+	protocol_id = purple_account_get_protocol_id(ar->account);
+	if ((plugin = purple_find_prpl(protocol_id)) != NULL)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
+
+	if (prpl_info && (prpl_info->options & OPT_PROTO_AUTHORIZATION_DENIED_MESSAGE)) {
+		/* Duplicate information because ar is freed by closing minidialog */
+		struct auth_request *aa = g_new0(struct auth_request, 1);
+		aa->auth_cb = ar->auth_cb;
+		aa->deny_cb = ar->deny_cb;
+		aa->data = ar->data;
+		aa->add_buddy_after_auth = ar->add_buddy_after_auth;
+		purple_request_input(ar->account, NULL, _("Authorization denied message:"),
+		                     NULL, _("No reason given."), TRUE, FALSE, NULL,
+		                     _("OK"), G_CALLBACK(deny_no_add_cb),
+		                     _("Cancel"), G_CALLBACK(deny_noreason_cb),
+		                     ar->account, ar->username, NULL,
+		                     aa);
+		/* FIXME: aa is going to leak now. */
+	} else {
+		deny_noreason_cb(ar);
+	}
 }
 
 static gboolean
@@ -2637,43 +2801,41 @@
 	GdkPixbuf *prpl_icon;
 	struct auth_request *aa;
 	const char *our_name;
-	gboolean have_valid_alias = alias && *alias;
+	gboolean have_valid_alias;
+	char *escaped_remote_user;
+	char *escaped_alias;
+	char *escaped_our_name;
+	char *escaped_message;
 
 	gc = purple_account_get_connection(account);
-	if (message != NULL && *message == '\0')
-		message = NULL;
+	if (message != NULL && *message != '\0')
+		escaped_message = g_markup_escape_text(message, -1);
+	else
+		escaped_message = g_strdup("");
 
 	our_name = (id != NULL) ? id :
 			(purple_connection_get_display_name(gc) != NULL) ? purple_connection_get_display_name(gc) :
 			purple_account_get_username(account);
-
-	if (pidgin_mini_dialog_links_supported()) {
-		char *escaped_remote_user = g_markup_escape_text(remote_user, -1);
-		char *escaped_alias = alias != NULL ? g_markup_escape_text(alias, -1) : g_strdup("");
-		char *escaped_our_name = g_markup_escape_text(our_name, -1);
-		char *escaped_message = message != NULL ? g_markup_escape_text(message, -1) : g_strdup("");
-		buffer = g_strdup_printf(_("<a href=\"viewinfo\">%s</a>%s%s%s wants to add you (%s) to his or her buddy list%s%s"),
-					escaped_remote_user,
-					(have_valid_alias ? " ("  : ""),
-					escaped_alias,
-					(have_valid_alias ? ")"   : ""),
-					escaped_our_name,
-					(have_valid_alias ? ": " : "."),
-					escaped_message);
-		g_free(escaped_remote_user);
-		g_free(escaped_alias);
-		g_free(escaped_our_name);
-		g_free(escaped_message);
-	} else {
-		buffer = g_strdup_printf(_("%s%s%s%s wants to add you (%s) to his or her buddy list%s%s"),
-					remote_user,
-					(have_valid_alias ? " ("  : ""),
-					(have_valid_alias ? alias : ""),
-					(have_valid_alias ? ")"   : ""),
-					our_name,
-					(message != NULL ? ": " : "."),
-					(message != NULL ? message  : ""));
-	}
+	escaped_our_name = g_markup_escape_text(our_name, -1);
+
+	escaped_remote_user = g_markup_escape_text(remote_user, -1);
+
+	have_valid_alias = alias && *alias;
+	escaped_alias = have_valid_alias ? g_markup_escape_text(alias, -1) : g_strdup("");
+
+	buffer = g_strdup_printf(_("<a href=\"viewinfo\">%s</a>%s%s%s wants to add you (%s) to his or her buddy list%s%s"),
+				escaped_remote_user,
+				(have_valid_alias ? " ("  : ""),
+				escaped_alias,
+				(have_valid_alias ? ")"   : ""),
+				escaped_our_name,
+				(have_valid_alias ? ": " : "."),
+				escaped_message);
+
+	g_free(escaped_remote_user);
+	g_free(escaped_alias);
+	g_free(escaped_our_name);
+	g_free(escaped_message);
 
 	prpl_icon = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL);
 
@@ -2689,15 +2851,13 @@
 	alert = pidgin_make_mini_dialog_with_custom_icon(
 		gc, prpl_icon,
 		_("Authorize buddy?"), NULL, aa,
-		_("Authorize"), authorize_and_add_cb,
-		_("Deny"), deny_no_add_cb,
+		_("Authorize"), authorize_reason_cb,
+		_("Deny"), deny_reason_cb,
 		NULL);
 
 	dialog = PIDGIN_MINI_DIALOG(alert);
-	if (pidgin_mini_dialog_links_supported()) {
-		pidgin_mini_dialog_enable_description_markup(dialog);
-		pidgin_mini_dialog_set_link_callback(dialog, G_CALLBACK(get_user_info_cb), aa);
-	}
+	pidgin_mini_dialog_enable_description_markup(dialog);
+	pidgin_mini_dialog_set_link_callback(dialog, G_CALLBACK(get_user_info_cb), aa);
 	pidgin_mini_dialog_set_description(dialog, buffer);
 	pidgin_mini_dialog_add_non_closing_button(dialog, _("Send Instant Message"), send_im_cb, aa);
 
--- a/pidgin/gtkblist.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkblist.c	Sat Feb 02 21:20:08 2013 +0100
@@ -1110,10 +1110,6 @@
 			if (pce->secret)
 			{
 				gtk_entry_set_visibility(GTK_ENTRY(input), FALSE);
-#if !GTK_CHECK_VERSION(2,16,0)
-				if (gtk_entry_get_invisible_char(GTK_ENTRY(input)) == '*')
-					gtk_entry_set_invisible_char(GTK_ENTRY(input), PIDGIN_INVISIBLE_CHAR);
-#endif /* Less than GTK+ 2.16 */
 			}
 			pidgin_add_widget_to_vbox(data->rq_data.vbox, pce->label, data->rq_data.sg, input, TRUE, NULL);
 			g_signal_connect(G_OBJECT(input), "changed",
@@ -5473,6 +5469,7 @@
 	GtkWidget *hbox, *label;
 	const char *username = purple_account_get_username(account);
 	char *markup;
+	char *description;
 
 	hbox = gtk_hbox_new(FALSE, 6);
 	g_object_set_data(G_OBJECT(hbox), OBJECT_DATA_KEY_ACCOUNT, account);
@@ -5485,14 +5482,9 @@
 	g_free(markup);
 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
 	g_object_set(G_OBJECT(label), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
-#if GTK_CHECK_VERSION(2,12,0)
-	{ /* avoid unused variable warnings on pre-2.12 Gtk */
-		char *description =
-			purple_account_get_current_error(account)->description;
-		if (description != NULL && *description != '\0')
-			gtk_widget_set_tooltip_text(label, description);
-	}
-#endif
+	description = purple_account_get_current_error(account)->description;
+	if (description != NULL && *description != '\0')
+		gtk_widget_set_tooltip_text(label, description);
 	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
 
 	return hbox;
@@ -5536,12 +5528,10 @@
 update_signed_on_elsewhere_tooltip(PurpleAccount *account,
                                    const char *description)
 {
-#if GTK_CHECK_VERSION(2,12,0)
 	PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);
 	GtkContainer *c = GTK_CONTAINER(priv->signed_on_elsewhere->contents);
 	GtkWidget *label = find_child_widget_by_account(c, account);
 	gtk_widget_set_tooltip_text(label, description);
-#endif
 }
 
 
@@ -5667,7 +5657,6 @@
 {
 	PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);
 	GtkStyle *style;
-#if GTK_CHECK_VERSION(2,12,0)
 	GtkWidget *window;
 
 	if (priv->changing_style)
@@ -5686,25 +5675,6 @@
 	gtk_widget_destroy(window);
 
 	gtk_widget_queue_draw(gtkblist->headline);
-#else
-	GtkTooltips *tooltips;
-
-	if (gtkblist->changing_style)
-		return;
-
-	tooltips = gtk_tooltips_new ();
-	g_object_ref_sink (tooltips);
-
-	gtk_tooltips_force_window (tooltips);
-	gtk_widget_ensure_style (tooltips->tip_window);
-	style = gtk_widget_get_style (tooltips->tip_window);
-
-	priv->changing_style = TRUE;
-	gtk_widget_set_style (gtkblist->headline, style);
-	priv->changing_style = FALSE;
-
-	g_object_unref (tooltips);
-#endif
 }
 #endif
 
@@ -6141,9 +6111,7 @@
 	close = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
 	close = pidgin_create_small_button(close);
 	gtk_box_pack_start(GTK_BOX(gtkblist->headline), close, FALSE, FALSE, 0);
-#if GTK_CHECK_VERSION(2,12,0)
 	gtk_widget_set_tooltip_text(close, _("Close"));
-#endif
 	g_signal_connect(close, "clicked", G_CALLBACK(headline_close_press_cb), gtkblist);
 
 	g_signal_connect(G_OBJECT(ebox), "enter-notify-event", G_CALLBACK(headline_box_enter_cb), priv);
@@ -7811,10 +7779,6 @@
 	purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/y", 0);
 	purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/width", 250); /* Golden ratio, baby */
 	purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/height", 405); /* Golden ratio, baby */
-#if !GTK_CHECK_VERSION(2,14,0)
-	/* This pref is used in pidgintooltip.c. */
-	purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/tooltip_delay", 500);
-#endif
 	purple_prefs_add_string(PIDGIN_PREFS_ROOT "/blist/theme", "");
 
 	purple_theme_manager_register_type(g_object_new(PIDGIN_TYPE_BLIST_THEME_LOADER, "type", "blist", NULL));
--- a/pidgin/gtkcellrendererexpander.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkcellrendererexpander.c	Sat Feb 02 21:20:08 2013 +0100
@@ -29,7 +29,6 @@
  * Jonathon Blandford <jrb@redhat.com> for RedHat, Inc.
  */
 
-#include <gtk/gtk.h>
 #include "gtkcellrendererexpander.h"
 
 #include "gtk3compat.h"
--- a/pidgin/gtkconv-theme.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkconv-theme.c	Sat Feb 02 21:20:08 2013 +0100
@@ -500,7 +500,8 @@
 	}
 	g_free(priv->variant);
 
-	g_array_unref(priv->nick_colors);
+	if (priv->nick_colors)
+		g_array_unref(priv->nick_colors);
 
 	parent_class->finalize(obj);
 }
--- a/pidgin/gtkconv.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkconv.c	Sat Feb 02 21:20:08 2013 +0100
@@ -1005,7 +1005,7 @@
 
 		/* Now the Buddy drop-down entry field. */
 		info->entry = gtk_entry_new();
-		pidgin_setup_screenname_autocomplete_with_filter(info->entry, NULL, chat_invite_filter,
+		pidgin_setup_screenname_autocomplete(info->entry, NULL, chat_invite_filter,
 				purple_conversation_get_account(conv));
 		gtk_table_attach_defaults(GTK_TABLE(table), info->entry, 1, 2, 0, 1);
 		gtk_label_set_mnemonic_widget(GTK_LABEL(label), info->entry);
@@ -3315,15 +3315,10 @@
 			return FALSE;
 
 		buddy = purple_find_buddy(account, purple_conversation_get_name(conv));
-
-		/* gotta remain bug-compatible :( libpurple < 2.0.2 didn't handle
-		 * removing "isolated" buddy nodes well */
-		if (purple_version_check(2, 0, 2) == NULL) {
-			if ((buddy == NULL) && (gtkconv->webview != NULL)) {
-				buddy = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_buddy");
-			}
-
-			if ((buddy == NULL) && (gtkconv->webview != NULL)) {
+		if (!buddy && gtkconv->webview) {
+			buddy = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_buddy");
+
+			if (!buddy) {
 				buddy = purple_buddy_new(account, purple_conversation_get_name(conv), NULL);
 				purple_blist_node_set_flags((PurpleBlistNode *)buddy,
 						PURPLE_BLIST_NODE_FLAG_NO_SAVE);
@@ -5776,9 +5771,6 @@
 	gtkconv->send_history = g_list_append(NULL, NULL);
 
 	/* Setup some initial variables. */
-#if !GTK_CHECK_VERSION(2,12,0)
-	gtkconv->tooltips = gtk_tooltips_new();
-#endif
 	gtkconv->unseen_state = PIDGIN_UNSEEN_NONE;
 	gtkconv->unseen_count = 0;
 	theme_name = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/theme");
@@ -5997,10 +5989,6 @@
 		g_free(gtkconv->u.chat);
 	}
 
-#if !GTK_CHECK_VERSION(2,12,0)
-	gtk_object_sink(GTK_OBJECT(gtkconv->tooltips));
-#endif
-
 	gtkconv->send_history = g_list_first(gtkconv->send_history);
 	g_list_foreach(gtkconv->send_history, (GFunc)g_free, NULL);
 	g_list_free(gtkconv->send_history);
@@ -6726,6 +6714,47 @@
 	}
 #endif
 
+
+	/* on rejoin only request message history from after this message */
+	if (flags & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV) &&
+		purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
+		PurpleChat *chat = purple_blist_find_chat(
+			purple_conversation_get_account(conv),
+			purple_conversation_get_name(conv));
+		if (chat) {
+			GHashTable *comps = purple_chat_get_components(chat);
+			time_t now, history_since, prev_history_since = 0;
+			struct tm *history_since_tm;
+			const char *history_since_s, *prev_history_since_s;
+
+			history_since = mtime + 1;
+
+			prev_history_since_s = g_hash_table_lookup(comps,
+				"history_since");
+			if (prev_history_since_s != NULL)
+				prev_history_since = purple_str_to_time(
+					prev_history_since_s, TRUE, NULL, NULL,
+					NULL);
+
+			now = time(NULL);
+			/* in case of incorrectly stored timestamps */
+			if (prev_history_since > now)
+				prev_history_since = now;
+			/* in case of delayed messages */
+			if (history_since < prev_history_since)
+				history_since = prev_history_since;
+
+			history_since_tm = gmtime(&history_since);
+			history_since_s = purple_utf8_strftime(
+				"%Y-%m-%dT%H:%M:%SZ", history_since_tm);
+			if (g_strcmp0(prev_history_since_s,
+				history_since_s) != 0)
+				g_hash_table_replace(comps,
+					g_strdup("history_since"),
+					g_strdup(history_since_s));
+		}
+	}
+
 	purple_signal_emit(pidgin_conversations_get_handle(),
 		(type == PURPLE_CONV_TYPE_IM ? "displayed-im-msg" : "displayed-chat-msg"),
 		account, name, displaying, conv, flags);
@@ -8207,7 +8236,7 @@
 			purple_conversation_write(conv, NULL, _("The account has disconnected and you are no "
 						"longer in this chat. You will automatically rejoin the chat when "
 						"the account reconnects."),
-					PURPLE_MESSAGE_SYSTEM, time(NULL));
+					PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));
 		}
 		list = list->next;
 	}
@@ -10226,7 +10255,7 @@
 	gtk_css_provider_load_from_data(provider, str->str, str->len, &error);
 
 	gtk_style_context_add_provider(gtk_widget_get_style_context(widget),
-	                               provider,
+	                               GTK_STYLE_PROVIDER(provider),
 	                               GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
 
 	if (error)
--- a/pidgin/gtkconv.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkconv.h	Sat Feb 02 21:20:08 2013 +0100
@@ -90,11 +90,7 @@
 
 	gboolean make_sound;
 
-#if GTK_CHECK_VERSION(2,12,0)
 	gpointer depr2;
-#else
-	GtkTooltips *tooltips;
-#endif
 
 	GtkWidget *tab_cont;
 	GtkWidget *tabby;
--- a/pidgin/gtkdebug.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkdebug.c	Sat Feb 02 21:20:08 2013 +0100
@@ -109,7 +109,8 @@
 		text = gtk_entry_get_text(GTK_ENTRY(debug_win->expression));
 		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/debug/regex", text);
 	}
-	g_regex_unref(debug_win->regex);
+	if (debug_win->regex != NULL)
+		g_regex_unref(debug_win->regex);
 
 	/* If the "Save Log" dialog is open then close it */
 	purple_request_close_with_handle(debug_win);
@@ -699,9 +700,6 @@
 	gint width, height;
 	void *handle;
 	GtkToolItem *item;
-#if !GTK_CHECK_VERSION(2,12,0)
-	GtkTooltips *tooltips;
-#endif
 
 	win = g_new0(DebugWindow, 1);
 
@@ -728,12 +726,6 @@
 	if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/debug/toolbar")) {
 		/* Setup our top button bar thingie. */
 		toolbar = gtk_toolbar_new();
-#if !GTK_CHECK_VERSION(2,12,0)
-		tooltips = gtk_tooltips_new();
-#endif
-#if !GTK_CHECK_VERSION(2,14,0)
-		gtk_toolbar_set_tooltips(GTK_TOOLBAR(toolbar), TRUE);
-#endif
 		gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolbar), TRUE);
 		g_signal_connect(G_OBJECT(toolbar), "button-press-event", G_CALLBACK(toolbar_context), win);
 
@@ -1046,7 +1038,7 @@
 
 	esc_s = purple_escape_js(arg_s);
 
-	js = g_strdup_printf("append(%d, '%s', '%s', '%s');",
+	js = g_strdup_printf("append(%d, '%s', '%s', %s);",
 		level, mdate, category ? category : "", esc_s);
 	g_free(esc_s);
 
--- a/pidgin/gtkdialogs.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkdialogs.c	Sat Feb 02 21:20:08 2013 +0100
@@ -220,7 +220,7 @@
 	{N_("Malay"),               "ms_MY", "Muhammad Najmi bin Ahmad Zabidi", "najmi.zabidi@gmail.com"},
 	{N_("Burmese"),             "my_MM", "Thura Hlaing", "trhura@gmail.com"},
 	{N_("Bokmål Norwegian"),    "nb", "Hans Fredrik Nordhaug", "hans@nordhaug.priv.no"},
-	{N_("Nepali"),              "ne", "Shyam Krishna Bal", "shyamkrishna_bal@yahoo.com"},
+	{N_("Nepali"),              "ne", "Shyam Krishna Bal", NULL},
 	{N_("Dutch, Flemish"),      "nl", "Gideon van Melle", "translations@gvmelle.com"},
 	{N_("Norwegian Nynorsk"),   "nn", "Yngve Spjeld Landro", "l10n@landro.net"},
 	{N_("Occitan"),             "oc", "Yannig Marchegay", "yannig@marchegay.org"},
--- a/pidgin/gtkdnd-hints.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkdnd-hints.c	Sat Feb 02 21:20:08 2013 +0100
@@ -26,7 +26,6 @@
 
 #include "gtkdnd-hints.h"
 
-#include <gtk/gtk.h>
 #include <gdk/gdk.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
--- a/pidgin/gtkdocklet.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkdocklet.c	Sat Feb 02 21:20:08 2013 +0100
@@ -847,38 +847,20 @@
 static gboolean
 docklet_gtk_embed_timeout_cb(gpointer data)
 {
-#if !GTK_CHECK_VERSION(2,12,0)
-	if (gtk_status_icon_is_embedded(docklet)) {
-		/* Older GTK+ (<2.12) don't implement the embedded signal, but the
-		   information is still accessible through the above function. */
-		purple_debug_info("docklet", "embedded\n");
+	/* The docklet was not embedded within the timeout.
+	 * Remove it as a visibility manager, but leave the plugin
+	 * loaded so that it can embed automatically if/when a notification
+	 * area becomes available.
+	 */
+	purple_debug_info("docklet", "failed to embed within timeout\n");
+	pidgin_docklet_remove();
+	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", FALSE);
 
-		pidgin_docklet_embedded();
-		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", TRUE);
-	}
-	else
-#endif
-	{
-		/* The docklet was not embedded within the timeout.
-		 * Remove it as a visibility manager, but leave the plugin
-		 * loaded so that it can embed automatically if/when a notification
-		 * area becomes available.
-		 */
-		purple_debug_info("docklet", "failed to embed within timeout\n");
-		pidgin_docklet_remove();
-		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", FALSE);
-	}
-
-#if GTK_CHECK_VERSION(2,12,0)
 	embed_timeout = 0;
 	return FALSE;
-#else
-	return TRUE;
-#endif
 }
 #endif
 
-#if GTK_CHECK_VERSION(2,12,0)
 static gboolean
 docklet_gtk_embedded_cb(GtkWidget *widget, gpointer data)
 {
@@ -901,7 +883,6 @@
 
 	return TRUE;
 }
-#endif
 
 static void
 docklet_gtk_status_activated_cb(GtkStatusIcon *status_icon, gpointer user_data)
@@ -956,9 +937,7 @@
 
 	g_signal_connect(G_OBJECT(docklet), "activate", G_CALLBACK(docklet_gtk_status_activated_cb), NULL);
 	g_signal_connect(G_OBJECT(docklet), "popup-menu", G_CALLBACK(docklet_gtk_status_clicked_cb), NULL);
-#if GTK_CHECK_VERSION(2,12,0)
 	g_signal_connect(G_OBJECT(docklet), "notify::embedded", G_CALLBACK(docklet_gtk_embedded_cb), NULL);
-#endif
 
 	gtk_status_icon_set_visible(docklet, TRUE);
 
@@ -978,15 +957,11 @@
 	if (!recreate) {
 		pidgin_docklet_embedded();
 #ifndef _WIN32
-#if GTK_CHECK_VERSION(2,12,0)
 		if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded")) {
 			embed_timeout = purple_timeout_add_seconds(LONG_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
 		} else {
 			embed_timeout = purple_timeout_add_seconds(SHORT_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
 		}
-#else
-		embed_timeout = purple_timeout_add_seconds(SHORT_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
-#endif
 #endif
 	}
 
--- a/pidgin/gtkeventloop.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkeventloop.c	Sat Feb 02 21:20:08 2013 +0100
@@ -124,11 +124,7 @@
 	pidgin_input_add,
 	g_source_remove,
 	NULL, /* input_get_error */
-#if GLIB_CHECK_VERSION(2,14,0)
 	g_timeout_add_seconds,
-#else
-	NULL,
-#endif
 	NULL,
 	NULL,
 	NULL
--- a/pidgin/gtkimhtml.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkimhtml.c	Sat Feb 02 21:20:08 2013 +0100
@@ -1758,7 +1758,7 @@
 	gtk_text_buffer_create_tag(imhtml->text_buffer, "PRE", "family", "Monospace", NULL);
 	gtk_text_buffer_create_tag(imhtml->text_buffer, "search", "background", "#22ff00", "weight", "bold", NULL);
 	gtk_text_buffer_create_tag(imhtml->text_buffer, "comment", "weight", PANGO_WEIGHT_NORMAL,
-#if FALSE && GTK_CHECK_VERSION(2,10,10)
+#if FALSE
 			"invisible", FALSE,
 #endif
 			NULL);
@@ -2523,7 +2523,7 @@
 [19:58] <Robot101> marv: images go into the imgstore, a refcounted... well.. hash. :)
 [19:59] <KingAnt> marv: I think the image tag used by the core is something like <img id="#"/>
 [19:59] Ro0tSiEgE robert42 RobFlynn Robot101 ross22 roz
-[20:00] <KingAnt> marv: Where the ID is the what is returned when you add the image to the imgstore using purple_imgstore_add
+[20:00] <KingAnt> marv: Where the ID is the what is returned when you add the image to the imgstore using purple_imgstore_new
 [20:00] <marv> Robot101: so how does the image get passed to serv_got_im() and serv_send_im()? just as the <img id="#" and then the prpl looks it up from the store?
 [20:00] <KingAnt> marv: Right
 [20:00] <marv> alright
@@ -3398,7 +3398,7 @@
 
 					gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
 
-#if FALSE && GTK_CHECK_VERSION(2,10,10)
+#if FALSE
 					wpos = g_snprintf (ws, len, "%s", tag);
 					gtk_text_buffer_insert_with_tags_by_name(imhtml->text_buffer, iter, ws, wpos, "comment", NULL);
 #else
@@ -3576,7 +3576,7 @@
 void       gtk_imhtml_show_comments    (GtkIMHtml        *imhtml,
 					gboolean          show)
 {
-#if FALSE && GTK_CHECK_VERSION(2,10,10)
+#if FALSE
 	GtkTextTag *tag;
 	tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "comment");
 	if (tag)
@@ -3963,8 +3963,7 @@
 
 	gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(image->image));
 
-	if(!gtk_check_version(2, 4, 0))
-		g_object_set(G_OBJECT(box), "visible-window", FALSE, NULL);
+	g_object_set(G_OBJECT(box), "visible-window", FALSE, NULL);
 
 	gtk_widget_show(GTK_WIDGET(image->image));
 	gtk_widget_show(box);
@@ -5268,8 +5267,10 @@
 		g_free(name);
 
 		if (tmp) {
-			g_snprintf(buf, sizeof(buf), "<a href=\"%s\">", tmp);
+			gchar *escaped = purple_markup_escape_text(tmp, -1);
+			g_snprintf(buf, sizeof(buf), "<a href=\"%s\">", escaped);
 			buf[sizeof(buf)-1] = '\0';
+			g_free(escaped);
 			return buf;
 		} else {
 			return "";
--- a/pidgin/gtkimhtmltoolbar.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkimhtmltoolbar.c	Sat Feb 02 21:20:08 2013 +0100
@@ -529,7 +529,7 @@
 
 	name = strrchr(filename, G_DIR_SEPARATOR) + 1;
 
-	id = purple_imgstore_add_with_id(filedata, size, name);
+	id = purple_imgstore_new_with_id(filedata, size, name);
 
 	if (id == 0) {
 		buf = g_strdup_printf(_("Failed to store image: %s\n"), filename);
@@ -1177,9 +1177,6 @@
 	}
 
 	g_free(toolbar->sml);
-#if !GTK_CHECK_VERSION(2,12,0)
-	gtk_object_sink(GTK_OBJECT(toolbar->tooltips));
-#endif
 
 	menu = g_object_get_data(object, "font_menu");
 	if (menu)
@@ -1377,10 +1374,6 @@
 	toolbar->smiley_dialog = NULL;
 	toolbar->image_dialog = NULL;
 
-#if !GTK_CHECK_VERSION(2,12,0)
-	toolbar->tooltips = gtk_tooltips_new();
-#endif
-
 	gtk_box_set_spacing(GTK_BOX(toolbar), 3);
 
 	gtk_imhtmltoolbar_create_old_buttons(toolbar);
--- a/pidgin/gtkimhtmltoolbar.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkimhtmltoolbar.h	Sat Feb 02 21:20:08 2013 +0100
@@ -44,11 +44,7 @@
 
 	GtkWidget *imhtml;
 
-#if GTK_CHECK_VERSION(2,12,0)
 	gpointer depr1;
-#else
-	GtkTooltips *tooltips;
-#endif
 
 	GtkWidget *bold;
 	GtkWidget *italic;
--- a/pidgin/gtkmain.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkmain.c	Sat Feb 02 21:20:08 2013 +0100
@@ -413,8 +413,8 @@
 /* FUCKING GET ME A TOWEL! */
 #ifdef _WIN32
 /* suppress gcc "no previous prototype" warning */
-int pidgin_main(HINSTANCE hint, int argc, char *argv[]);
-int pidgin_main(HINSTANCE hint, int argc, char *argv[])
+int __cdecl pidgin_main(HINSTANCE hint, int argc, char *argv[]);
+int __cdecl pidgin_main(HINSTANCE hint, int argc, char *argv[])
 #else
 int main(int argc, char *argv[])
 #endif
@@ -754,16 +754,9 @@
 		return 0;
 	}
 
-	/* TODO: Move blist loading into purple_blist_init() */
-	purple_set_blist(purple_blist_new());
-	purple_blist_load();
-
 	/* load plugins we had when we quit */
 	purple_plugins_load_saved(PIDGIN_PREFS_ROOT "/plugins/loaded");
 
-	/* TODO: Move pounces loading into purple_pounces_init() */
-	purple_pounces_load();
-
 	ui_main();
 
 #ifdef USE_SM
--- a/pidgin/gtkmedia.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkmedia.c	Sat Feb 02 21:20:08 2013 +0100
@@ -666,30 +666,18 @@
 }
 
 static void
-#if GTK_CHECK_VERSION(2,12,0)
 pidgin_media_input_volume_changed(GtkScaleButton *range, double value,
 		PurpleMedia *media)
 {
 	double val = (double)value * 100.0;
-#else
-pidgin_media_input_volume_changed(GtkRange *range, PurpleMedia *media)
-{
-	double val = (double)gtk_range_get_value(GTK_RANGE(range));
-#endif
 	purple_media_set_input_volume(media, NULL, val);
 }
 
 static void
-#if GTK_CHECK_VERSION(2,12,0)
 pidgin_media_output_volume_changed(GtkScaleButton *range, double value,
 		PurpleMedia *media)
 {
 	double val = (double)value * 100.0;
-#else
-pidgin_media_output_volume_changed(GtkRange *range, PurpleMedia *media)
-{
-	double val = (double)gtk_range_get_value(GTK_RANGE(range));
-#endif
 	purple_media_set_output_volume(media, NULL, NULL, val);
 }
 
@@ -717,7 +705,6 @@
 	} else
 		g_return_val_if_reached(NULL);
 
-#if GTK_CHECK_VERSION(2,12,0)
 	/* Setup widget structure */
 	volume_widget = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
 	progress_parent = gtk_vbox_new(FALSE, 0);
@@ -729,19 +716,6 @@
 	gtk_scale_button_set_value(GTK_SCALE_BUTTON(volume), value/100.0);
 	gtk_box_pack_end(GTK_BOX(volume_widget),
 			volume, FALSE, FALSE, 0);
-#else
-	/* Setup widget structure */
-	volume_widget = gtk_vbox_new(FALSE, 0);
-	progress_parent = volume_widget;
-
-	/* Volume slider */
-	volume = gtk_hscale_new_with_range(0.0, 100.0, 5.0);
-	gtk_range_set_increments(GTK_RANGE(volume), 5.0, 25.0);
-	gtk_range_set_value(GTK_RANGE(volume), value);
-	gtk_scale_set_draw_value(GTK_SCALE(volume), FALSE);
-	gtk_box_pack_end(GTK_BOX(volume_widget),
-			volume, TRUE, FALSE, 0);
-#endif
 
 	/* Volume level indicator */
 	progress = gtk_progress_bar_new();
--- a/pidgin/gtkmenutray.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkmenutray.c	Sat Feb 02 21:20:08 2013 +0100
@@ -37,10 +37,6 @@
  * Globals
  *****************************************************************************/
 static GObjectClass *parent_class = NULL;
-#if !GTK_CHECK_VERSION(2,12,0)
-static GtkTooltips *tooltips = NULL;
-#endif
-
 /******************************************************************************
  * Internal Stuff
  *****************************************************************************/
@@ -80,20 +76,6 @@
 #endif
 
 /******************************************************************************
- * Widget Stuff
- *****************************************************************************/
-#if !GTK_CHECK_VERSION(2,12,0)
-static void
-tooltips_unref_cb(gpointer data, GObject *object, gboolean is_last_ref)
-{
-	if (is_last_ref) {
-		g_object_unref(tooltips);
-		tooltips = NULL;
-	}
-}
-#endif
-
-/******************************************************************************
  * Object Stuff
  *****************************************************************************/
 static void
@@ -270,14 +252,6 @@
 void
 pidgin_menu_tray_set_tooltip(PidginMenuTray *menu_tray, GtkWidget *widget, const char *tooltip)
 {
-#if !GTK_CHECK_VERSION(2,12,0)
-	gboolean notify_tooltips = FALSE;
-	if (!tooltips) {
-		tooltips = gtk_tooltips_new();
-		notify_tooltips = TRUE;
-	}
-#endif
-
 	/* Should we check whether widget is a child of menu_tray? */
 
 	/*
@@ -290,13 +264,5 @@
 	if (!gtk_widget_get_has_window(widget))
 		widget = gtk_widget_get_parent(widget);
 
-#if GTK_CHECK_VERSION(2,12,0)
 	gtk_widget_set_tooltip_text(widget, tooltip);
-#else
-	gtk_tooltips_set_tip(tooltips, widget, tooltip, NULL);
-
-	if (notify_tooltips)
-		g_object_add_toggle_ref(G_OBJECT(tooltips), tooltips_unref_cb, NULL);
-#endif
 }
-
--- a/pidgin/gtknotify.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtknotify.c	Sat Feb 02 21:20:08 2013 +0100
@@ -388,13 +388,8 @@
 gboolean
 pidgin_notify_emails_pending()
 {
-#if GTK_CHECK_VERSION(2,18,0)
 	return mail_dialog != NULL
 		&& !gtk_widget_get_visible(mail_dialog->dialog);
-#else
-	return mail_dialog != NULL
-		&& !GTK_WIDGET_VISIBLE(mail_dialog->dialog);
-#endif
 }
 
 void pidgin_notify_emails_present(void *data)
--- a/pidgin/gtkpluginpref.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkpluginpref.c	Sat Feb 02 21:20:08 2013 +0100
@@ -94,10 +94,6 @@
 				if (purple_plugin_pref_get_masked(pref))
 				{
 					gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
-#if !GTK_CHECK_VERSION(2,16,0)
-					if (gtk_entry_get_invisible_char(GTK_ENTRY(entry)) == '*')
-						gtk_entry_set_invisible_char(GTK_ENTRY(entry), PIDGIN_INVISIBLE_CHAR);
-#endif /* Less than GTK+ 2.16 */
 				}
 				g_signal_connect(G_OBJECT(entry), "changed",
 								 G_CALLBACK(entry_cb),
--- a/pidgin/gtkpounce.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkpounce.c	Sat Feb 02 21:20:08 2013 +0100
@@ -601,7 +601,7 @@
 
 	dialog->buddy_entry = gtk_entry_new();
 
-	pidgin_setup_screenname_autocomplete_with_filter(dialog->buddy_entry, dialog->account_menu, pidgin_screenname_autocomplete_default_filter, GINT_TO_POINTER(FALSE));
+	pidgin_setup_screenname_autocomplete(dialog->buddy_entry, dialog->account_menu, pidgin_screenname_autocomplete_default_filter, GINT_TO_POINTER(FALSE));
 
 	gtk_box_pack_start(GTK_BOX(hbox), dialog->buddy_entry, TRUE, TRUE, 0);
 	gtk_widget_show(dialog->buddy_entry);
--- a/pidgin/gtkprefs.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkprefs.c	Sat Feb 02 21:20:08 2013 +0100
@@ -58,7 +58,7 @@
 #include "gtkwebview.h"
 #include "gtkwebviewtoolbar.h"
 #include "pidginstock.h"
-#if USE_VV
+#ifdef USE_VV
 #include "media-gst.h"
 #if GST_CHECK_VERSION(1,0,0)
 #include <gst/video/videooverlay.h>
@@ -123,7 +123,7 @@
 static GtkListStore *prefs_status_icon_themes;
 static GtkListStore *prefs_smiley_themes;
 
-#if USE_VV
+#ifdef USE_VV
 
 static const gchar *AUDIO_SRC_PLUGINS[] = {
 	"alsasrc",	"ALSA",
@@ -733,6 +733,19 @@
 	prefs_smiley_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
 }
 
+/**
+ * Attempt to load the given directory as a theme.  If we are unable to
+ * open the path as a theme then we recurse into path and attempt to
+ * load each subdirectory that we encounter.
+ *
+ * @param path A directory containing a theme.  The theme could be at the
+ *        top level of this directory or in any subdirectory thereof.
+ * @param type The type of theme to load.  The loader for this theme type
+ *        will be used and this loader will determine what constitutes a
+ *        "theme."
+ *
+ * @return A new reference to a PurpleTheme.
+ */
 static PurpleTheme *
 prefs_theme_find_theme(const gchar *path, const gchar *type)
 {
@@ -876,7 +889,11 @@
 						 "purple", info->type, NULL);
 
 			/* move the entire directory to new location */
-			g_rename(purple_theme_get_dir(theme), theme_dest);
+			if (g_rename(purple_theme_get_dir(theme), theme_dest)) {
+				purple_debug_error("gtkprefs", "Error renaming %s to %s: "
+						"%s\n", purple_theme_get_dir(theme), theme_dest,
+						g_strerror(errno));
+			}
 
 			g_free(theme_dest);
 			g_remove(destdir);
@@ -920,14 +937,21 @@
 				if(!g_file_test(theme_dest, G_FILE_TEST_IS_DIR))
 					purple_build_dir(theme_dest, S_IRUSR | S_IWUSR | S_IXUSR);
 
-				g_rename(purple_theme_get_dir(theme), theme_dest);
+				if (g_rename(purple_theme_get_dir(theme), theme_dest)) {
+					purple_debug_error("gtkprefs", "Error renaming %s to %s: "
+							"%s\n", purple_theme_get_dir(theme), theme_dest,
+							g_strerror(errno));
+				}
 
 				g_free(theme_dest);
 				g_object_unref(theme);
 
 				prefs_themes_refresh();
 			} else {
-				g_remove(temp_path);
+				if (g_remove(temp_path)) {
+					purple_debug_error("gtkprefs", "Error removing %s: %s\n",
+							temp_path, g_strerror(errno));
+				}
 				purple_notify_error(NULL, NULL, _("Theme failed to load."), NULL);
 			}
 		} else {
@@ -2435,10 +2459,6 @@
 		gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
 		gtk_table_attach(GTK_TABLE(table), entry, 3, 4, 1, 2, GTK_FILL , 0, 0, 0);
 		gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
-#if !GTK_CHECK_VERSION(2,16,0)
-		if (gtk_entry_get_invisible_char(GTK_ENTRY(entry)) == '*')
-			gtk_entry_set_invisible_char(GTK_ENTRY(entry), PIDGIN_INVISIBLE_CHAR);
-#endif /* Less than GTK+ 2.16 */
 		g_signal_connect(G_OBJECT(entry), "changed",
 				 G_CALLBACK(proxy_print_option), (void *)PROXYPASS);
 
@@ -3018,7 +3038,7 @@
 	return ret;
 }
 
-#if USE_VV
+#ifdef USE_VV
 static GList *
 get_vv_element_devices(const gchar *element_name)
 {
@@ -3377,10 +3397,9 @@
 }
 
 static void
-volume_changed_cb(GtkScaleButton *button, gpointer data)
+volume_changed_cb(GtkScaleButton *button, gdouble value, gpointer data)
 {
-	purple_prefs_set_int("/purple/media/audio/volume/input",
-	                     gtk_scale_button_get_value(GTK_SCALE_BUTTON(button)) * 100);
+	purple_prefs_set_int("/purple/media/audio/volume/input", value * 100);
 }
 
 static void
@@ -3655,7 +3674,7 @@
 	prefs_notebook_add_page(_("Sounds"), sound_page(), notebook_page++);
 	prefs_notebook_add_page(_("Status / Idle"), away_page(), notebook_page++);
 	prefs_notebook_add_page(_("Themes"), theme_page(), notebook_page++);
-#if USE_VV
+#ifdef USE_VV
 	prefs_notebook_add_page(_("Voice/Video"), vv_page(), notebook_page++);
 #endif
 }
@@ -3789,7 +3808,7 @@
 	purple_prefs_connect_callback(&prefs, PIDGIN_PREFS_ROOT "/smileys/theme",
 								smiley_theme_pref_cb, NULL);
 
-#if USE_VV
+#ifdef USE_VV
 	/* Voice/Video */
 	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/vvconfig");
 	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/vvconfig/audio");
--- a/pidgin/gtkrequest.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkrequest.c	Sat Feb 02 21:20:08 2013 +0100
@@ -48,11 +48,6 @@
 
 #include "gtk3compat.h"
 
-#if !GTK_CHECK_VERSION(2,12,0)
-#undef gtk_widget_set_tooltip_text
-#define gtk_widget_set_tooltip_text(x,y)
-#endif
-
 static GtkWidget * create_account_field(PurpleRequestField *field);
 
 typedef struct
@@ -466,10 +461,6 @@
 			if (masked)
 			{
 				gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
-#if !GTK_CHECK_VERSION(2,16,0)
-				if (gtk_entry_get_invisible_char(GTK_ENTRY(entry)) == '*')
-					gtk_entry_set_invisible_char(GTK_ENTRY(entry), PIDGIN_INVISIBLE_CHAR);
-#endif /* Less than GTK+ 2.16 */
 			}
 		}
 		gtk_widget_show_all(vbox);
@@ -844,7 +835,7 @@
 					}
 				}
 			}
-			pidgin_setup_screenname_autocomplete_with_filter(entry, optmenu, pidgin_screenname_autocomplete_default_filter, GINT_TO_POINTER(!strcmp(type_hint, "screenname-all")));
+			pidgin_setup_screenname_autocomplete(entry, optmenu, pidgin_screenname_autocomplete_default_filter, GINT_TO_POINTER(!strcmp(type_hint, "screenname-all")));
 		}
 	}
 }
@@ -912,10 +903,6 @@
 		if (purple_request_field_string_is_masked(field))
 		{
 			gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE);
-#if !GTK_CHECK_VERSION(2,16,0)
-			if (gtk_entry_get_invisible_char(GTK_ENTRY(widget)) == '*')
-				gtk_entry_set_invisible_char(GTK_ENTRY(widget),	PIDGIN_INVISIBLE_CHAR);
-#endif /* Less than GTK+ 2.16 */
 		}
 
 		gtk_editable_set_editable(GTK_EDITABLE(widget),
--- a/pidgin/gtkstatusbox.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkstatusbox.c	Sat Feb 02 21:20:08 2013 +0100
@@ -454,11 +454,9 @@
 	gtk_widget_set_parent(status_box->icon_box, GTK_WIDGET(status_box));
 	gtk_widget_show(status_box->icon_box);
 
-#if GTK_CHECK_VERSION(2,12,0)
 	gtk_widget_set_tooltip_text(status_box->icon_box,
 			status_box->account ? _("Click to change your buddyicon for this account.") :
 				_("Click to change your buddyicon for all accounts."));
-#endif
 
 	if (status_box->account &&
 		!purple_account_get_bool(status_box->account, "use-global-buddyicon", TRUE))
--- a/pidgin/gtkutils.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkutils.c	Sat Feb 02 21:20:08 2013 +0100
@@ -28,9 +28,7 @@
 #include "internal.h"
 #include "pidgin.h"
 
-#ifndef _WIN32
-# include <X11/Xlib.h>
-#else
+#ifdef _WIN32
 # ifdef small
 #  undef small
 # endif
@@ -1412,7 +1410,7 @@
 		}
 		shortname = strrchr(data->filename, G_DIR_SEPARATOR);
 		shortname = shortname ? shortname + 1 : data->filename;
-		id = purple_imgstore_add_with_id(filedata, size, shortname);
+		id = purple_imgstore_new_with_id(filedata, size, shortname);
 
 		gtk_webview_insert_image(GTK_WEBVIEW(gtkconv->entry), id);
 		purple_imgstore_unref_by_id(id);
@@ -2021,7 +2019,7 @@
 }
 
 void
-pidgin_setup_screenname_autocomplete_with_filter(GtkWidget *entry, GtkWidget *accountopt, PidginFilterBuddyCompletionEntryFunc filter_func, gpointer user_data)
+pidgin_setup_screenname_autocomplete(GtkWidget *entry, GtkWidget *accountopt, PidginFilterBuddyCompletionEntryFunc filter_func, gpointer user_data)
 {
 	PidginCompletionData *data;
 
--- a/pidgin/gtkutils.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkutils.h	Sat Feb 02 21:20:08 2013 +0100
@@ -359,7 +359,7 @@
  *                    should be shown. This can be @c NULL.
  * @param user_data  The data to be passed to the filter_func function.
  */
-void pidgin_setup_screenname_autocomplete_with_filter(GtkWidget *entry, GtkWidget *optmenu, PidginFilterBuddyCompletionEntryFunc filter_func, gpointer user_data);
+void pidgin_setup_screenname_autocomplete(GtkWidget *entry, GtkWidget *optmenu, PidginFilterBuddyCompletionEntryFunc filter_func, gpointer user_data);
 
 /**
  * The default filter function for username autocomplete.
--- a/pidgin/gtkwebviewtoolbar.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/gtkwebviewtoolbar.c	Sat Feb 02 21:20:08 2013 +0100
@@ -579,7 +579,7 @@
 
 	name = strrchr(filename, G_DIR_SEPARATOR) + 1;
 
-	id = purple_imgstore_add_with_id(filedata, size, name);
+	id = purple_imgstore_new_with_id(filedata, size, name);
 
 	if (id == 0) {
 		buf = g_strdup_printf(_("Failed to store image: %s\n"), filename);
--- a/pidgin/minidialog.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/minidialog.c	Sat Feb 02 21:20:08 2013 +0100
@@ -145,16 +145,6 @@
 	g_object_set(G_OBJECT(mini_dialog), "enable-description-markup", TRUE, NULL);
 }
 
-gboolean
-pidgin_mini_dialog_links_supported()
-{
-#if GTK_CHECK_VERSION(2,18,0)
-	return TRUE;
-#else
-	return FALSE;
-#endif
-}
-
 void pidgin_mini_dialog_set_link_callback(PidginMiniDialog *mini_dialog, GCallback cb, gpointer user_data)
 {
 	g_signal_connect(PIDGIN_MINI_DIALOG_GET_PRIVATE(mini_dialog)->desc, "activate-link", cb, user_data);
--- a/pidgin/minidialog.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/minidialog.h	Sat Feb 02 21:20:08 2013 +0100
@@ -144,11 +144,6 @@
  */
 void pidgin_mini_dialog_enable_description_markup(PidginMiniDialog *mini_dialog);
 
-/** Mini-dialogs support hyperlinks in their description
- *  (you should first call pidgin_mini_dialog_enable_description_markup() on a given
- *  dialog to enable them). */
-gboolean pidgin_mini_dialog_links_supported(void);
-
 /** Sets a callback which gets invoked when a hyperlink in the dialog's description is clicked on.
  *  @param mini_dialog a mini-dialog
  *  @param cb the callback to invoke
--- a/pidgin/pidgin-3.pc.in	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/pidgin-3.pc.in	Sat Feb 02 21:20:08 2013 +0100
@@ -11,5 +11,5 @@
 Name: Pidgin
 Description: Pidgin is a GTK2-based instant messenger application.
 Version: @VERSION@
-Requires: gtk+-2.0 purple-3
+Requires: @GTK_PC_MODULE@ purple-3
 Cflags: -I${includedir}
--- a/pidgin/pidgin.h	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/pidgin.h	Sat Feb 02 21:20:08 2013 +0100
@@ -60,22 +60,5 @@
 #define PIDGIN_HIG_BORDER        12
 #define PIDGIN_HIG_BOX_SPACE      6
 
-#if !GTK_CHECK_VERSION(2,16,0) || !defined(PIDGIN_DISABLE_DEPRECATED)
-/*
- * Older versions of GNOME defaulted to using an asterisk as the invisible
- * character.  But this is ugly and we want to use something nicer.
- *
- * The default invisible character was changed in GNOME revision 21446
- * (GTK+ 2.16) from an asterisk to the first available character out of
- * 0x25cf, 0x2022, 0x2731, 0x273a.  See GNOME bugs 83935 and 307304 for
- * discussion leading up to the change.
- *
- * Here's the change:
- * http://svn.gnome.org/viewvc/gtk%2B?view=revision&revision=21446
- *
- */
-#define PIDGIN_INVISIBLE_CHAR (gunichar)0x25cf
-#endif /* Less than GTK+ 2.16 */
-
 #endif /* _PIDGIN_H_ */
 
--- a/pidgin/pidginstock.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/pidginstock.c	Sat Feb 02 21:20:08 2013 +0100
@@ -67,7 +67,7 @@
 	{ PIDGIN_STOCK_IGNORE,          NULL,      GTK_STOCK_DIALOG_ERROR     },
 	{ PIDGIN_STOCK_INVITE,          NULL,      GTK_STOCK_JUMP_TO          },
 	{ PIDGIN_STOCK_MODIFY,          NULL,      GTK_STOCK_PREFERENCES      },
-	{ PIDGIN_STOCK_ADD,             NULL,	   GTK_STOCK_ADD			  },
+	{ PIDGIN_STOCK_ADD,             NULL,	   GTK_STOCK_ADD              },
 	{ PIDGIN_STOCK_PAUSE,           NULL,      GTK_STOCK_MEDIA_PAUSE      },
 	{ PIDGIN_STOCK_POUNCE,          NULL,      GTK_STOCK_REDO             },
 	{ PIDGIN_STOCK_OPEN_MAIL,       NULL,      GTK_STOCK_JUMP_TO          },
@@ -80,17 +80,17 @@
 
 static const GtkStockItem stock_items[] =
 {
-	{ PIDGIN_STOCK_ALIAS,               N_("_Alias"),      0, 0, NULL },
-	{ PIDGIN_STOCK_CHAT,                N_("_Join"),       0, 0, NULL },
-	{ PIDGIN_STOCK_CLOSE_TABS,          N_("Close _tabs"), 0, 0, NULL },
-	{ PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW, N_("I_M"),         0, 0, NULL },
-	{ PIDGIN_STOCK_TOOLBAR_USER_INFO,   N_("_Get Info"),   0, 0, NULL },
-	{ PIDGIN_STOCK_INVITE,              N_("_Invite"),     0, 0, NULL },
-	{ PIDGIN_STOCK_MODIFY,              N_("_Modify..."),  0, 0, NULL },
-	{ PIDGIN_STOCK_ADD,                 N_("_Add..."),     0, 0, NULL },
-	{ PIDGIN_STOCK_OPEN_MAIL,           N_("_Open Mail"),  0, 0, NULL },
-	{ PIDGIN_STOCK_PAUSE,               N_("_Pause"),      0, 0, NULL },
-	{ PIDGIN_STOCK_EDIT,                N_("_Edit"),       0, 0, NULL }
+	{ PIDGIN_STOCK_ALIAS,               N_("_Alias"),      0, 0, PACKAGE },
+	{ PIDGIN_STOCK_CHAT,                N_("_Join"),       0, 0, PACKAGE },
+	{ PIDGIN_STOCK_CLOSE_TABS,          N_("Close _tabs"), 0, 0, PACKAGE },
+	{ PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW, N_("I_M"),         0, 0, PACKAGE },
+	{ PIDGIN_STOCK_TOOLBAR_USER_INFO,   N_("_Get Info"),   0, 0, PACKAGE },
+	{ PIDGIN_STOCK_INVITE,              N_("_Invite"),     0, 0, PACKAGE },
+	{ PIDGIN_STOCK_MODIFY,              N_("_Modify..."),  0, 0, PACKAGE },
+	{ PIDGIN_STOCK_ADD,                 N_("_Add..."),     0, 0, PACKAGE },
+	{ PIDGIN_STOCK_OPEN_MAIL,           N_("_Open Mail"),  0, 0, PACKAGE },
+	{ PIDGIN_STOCK_PAUSE,               N_("_Pause"),      0, 0, PACKAGE },
+	{ PIDGIN_STOCK_EDIT,                N_("_Edit"),       0, 0, PACKAGE }
 };
 
 typedef struct {
--- a/pidgin/pidgintooltip.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/pidgintooltip.c	Sat Feb 02 21:20:08 2013 +0100
@@ -61,22 +61,15 @@
 static void
 initialize_tooltip_delay()
 {
-#if GTK_CHECK_VERSION(2,14,0)
 	GtkSettings *settings;
-#endif
 
 	if (tooltip_delay != -1)
 		return;
 
-#if GTK_CHECK_VERSION(2,14,0)
 	settings = gtk_settings_get_default();
 
 	g_object_get(settings, "gtk-enable-tooltips", &enable_tooltips, NULL);
 	g_object_get(settings, "gtk-tooltip-timeout", &tooltip_delay, NULL);
-#else
-	tooltip_delay = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/tooltip_delay");
-	enable_tooltips = (tooltip_delay != 0);
-#endif
 }
 
 static void
--- a/pidgin/pixmaps/Makefile.am	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/pixmaps/Makefile.am	Sat Feb 02 21:20:08 2013 +0100
@@ -297,6 +297,7 @@
 		protocols/48/bonjour.png \
 		protocols/48/facebook.png \
 		protocols/48/gadu-gadu.png \
+		protocols/48/google-talk.png \
 		protocols/48/novell.png \
 		protocols/48/icq.png \
 		protocols/48/irc.png \
Binary file pidgin/pixmaps/protocols/48/google-talk.png has changed
--- a/pidgin/plugins/Makefile.am	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/plugins/Makefile.am	Sat Feb 02 21:20:08 2013 +0100
@@ -45,7 +45,6 @@
 sendbutton_la_LDFLAGS       = -module -avoid-version
 spellchk_la_LDFLAGS         = -module -avoid-version
 themeedit_la_LDFLAGS        = -module -avoid-version
-vvconfig_la_LDFLAGS         = -module -avoid-version
 webkit_la_LDFLAGS           = -module -avoid-version
 xmppconsole_la_LDFLAGS      = -module -avoid-version
 
--- a/pidgin/plugins/cap/cap.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/plugins/cap/cap.c	Sat Feb 02 21:20:08 2013 +0100
@@ -43,7 +43,7 @@
 	int threshold = purple_prefs_get_int("/plugins/gtk/cap/threshold");
 	int min_minute = (current_minute - threshold) % 1440;
 	int max_minute = (current_minute + threshold) % 1440;
-	char *sql;
+	char *sql, sta_id = NULL;
 	sqlite3_stmt *stmt = NULL;
 	const char *tail = NULL;
 	int rc;
@@ -94,7 +94,9 @@
 	sqlite3_free(sql);
 
 
-	if(strcmp(purple_status_get_id(get_status_for(buddy)), "offline") == 0) {
+	sta_id = purple_status_get_id(get_status_for(buddy));
+
+	if(sta_id && !strcmp(sta_id, "offline")) {
 		/* This is kind of stupid, change it. */
 		if(prediction == 1.0f)
 			prediction = 0.0f;
--- a/pidgin/plugins/convcolors.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/plugins/convcolors.c	Sat Feb 02 21:20:08 2013 +0100
@@ -198,12 +198,8 @@
 {
 	if (response == GTK_RESPONSE_OK)
 	{
-#if GTK_CHECK_VERSION(2,14,0)
 		GtkWidget *colorsel =
 			gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(color_dialog));
-#else
-		GtkWidget *colorsel = GTK_COLOR_SELECTION_DIALOG(color_dialog)->colorsel;
-#endif
 		GdkColor color;
 		char colorstr[8];
 		char tmp[128];
@@ -237,15 +233,9 @@
 	g_snprintf(tmp, sizeof(tmp), "%s/color", data);
 	if (gdk_color_parse(purple_prefs_get_string(tmp), &color))
 	{
-#if GTK_CHECK_VERSION(2,14,0)
 		gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(
 			gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(color_dialog))),
 			&color);
-#else
-		gtk_color_selection_set_current_color(
-			GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(color_dialog)->colorsel),
-			&color);
-#endif
 	}
 
 	gtk_window_present(GTK_WINDOW(color_dialog));
--- a/pidgin/plugins/disco/xmppdisco.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/plugins/disco/xmppdisco.c	Sat Feb 02 21:20:08 2013 +0100
@@ -265,7 +265,7 @@
 	g_return_val_if_fail(str != NULL, "");
 
 	for ( ; disco_type_mappings[i].from; ++i) {
-		if (!strcasecmp(str, disco_type_mappings[i].from))
+		if (!g_ascii_strcasecmp(str, disco_type_mappings[i].from))
 			return disco_type_mappings[i].to;
 	}
 
--- a/pidgin/plugins/notify.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/plugins/notify.c	Sat Feb 02 21:20:08 2013 +0100
@@ -96,16 +96,10 @@
 #include "gtkplugin.h"
 #include "gtkutils.h"
 
-#ifndef _WIN32
-#include <X11/Xatom.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#endif
-
 #define NOTIFY_PLUGIN_ID "gtk-x11-notify"
 
 static PurplePlugin *my_plugin = NULL;
-#ifndef _WIN32
+#ifdef HAVE_X11
 static GdkAtom _Cardinal = GDK_NONE;
 static GdkAtom _PurpleUnseenCount = GDK_NONE;
 #endif
@@ -525,7 +519,7 @@
 static void
 handle_count_xprop(PidginWindow *purplewin)
 {
-#ifndef _WIN32
+#ifdef HAVE_X11
 	guint count;
 	GtkWidget *window;
 	GdkWindow *gdkwin;
@@ -542,11 +536,7 @@
 	}
 
 	count = count_messages(purplewin);
-#if GTK_CHECK_VERSION(2,14,0)
 	gdkwin = gtk_widget_get_window(window);
-#else
-	gdkwin = window->window;
-#endif
 
 	gdk_property_change(gdkwin, _PurpleUnseenCount, _Cardinal, 32,
 	                    GDK_PROP_MODE_REPLACE, (guchar *) &count, 1);
@@ -757,7 +747,7 @@
 	g_signal_connect(G_OBJECT(toggle), "toggled",
 	                 G_CALLBACK(method_toggle_cb), "method_count");
 
-#ifndef _WIN32
+#ifdef HAVE_X11
 	/* Count xprop method button */
 	toggle = gtk_check_button_new_with_mnemonic(_("Insert count of new message into _X property"));
 	gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0);
--- a/pidgin/plugins/perl/common/Makefile.mingw	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/plugins/perl/common/Makefile.mingw	Sat Feb 02 21:20:08 2013 +0100
@@ -102,7 +102,7 @@
 $(C_FILES): $(PIDGIN_CONFIG_H)
 
 $(TARGET).dll: $(PIDGIN_DLL).a $(PURPLE_PERL_DLL).a $(OBJECTS)
-	$(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) -o $(TARGET).dll
+	$(CC) -shared $(OBJECTS) $(LIB_PATHS) $(DLL_LD_FLAGS) $(LIBS) -o $(TARGET).dll
 
 ##
 ## CLEAN
--- a/pidgin/plugins/pidginrc.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/plugins/pidginrc.c	Sat Feb 02 21:20:08 2013 +0100
@@ -244,12 +244,8 @@
 	if (response == GTK_RESPONSE_OK) {
 		GdkColor color;
 		gchar colorstr[8];
-#if GTK_CHECK_VERSION(2,14,0)
 		GtkWidget *colorsel =
 			gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(color_dialog));
-#else
-		GtkWidget *colorsel = GTK_COLOR_SELECTION_DIALOG(color_dialog)->colorsel;
-#endif
 
 		gtk_color_selection_get_current_color(GTK_COLOR_SELECTION(colorsel), &color);
 
@@ -280,13 +276,9 @@
 
 	if (pref != NULL && strcmp(pref, "")) {
 		if (gdk_color_parse(pref, &color)) {
-#if GTK_CHECK_VERSION(2,14,0)
 			gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(
 				gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(color_dialog))),
 				&color);
-#else
-			gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(color_dialog)->colorsel), &color);
-#endif
 		}
 	}
 
--- a/pidgin/plugins/relnot.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/plugins/relnot.c	Sat Feb 02 21:20:08 2013 +0100
@@ -74,7 +74,7 @@
 	if(!purple_http_response_is_successfull(response))
 		return;
 
-	changelog = purple_http_response_get_data(response);
+	changelog = purple_http_response_get_data(response, NULL);
 
 	while(changelog[i] && changelog[i] != '\n') i++;
 
@@ -113,7 +113,7 @@
 		gchar *url;
 		const char *host = "pidgin.im";
 
-		url = g_strdup_printf("http://%s/version.php?version=%s&build=%s",
+		url = g_strdup_printf("https://%s/version.php?version=%s&build=%s",
 				host,
 				purple_core_get_version(),
 #ifdef _WIN32
--- a/pidgin/plugins/spellchk.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/plugins/spellchk.c	Sat Feb 02 21:20:08 2013 +0100
@@ -319,6 +319,10 @@
 	 * Part 1 of 2: This marks . as being an inside-word character. */
 	if (c == '.')
 		return TRUE;
+	if (c == '+')
+		return TRUE;
+	if (c == '-')
+		return TRUE;
 
 	/* Avoid problems with \r, for example (SF #1289031). */
 	if (c == '\\')
--- a/pidgin/plugins/themeedit.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/plugins/themeedit.c	Sat Feb 02 21:20:08 2013 +0100
@@ -67,12 +67,8 @@
 		GdkColor color;
 		PidginBlistTheme *theme;
 
-#if GTK_CHECK_VERSION(2,14,0)
 		colorsel =
 			gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog));
-#else
-		colorsel = GTK_COLOR_SELECTION_DIALOG(dialog)->colorsel;
-#endif
 		gtk_color_selection_get_current_color(GTK_COLOR_SELECTION(colorsel), &color);
 
 		theme = pidgin_blist_get_theme();
@@ -155,16 +151,10 @@
 	}
 
 	dialog = gtk_color_selection_dialog_new(_("Select Color"));
-#if GTK_CHECK_VERSION(2,14,0)
 	if (color)
 		gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(
 			gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog))),
 			color);
-#else
-	if (color)
-		gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(dialog)->colorsel),
-				color);
-#endif
 	g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(theme_color_selected),
 			prop);
 
@@ -184,9 +174,7 @@
 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 	gtk_size_group_add_widget(sizegroup, label);
 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-#if GTK_CHECK_VERSION(2, 12, 0)
 	gtk_widget_set_tooltip_text(label, blurb);
-#endif
 
 	color = pidgin_pixbuf_button_from_stock("", GTK_STOCK_SELECT_COLOR,
 			PIDGIN_BUTTON_HORIZONTAL);
@@ -210,9 +198,7 @@
 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 	gtk_size_group_add_widget(sizegroup, label);
 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-#if GTK_CHECK_VERSION(2, 12, 0)
 	gtk_widget_set_tooltip_text(label, blurb);
-#endif
 
 	font = pidgin_pixbuf_button_from_stock("", GTK_STOCK_SELECT_FONT,
 			PIDGIN_BUTTON_HORIZONTAL);
--- a/pidgin/plugins/timestamp_format.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/plugins/timestamp_format.c	Sat Feb 02 21:20:08 2013 +0100
@@ -160,11 +160,7 @@
 			GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
 			NULL);
 	g_signal_connect_after(G_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), dialog);
-#if GTK_CHECK_VERSION(2,14,0)
 	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), frame);
-#else
-	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), frame);
-#endif
 	gtk_window_set_role(GTK_WINDOW(dialog), "plugin_config");
 	gtk_window_set_title(GTK_WINDOW(dialog), _(purple_plugin_get_name(plugin)));
 	gtk_widget_show_all(dialog);
@@ -183,13 +179,8 @@
 	if (!GTK_IS_IMHTML(view))
 		return TRUE;
 
-#if GTK_CHECK_VERSION(2,14,0)
 	if (!gdk_window_get_pointer(gtk_widget_get_window(GTK_WIDGET(view)), &cx, &cy, NULL))
 		return TRUE;
-#else
-	if (!gdk_window_get_pointer(GTK_WIDGET(view)->window, &cx, &cy, NULL))
-		return TRUE;
-#endif
 
 	buffer = gtk_text_view_get_buffer(view);
 
--- a/pidgin/plugins/xmppconsole.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/plugins/xmppconsole.c	Sat Feb 02 21:20:08 2013 +0100
@@ -291,11 +291,7 @@
 #endif
 	gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
 	gtk_container_set_border_width(GTK_CONTAINER(dialog), 12);
-#if GTK_CHECK_VERSION(2,14,0)
 	vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
-#else
-	vbox = GTK_DIALOG(dialog)->vbox;
-#endif
 
 	hbox = gtk_hbox_new(FALSE, 3);
 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
@@ -381,11 +377,7 @@
 #endif
 	gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
 	gtk_container_set_border_width(GTK_CONTAINER(dialog), 12);
-#if GTK_CHECK_VERSION(2,14,0)
 	vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
-#else
-	vbox = GTK_DIALOG(dialog)->vbox;
-#endif
 
 	hbox = gtk_hbox_new(FALSE, 3);
 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
@@ -541,11 +533,7 @@
 #endif
 	gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
 	gtk_container_set_border_width(GTK_CONTAINER(dialog), 12);
-#if GTK_CHECK_VERSION(2,14,0)
 	vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
-#else
-	vbox = GTK_DIALOG(dialog)->vbox;
-#endif
 
 	hbox = gtk_hbox_new(FALSE, 3);
 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
--- a/pidgin/smileyparser.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/smileyparser.c	Sat Feb 02 21:20:08 2013 +0100
@@ -151,7 +151,7 @@
 	}
 
 	/* now for each theme smiley, observe that this does look nasty */
-	if (!current_smiley_theme || !(current_smiley_theme->list)) {
+	if (!current_smiley_theme) {
 		purple_debug_warning("smiley", "theme does not exist\n");
 		return temp;
 	}
--- a/pidgin/themes/Contents/Resources/Content.html	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/themes/Contents/Resources/Content.html	Sat Feb 02 21:20:08 2013 +0100
@@ -1,6 +1,6 @@
 <div class="x-container %messageClasses% %messageDirection%">
 	<abbr class="x-time" title="%time{yyyy-MM-ddTHH:mm:ssZZ}%">(%time%)</abbr>
-	<div class="x-sender">%sender%:</div>
-	<div class="x-message">%message%</div>
+	<span class="x-sender">%sender%:</span>
+	<span class="x-message">%message%</span>
 </div>
 <div id="insert"></div>
--- a/pidgin/themes/Contents/Resources/Incoming/Content.html	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/themes/Contents/Resources/Incoming/Content.html	Sat Feb 02 21:20:08 2013 +0100
@@ -1,8 +1,8 @@
 <div class="x-container %messageClasses% %messageDirection%">
-	<div class="x-header" style="color: %senderColor%;">
+	<span class="x-header" style="color: %senderColor%;">
 		<abbr class="x-time" title="%time{yyyy-MM-ddTHH:mm:ssZZ}%">(%time%)</abbr>
-		<div class="x-sender">%sender%:</div>
-	</div>
-	<div class="x-message">%message%</div>
+		<span class="x-sender">%sender%:</span>
+	</span>
+	<span class="x-message">%message%</span>
 </div>
 <div id="insert"></div>
--- a/pidgin/themes/Contents/Resources/Status.html	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/themes/Contents/Resources/Status.html	Sat Feb 02 21:20:08 2013 +0100
@@ -1,5 +1,7 @@
 <div class="x-status_container %messageClasses% %messageDirection% %status%">
-	<abbr class="x-time" title="%time{yyyy-MM-ddTHH:mm:ssZZ}%">%time%</abbr>
-	<div class="x-message">%message%</div>
+	<span class="x-header">
+		<abbr class="x-time" title="%time{yyyy-MM-ddTHH:mm:ssZZ}%">%time%</abbr>
+	</span>
+	<span class="x-message">%message%</span>
 </div>
 <div id="insert"></div>
--- a/pidgin/themes/Contents/Resources/main.css	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/themes/Contents/Resources/main.css	Sat Feb 02 21:20:08 2013 +0100
@@ -29,12 +29,6 @@
 	font-weight: bold;
 }
 
-.x-time, .x-sender
-{
-	float: left;
-	margin-right: 4px;
-}
-
 .x-message p
 {
 	margin: 0;
--- a/pidgin/win32/gtkwin32dep.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/win32/gtkwin32dep.c	Sat Feb 02 21:20:08 2013 +0100
@@ -171,10 +171,19 @@
 }
 
 void winpidgin_notify_uri(const char *uri) {
-	/* We'll allow whatever URI schemes are supported by the
-	 * default http browser.
+	/* Allow a few commonly used and "safe" schemes to go to the specific
+	 * class handlers and send everything else to the default http browser.
+	 * This isn't optimal, but should cover the most common cases. I didn't
+	 * see any better secure solutions when I did some research.
 	 */
-	winpidgin_shell_execute(uri, "open", "http");
+	gchar *scheme = g_uri_parse_scheme(uri);
+	if (scheme && (g_ascii_strcasecmp(scheme, "https") == 0
+			|| g_ascii_strcasecmp(scheme, "ftp") == 0
+			|| g_ascii_strcasecmp(scheme, "mailto") == 0))
+		winpidgin_shell_execute(uri, "open", scheme);
+	else
+		winpidgin_shell_execute(uri, "open", "http");
+	g_free(scheme);
 }
 
 #define PIDGIN_WM_FOCUS_REQUEST (WM_APP + 13)
@@ -377,7 +386,8 @@
 }
 
 void winpidgin_init(HINSTANCE hint) {
-	FARPROC proc;
+	typedef void (__cdecl* LPFNSETLOGFILE)(const LPCSTR);
+	LPFNSETLOGFILE MySetLogFile;
 	gchar *exchndl_dll_path;
 
 	purple_debug_info("winpidgin", "winpidgin_init start\n");
@@ -385,10 +395,10 @@
 	exe_hInstance = hint;
 
 	exchndl_dll_path = g_build_filename(wpurple_install_dir(), "exchndl.dll", NULL);
-	proc = wpurple_find_and_loadproc(exchndl_dll_path, "SetLogFile");
+	MySetLogFile = (LPFNSETLOGFILE) wpurple_find_and_loadproc(exchndl_dll_path, "SetLogFile");
 	g_free(exchndl_dll_path);
 	exchndl_dll_path = NULL;
-	if (proc) {
+	if (MySetLogFile) {
 		gchar *debug_dir, *locale_debug_dir;
 
 		debug_dir = g_build_filename(purple_user_dir(), "pidgin.RPT", NULL);
@@ -396,7 +406,7 @@
 
 		purple_debug_info("winpidgin", "Setting exchndl.dll LogFile to %s\n", debug_dir);
 
-		(proc)(locale_debug_dir);
+		MySetLogFile(locale_debug_dir);
 
 		g_free(debug_dir);
 		g_free(locale_debug_dir);
--- a/pidgin/win32/nsis/generate_gtk_zip.sh	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/win32/nsis/generate_gtk_zip.sh	Sat Feb 02 21:20:08 2013 +0100
@@ -2,31 +2,57 @@
 # Script to generate zip file for GTK+ runtime to be included in Pidgin installer
 
 PIDGIN_BASE=$1
+GPG_SIGN=$2
 
 if [ ! -e $PIDGIN_BASE/ChangeLog ]; then
 	echo $(basename $0) must must have the pidgin base dir specified as a parameter.
 	exit 1
 fi
 
-STAGE_DIR=$PIDGIN_BASE/pidgin/win32/nsis/gtk_runtime_stage
+STAGE_DIR=`readlink -f $PIDGIN_BASE/pidgin/win32/nsis/gtk_runtime_stage`
 #Subdirectory of $STAGE_DIR
 INSTALL_DIR=Gtk
 CONTENTS_FILE=$INSTALL_DIR/CONTENTS
+PIDGIN_VERSION=$( < $PIDGIN_BASE/VERSION )
 
 #This needs to be changed every time there is any sort of change.
-BUNDLE_VERSION=2.16.6.0
+BUNDLE_VERSION=2.16.6.1
+BUNDLE_SHA1SUM=5e16b7efb11943e8c80bc390f6c38df904fd36ed
+ZIP_FILE="$PIDGIN_BASE/pidgin/win32/nsis/gtk-runtime-$BUNDLE_VERSION.zip"
 
-ATK="http://ftp.acc.umu.se/pub/gnome/binaries/win32/atk/1.26/atk_1.26.0-1_win32.zip ATK 1.26.0-1"
-CAIRO="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/cairo_1.8.10-1_win32.zip Cairo 1.8.10-1"
-EXPAT="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/expat_2.0.1-1_win32.zip Expat 2.0.1-1"
-FONTCONFIG="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/fontconfig_2.8.0-2_win32.zip Fontconfig 2.8.0-2"
-FREETYPE="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/freetype_2.3.11-2_win32.zip Freetype 2.3.11-2"
-GETTEXT="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/gettext-runtime-0.17-1.zip Gettext 0.17-1"
-GLIB="http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.20/glib_2.20.5-1_win32.zip Glib 2.20.5-1"
-GTK="http://ftp.acc.umu.se/pub/gnome/binaries/win32/gtk+/2.16/gtk+_2.16.6-2_win32.zip GTK+ 2.16.6-2"
-LIBPNG="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/libpng_1.4.0-1_win32.zip libpng 1.4.0-1"
-PANGO="http://ftp.gnome.org/pub/gnome/binaries/win32/pango/1.26/pango_1.26.2-1_win32.zip Pango 1.26.2-1"
-ZLIB="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/zlib-1.2.3.zip zlib 1.2.3"
+#Download the existing file (so that we distribute the exact same file for all releases with the same bundle version)
+FILE="$ZIP_FILE"
+if [ ! -e "$FILE" ]; then
+	wget "https://pidgin.im/win32/download_redir.php?version=$PIDGIN_VERSION&gtk_version=$BUNDLE_VERSION&dl_pkg=gtk" -O "$FILE"
+fi
+CHECK_SHA1SUM=`sha1sum $FILE`
+CHECK_SHA1SUM=${CHECK_SHA1SUM%%\ *}
+if [ "$CHECK_SHA1SUM" != "$BUNDLE_SHA1SUM" ]; then
+	echo "sha1sum ($CHECK_SHA1SUM) for $FILE doesn't match expected value of $BUNDLE_SHA1SUM"
+	# Allow "devel" versions to build their own bundles if the download doesn't succeed
+	if [[ "$PIDGIN_VERSION" == *"devel" ]]; then
+		echo "Continuing GTK+ Bundle creation for development version of Pidgin"
+	else
+		exit 1
+	fi
+else
+	exit 0
+fi
+
+
+ATK="http://ftp.gnome.org/pub/gnome/binaries/win32/atk/1.32/atk_1.32.0-2_win32.zip ATK 1.32.0-2 sha1sum:3c31c9d6b19af840e2bd8ccbfef4072a6548dc4e"
+#Cairo 1.10.2 has a bug that can be seen when selecting text
+#CAIRO="http://ftp.gnome.org/pub/GNOME/binaries/win32/dependencies/cairo_1.10.2-2_win32.zip Cairo 1.10.2-2 sha1sum:d44cd66a9f4d7d29a8f2c28d1c1c5f9b0525ba44"
+CAIRO="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/cairo_1.8.10-1_win32.zip Cairo 1.8.10-1 sha1sum:a08476cccd807943958610977a138c4d6097c7b8"
+EXPAT="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/expat_2.1.0-1_win32.zip Expat 2.1.0-1 gpg:0x71D4DDE53F188CBE"
+FONTCONFIG="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/fontconfig_2.8.0-2_win32.zip Fontconfig 2.8.0-2 sha1sum:37a3117ea6cc50c8a88fba9b6018f35a04fa71ce"
+FREETYPE="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/freetype_2.4.10-1_win32.zip Freetype 2.4.10-1 gpg:0x71D4DDE53F188CBE"
+GETTEXT="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/gettext-runtime_0.18.1.1-2_win32.zip Gettext 0.18.1.1-2 sha1sum:a7cc1ce2b99b408d1bbea9a3b4520fcaf26783b3"
+GLIB="http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.28/glib_2.28.8-1_win32.zip Glib 2.28.8-1 sha1sum:5d158f4c77ca0b5508e1042955be573dd940b574"
+GTK="http://ftp.acc.umu.se/pub/gnome/binaries/win32/gtk+/2.16/gtk+_2.16.6-2_win32.zip GTK+ 2.16.6-2 sha1sum:012853e6de814ebda0cc4459f9eed8ae680e6d17"
+LIBPNG="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/libpng_1.4.12-1_win32.zip libpng 1.4.12-1 gpg:0x71D4DDE53F188CBE"
+PANGO="http://ftp.gnome.org/pub/gnome/binaries/win32/pango/1.29/pango_1.29.4-1_win32.zip Pango 1.29.4-1 sha1sum:3959319bd04fbce513458857f334ada279b8cdd4"
+ZLIB="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/zlib_1.2.5-2_win32.zip zlib 1.2.5-2 sha1sum:568907188761df2d9309196e447d91bbc5555d2b"
 
 ALL="ATK CAIRO EXPAT FONTCONFIG FREETYPE GETTEXT GLIB GTK LIBPNG PANGO ZLIB"
 
@@ -41,11 +67,40 @@
 
 function download_and_extract {
 	URL=${1%%\ *}
-	NAME=${1#*\ }
+	VALIDATION=${1##*\ }
+	NAME=${1%\ *}
+	NAME=${NAME#*\ }
 	FILE=$(basename $URL)
 	if [ ! -e $FILE ]; then
 		echo Downloading $NAME
-		wget $URL || return 1
+		wget $URL || exit 1
+	fi
+	VALIDATION_TYPE=${VALIDATION%%:*}
+	VALIDATION_VALUE=${VALIDATION##*:}
+	if [ $VALIDATION_TYPE == 'sha1sum' ]; then
+		CHECK_SHA1SUM=`sha1sum $FILE`
+		CHECK_SHA1SUM=${CHECK_SHA1SUM%%\ *}
+		if [ "$CHECK_SHA1SUM" != "$VALIDATION_VALUE" ]; then
+			echo "sha1sum ($CHECK_SHA1SUM) for $FILE doesn't match expected value of $VALIDATION_VALUE"
+			exit 1
+		fi
+	elif [ $VALIDATION_TYPE == 'gpg' ]; then
+		if [ ! -e "$FILE.asc" ]; then
+			echo Downloading GPG key for $NAME
+			wget "$URL.asc" || exit 1
+		fi
+		#Use our own keyring to avoid adding stuff to the main keyring
+		#This doesn't use $GPG_SIGN because we don't this validation to be bypassed when people are skipping signing output
+		GPG_BASE="gpg -q --keyring $STAGE_DIR/$VALIDATION_VALUE-keyring.gpg" 
+		if [[ ! -e $STAGE_DIR/$VALIDATION_VALUE-keyring.gpg \
+				|| `$GPG_BASE --list-keys "$VALIDATION_VALUE" > /dev/null && echo -n "0"` -ne 0 ]]; then
+			touch $STAGE_DIR/$VALIDATION_VALUE-keyring.gpg
+		       	$GPG_BASE --no-default-keyring --keyserver pgp.mit.edu --recv-key "$VALIDATION_VALUE" || exit 1
+		fi
+		$GPG_BASE --verify "$FILE.asc" || (echo "$FILE failed signature verification"; exit 1) || exit 1
+	else
+		echo "Unrecognized validation type of $VALIDATION_TYPE"
+		exit 1
 	fi
 	EXTENSION=${FILE##*.}
 	#This is an OpenSuSE build service RPM
@@ -77,7 +132,9 @@
 done
 
 #Generate zip file to be included in installer
-zip -9 -r ../gtk-runtime-$BUNDLE_VERSION.zip Gtk
+rm -f $ZIP_FILE
+zip -9 -r $ZIP_FILE Gtk
+($GPG_SIGN -ab $ZIP_FILE && $GPG_SIGN --verify $ZIP_FILE.asc) || exit 1
 
 exit 0
 
--- a/pidgin/win32/nsis/pidgin-installer.nsi	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/win32/nsis/pidgin-installer.nsi	Sat Feb 02 21:20:08 2013 +0100
@@ -34,7 +34,6 @@
 
 !include "MUI.nsh"
 !include "Sections.nsh"
-!include "WinVer.nsh"
 !include "LogicLib.nsh"
 !include "Memento.nsh"
 
@@ -71,7 +70,7 @@
 !define PERL_REG_KEY				"SOFTWARE\Perl"
 !define PERL_DLL				"perl510.dll"
 
-!define DOWNLOADER_URL				"http://pidgin.im/win32/download_redir.php?version=${PIDGIN_VERSION}"
+!define DOWNLOADER_URL				"https://pidgin.im/win32/download_redir.php?version=${PIDGIN_VERSION}"
 
 !define MEMENTO_REGISTRY_ROOT			HKLM
 !define MEMENTO_REGISTRY_KEY			"${PIDGIN_UNINSTALL_KEY}"
@@ -93,6 +92,7 @@
 ;Reserve files used in .onInit
 ;for faster start-up
 ReserveFile "${NSISDIR}\Plugins\System.dll"
+ReserveFile "${NSISDIR}\Plugins\UserInfo.dll"
 !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
 !insertmacro MUI_RESERVEFILE_LANGDLL
 
@@ -118,8 +118,8 @@
 
   ;Finish Page config
   !define MUI_FINISHPAGE_NOAUTOCLOSE
-  !define MUI_FINISHPAGE_RUN			"$INSTDIR\pidgin.exe"
-  !define MUI_FINISHPAGE_RUN_NOTCHECKED
+  ;!define MUI_FINISHPAGE_RUN			"$INSTDIR\pidgin.exe"
+  ;!define MUI_FINISHPAGE_RUN_NOTCHECKED
   !define MUI_FINISHPAGE_LINK			$(PIDGINFINISHVISITWEBSITE)
   !define MUI_FINISHPAGE_LINK_LOCATION		"http://pidgin.im"
 
@@ -148,13 +148,6 @@
   !include "${PIDGIN_NSIS_INCLUDE_PATH}\langmacros.nsh"
 
 ;--------------------------------
-;Reserve Files
-  ; Only need this if using bzip2 compression
-
-  !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
-  !insertmacro MUI_RESERVEFILE_LANGDLL
-  ReserveFile "${NSISDIR}\Plugins\UserInfo.dll"
-
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Start Install Sections ;;
@@ -268,9 +261,18 @@
   NSISdl::download /TIMEOUT=10000 $R2 $R1
   Pop $R0
   ;StrCmp $R0 "cancel" done
-  StrCmp $R0 "success" +2
+  StrCmp $R0 "success" 0 prompt_retry
+
+  Push "${GTK_SHA1SUM}"
+  Push "$R1" ; Filename
+  Call CheckSHA1Sum
+  Pop $R0
+
+  StrCmp "$R0" "0" extract
+    prompt_retry:
     MessageBox MB_RETRYCANCEL "$(PIDGINGTKDOWNLOADERROR)" /SD IDCANCEL IDRETRY retry IDCANCEL done
 
+  extract:
 !endif
 
   ;Delete the old Gtk directory
@@ -282,7 +284,9 @@
   StrCmp $R0 "success" +2
     DetailPrint "$R0" ;print error message to log
 
+!ifndef OFFLINE_INSTALLER
   done:
+!endif
 SectionEnd ; end of GTK+ section
 
 ;--------------------------------
@@ -335,7 +339,7 @@
     Delete "$INSTDIR\plugins\liboscar.dll"
     Delete "$INSTDIR\plugins\libjabber.dll"
 
-    File /r /x locale ..\..\..\${PIDGIN_INSTALL_DIR}\*.*
+    File /r /x locale /x Gtk ..\..\..\${PIDGIN_INSTALL_DIR}\*.*
 
     ; Check if Perl is installed, if so add it to the AppPaths
     ReadRegStr $R2 HKLM ${PERL_REG_KEY} ""
@@ -351,21 +355,6 @@
 
     perl_done:
 
-    ; If this is under NT4, delete the SILC support stuff
-    ; there is a bug that will prevent any account from connecting
-    ; See https://lists.silcnet.org/pipermail/silc-devel/2005-January/001588.html
-    ; Also, remove the GSSAPI SASL plugin and associated files as they aren't
-    ; compatible with NT4.
-    ${If} ${IsNT}
-    ${AndIf} ${IsWinNT4}
-      ;SILC
-      Delete "$INSTDIR\plugins\libsilc.dll"
-      Delete "$INSTDIR\libsilcclient-1-1-3.dll"
-      Delete "$INSTDIR\libsilc-1-1-2.dll"
-      ;GSSAPI
-      Delete "$INSTDIR\sasl2\saslGSSAPI.dll"
-    ${EndIf}
-
     SetOutPath "$INSTDIR"
 
     ; If we don't have install rights we're done
@@ -467,9 +456,18 @@
   NSISdl::download /TIMEOUT=10000 $R2 $R1
   Pop $R0
   StrCmp $R0 "cancel" done
-  StrCmp $R0 "success" +2
+  StrCmp $R0 "success" 0 prompt_retry
+
+  Push "${DEBUG_SYMBOLS_SHA1SUM}"
+  Push "$R1" ; Filename
+  Call CheckSHA1Sum
+  Pop $R0
+
+  StrCmp "$R0" "0" extract
+    prompt_retry:
     MessageBox MB_RETRYCANCEL "$(PIDGINDEBUGSYMBOLSERROR)" /SD IDCANCEL IDRETRY retry IDCANCEL done
 
+  extract:
 !endif
 
   SetOutPath "$INSTDIR"
@@ -478,7 +476,9 @@
   StrCmp $R0 "success" +2
     DetailPrint "$R0" ;print error message to log
 
+!ifndef OFFLINE_INSTALLER
   done:
+!endif
 SectionEnd
 
 ;--------------------------------
@@ -638,11 +638,11 @@
     Delete "$INSTDIR\libsasl.dll"
     Delete "$INSTDIR\libsilc-1-1-2.dll"
     Delete "$INSTDIR\libsilcclient-1-1-3.dll"
+    Delete "$INSTDIR\libssp-0.dll"
     Delete "$INSTDIR\libxml2-2.dll"
     Delete "$INSTDIR\libymsg.dll"
     Delete "$INSTDIR\nss3.dll"
     Delete "$INSTDIR\nssutil3.dll"
-    Delete "$INSTDIR\nssckbi.dll"
     Delete "$INSTDIR\pidgin.dll"
     Delete "$INSTDIR\pidgin.exe"
     Delete "$INSTDIR\smime3.dll"
@@ -1300,3 +1300,40 @@
   Pop $R0
   Exch $R1
 FunctionEnd
+
+!ifndef OFFLINE_INSTALLER
+; Input Stack: Filename, SHA1sum
+; Output Return Code: 0=Match; 1=FileSum error; 2=Mismatch
+Function CheckSHA1Sum
+  Push $R0
+  Exch
+  Pop $R0 ;Filename
+  Push $R2
+  Exch 2
+  Pop $R2 ;SHA1sum
+  Push $R1
+
+  SHA1Plugin::FileSum "$R0"
+  Pop $R1
+  Pop $R0
+
+  StrCmp "$R1" "0" +4
+    DetailPrint "SHA1Sum calculation error: $R0"
+    IntOp $R1 0 + 1
+    Goto done
+
+  ; Compare the SHA1Sums
+  StrCmp $R2 $R0 +4
+    DetailPrint "SHA1Sum mismatch... Expected $R2; got $R0"
+    IntOp $R1 0 + 2
+    Goto done
+
+  IntOp $R1 0 + 0
+
+  done:
+  Pop $R2
+  Pop $R0
+  Exch $R1 ;$R1 has the return code
+FunctionEnd
+!endif
+
--- a/pidgin/win32/winpidgin.c	Sat Feb 02 18:29:35 2013 +0100
+++ b/pidgin/win32/winpidgin.c	Sat Feb 02 21:20:08 2013 +0100
@@ -38,9 +38,10 @@
 #include <sys/stat.h>
 #include "config.h"
 
-typedef int (CALLBACK* LPFNPIDGINMAIN)(HINSTANCE, int, char**);
-typedef void (CALLBACK* LPFNSETDLLDIRECTORY)(LPCWSTR);
-typedef BOOL (CALLBACK* LPFNATTACHCONSOLE)(DWORD);
+typedef int (__cdecl* LPFNPIDGINMAIN)(HINSTANCE, int, char**);
+typedef void (WINAPI* LPFNSETDLLDIRECTORY)(LPCWSTR);
+typedef BOOL (WINAPI* LPFNATTACHCONSOLE)(DWORD);
+typedef BOOL (WINAPI* LPFNSETPROCESSDEPPOLICY)(DWORD);
 
 static BOOL portable_mode = FALSE;
 
@@ -556,7 +557,7 @@
 	len = WideCharToMultiByte(CP_UTF8, 0, tmp1,
 			wlen, NULL, 0, NULL, NULL);
 	if (len) {
-		utf8msg = malloc(len * sizeof(char));
+		utf8msg = malloc(len);
 		len = WideCharToMultiByte(CP_UTF8, 0, tmp1,
 			wlen, utf8msg, len, NULL, NULL);
 	}
@@ -642,16 +643,24 @@
 		}
 	}
 
+	/* Permanently enable DEP if the OS supports it */
+	if ((hmod = GetModuleHandleW(L"kernel32.dll"))) {
+		LPFNSETPROCESSDEPPOLICY MySetProcessDEPPolicy =
+			(LPFNSETPROCESSDEPPOLICY)
+			GetProcAddress(hmod, "SetProcessDEPPolicy");
+		if (MySetProcessDEPPolicy)
+			MySetProcessDEPPolicy(1); //PROCESS_DEP_ENABLE
+	}
+
 	if (debug || help || version) {
 		/* If stdout hasn't been redirected to a file, alloc a console
 		 *  (_istty() doesn't work for stuff using the GUI subsystem) */
 		if (_fileno(stdout) == -1 || _fileno(stdout) == -2) {
 			LPFNATTACHCONSOLE MyAttachConsole = NULL;
-			if ((hmod = GetModuleHandleW(L"kernel32.dll"))) {
+			if (hmod)
 				MyAttachConsole =
 					(LPFNATTACHCONSOLE)
 					GetProcAddress(hmod, "AttachConsole");
-			}
 			if ((MyAttachConsole && MyAttachConsole(ATTACH_PARENT_PROCESS))
 					|| AllocConsole()) {
 				freopen("CONOUT$", "w", stdout);
@@ -683,31 +692,34 @@
 
 			wcscat(pidgin_dir, L"\\exchndl.dll");
 			if ((hmod = LoadLibraryW(pidgin_dir))) {
-				FARPROC proc;
+				typedef void (__cdecl* LPFNSETLOGFILE)(const LPCSTR);
+				LPFNSETLOGFILE MySetLogFile;
 				/* exchndl.dll is built without UNICODE */
 				char debug_dir[MAX_PATH];
 				printf("Loaded exchndl.dll\n");
 				/* Temporarily override exchndl.dll's logfile
 				 * to something sane (Pidgin will override it
 				 * again when it initializes) */
-				proc = GetProcAddress(hmod, "SetLogFile");
-				if (proc) {
-					if (GetTempPathA(sizeof(debug_dir) * sizeof(char), debug_dir) != 0) {
+				MySetLogFile = (LPFNSETLOGFILE) GetProcAddress(hmod, "SetLogFile");
+				if (MySetLogFile) {
+					if (GetTempPathA(sizeof(debug_dir), debug_dir) != 0) {
 						strcat(debug_dir, "pidgin.RPT");
 						printf(" Setting exchndl.dll LogFile to %s\n",
 							debug_dir);
-						(proc)(debug_dir);
+						MySetLogFile(debug_dir);
 					}
 				}
-				proc = GetProcAddress(hmod, "SetDebugInfoDir");
-				if (proc) {
+				/* The function signature for SetDebugInfoDir is the same as SetLogFile,
+				 * so we can reuse the variable */
+				MySetLogFile = (LPFNSETLOGFILE) GetProcAddress(hmod, "SetDebugInfoDir");
+				if (MySetLogFile) {
 					char *pidgin_dir_ansi = NULL;
 					/* Restore pidgin_dir to point to where the executable is */
 					pidgin_dir_start[0] = L'\0';
 					i = WideCharToMultiByte(CP_ACP, 0, pidgin_dir,
 						-1, NULL, 0, NULL, NULL);
 					if (i != 0) {
-						pidgin_dir_ansi = malloc(i * sizeof(char));
+						pidgin_dir_ansi = malloc(i);
 						i = WideCharToMultiByte(CP_ACP, 0, pidgin_dir,
 							-1, pidgin_dir_ansi, i, NULL, NULL);
 						if (i == 0) {
@@ -716,13 +728,13 @@
 						}
 					}
 					if (pidgin_dir_ansi != NULL) {
-						_snprintf(debug_dir, sizeof(debug_dir) / sizeof(char),
+						_snprintf(debug_dir, sizeof(debug_dir),
 							"%s\\pidgin-%s-dbgsym",
 							pidgin_dir_ansi,  VERSION);
-						debug_dir[sizeof(debug_dir) / sizeof(char) - 1] = '\0';
+						debug_dir[sizeof(debug_dir) - 1] = '\0';
 						printf(" Setting exchndl.dll DebugInfoDir to %s\n",
 							debug_dir);
-						(proc)(debug_dir);
+						MySetLogFile(debug_dir);
 						free(pidgin_dir_ansi);
 					}
 				}
@@ -800,7 +812,7 @@
 			int len = WideCharToMultiByte(CP_UTF8, 0, szArglist[i],
 				-1, NULL, 0, NULL, NULL);
 			if (len != 0) {
-				char *arg = malloc(len * sizeof(char));
+				char *arg = malloc(len);
 				len = WideCharToMultiByte(CP_UTF8, 0, szArglist[i],
 					-1, arg, len, NULL, NULL);
 				if (len != 0) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/ca-certs/Baltimore_CyberTrust_Root.pem	Sat Feb 02 21:20:08 2013 +0100
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
+RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
+VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
+DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
+ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
+VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
+mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
+IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
+mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
+XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
+dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
+jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
+BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
+DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
+9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
+jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
+Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
+ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
+R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
+-----END CERTIFICATE-----
--- a/share/ca-certs/Makefile.am	Sat Feb 02 18:29:35 2013 +0100
+++ b/share/ca-certs/Makefile.am	Sat Feb 02 21:20:08 2013 +0100
@@ -1,6 +1,7 @@
 CERTIFICATES = \
 		AddTrust_External_Root.pem \
 		America_Online_Root_Certification_Authority_1.pem \
+		Baltimore_CyberTrust_Root.pem \
 		CAcert_Root.pem \
 		CAcert_Class3.pem \
 		Deutsche_Telekom_Root_CA_2.pem \
@@ -14,7 +15,6 @@
 		Thawte_Premium_Server_CA.pem \
 		Thawte_Primary_Root_CA.pem \
 		ValiCert_Class_2_VA.pem \
-		Verisign_RSA_Secure_Server_CA.pem \
 		Verisign_Class3_Primary_CA.pem \
 		VeriSign_Class_3_Public_Primary_Certification_Authority_-_G2.pem \
 		VeriSign_Class_3_Public_Primary_Certification_Authority_-_G5.pem \
@@ -23,9 +23,7 @@
 EXTRA_CERTS = \
 		AOL_Member_CA.pem \
 		DigiCertHighAssuranceCA-3.pem \
-		Microsoft_Internet_Authority.pem \
 		Microsoft_Internet_Authority_2010.pem \
-		Microsoft_Secure_Server_Authority.pem \
 		Microsoft_Secure_Server_Authority_2010.pem \
 		VeriSign_Class3_Extended_Validation_CA.pem \
 		VeriSign_International_Server_Class_3_CA.pem
--- a/share/ca-certs/Microsoft_Internet_Authority.pem	Sat Feb 02 18:29:35 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFCjCCBHOgAwIBAgIEBycWdTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJV
-UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
-cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds
-b2JhbCBSb290MB4XDTA4MDIxOTE4MjcwMloXDTExMDIxOTE4MjQ1M1owJzElMCMG
-A1UEAxMcTWljcm9zb2Z0IEludGVybmV0IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcN
-AQEBBQADggIPADCCAgoCggIBAKiloatvDehDG/rQriel2AC9qmSJdvjKb2fmJf30
-K7SaC3zQu8kGQxENUEFsHsH0jmBejJ9vvn9tHZ8hGL+kORvWUVBskdMzP65rC0V0
-VeVgUYzPZ7MvrLfhh9+v3yJ7qRuf1aNgmzJg5t1AA91X+aRrFT4lRzl9BFWhQ1VS
-XaD7l6qoiyhD8FbrdLRAe61swsRmzWeXoy6NJpOBsGXaCSG1Jooylro+zkWxt97c
-NkNf/wYqoYcIXo02YpFbwreveejW9a0Lh/1z9+e9aiMtC5QnPT57GTqNINt5R0rp
-Iz4g3GJhmjXVoVF/tev5DMJuhRgPoz0W0aA3UnSmTWh2RFvgqawLqSRrKUhVjySi
-/m5s62uG5xxIftO7/6ljzS061CFoV/RBl/I3WghYp04sr4cSXWa/rL449YhBT8BJ
-jltefWCYAOcT1nA4oFXwXbl1qCUIkZ0bqwju2FGW5vl2qh6vmzcQjc3XxD0m2UqC
-yJNFa9SUgVXtUCqeOI+KqgLW01tpqZteG10byWKmppTVAvdPwHoGE0bl6wBwXldE
-f7Pn4lqu6Yp4bedP3Qv1sfp2H7D98cxSwYRt3UcXN2kjTPv+pby2fEHm9GWf3iE/
-7OtzUI7LYhP7+rGyuCYTtZKH1jDWHrTZBpnAPmrAQQHCI8/4TjF9ZQ1mqRi6x9I9
-9XGfAgMBAAGjggFvMIIBazASBgNVHRMBAf8ECDAGAQH/AgEBMFMGA1UdIARMMEow
-SAYJKwYBBAGxPgEAMDswOQYIKwYBBQUHAgEWLWh0dHA6Ly9jeWJlcnRydXN0Lm9t
-bmlyb290LmNvbS9yZXBvc2l0b3J5LmNmbTAOBgNVHQ8BAf8EBAMCAYYwgYkGA1Ud
-IwSBgTB/oXmkdzB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0
-aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAh
-BgNVBAMTGkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290ggIBpTBFBgNVHR8EPjA8
-MDqgOKA2hjRodHRwOi8vd3d3LnB1YmxpYy10cnVzdC5jb20vY2dpLWJpbi9DUkwv
-MjAxOC9jZHAuY3JsMB0GA1UdDgQWBBTG27vA2CAZkvFg/IjxWH+8G06PGjANBgkq
-hkiG9w0BAQUFAAOBgQBnSDXCyiqGmHTAEJOtZYVm/IbzGtzCY423NF6/yuccYZkm
-spJnDoh8nq3nx3P2KBEyPAqoQ1MEFC+ByQjV4AAQ9dMQALUGNRfHhFUhBeeIybYd
-bzvKOxSlIYSwO2T56+oXyDlkbQWKmHec5qzCE0lwGHslsRU/CHwhuFu2nH+CxQ==
------END CERTIFICATE-----
--- a/share/ca-certs/Microsoft_Secure_Server_Authority.pem	Sat Feb 02 18:29:35 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIGEzCCA/ugAwIBAgIKYRZtLwAEAAAAIDANBgkqhkiG9w0BAQUFADAnMSUwIwYD
-VQQDExxNaWNyb3NvZnQgSW50ZXJuZXQgQXV0aG9yaXR5MB4XDTA4MDQwOTIxMzc1
-NFoXDTExMDIxOTE4MjQ1M1owgYsxEzARBgoJkiaJk/IsZAEZFgNjb20xGTAXBgoJ
-kiaJk/IsZAEZFgltaWNyb3NvZnQxFDASBgoJkiaJk/IsZAEZFgRjb3JwMRcwFQYK
-CZImiZPyLGQBGRYHcmVkbW9uZDEqMCgGA1UEAxMhTWljcm9zb2Z0IFNlY3VyZSBT
-ZXJ2ZXIgQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
-kYTz6fKXvrdfIr5o3Ue4CRIzhTE+8JE4hrLTQki3emjYn/CfHRPb7hmMiOZmWBdE
-DUEymyXOyZ7Sy2tC6WaBC4onVYotPoSsaOZJv6EJeHPk64RiWTfX+XqufRndYOEC
-DUmotYQNPV/8InioIBf9+gOSsAMdmyGZF6C1PkJqvPZTRxNv6hxuMMb6uOQIPoFX
-/ceQvAOZcJx2qGsAVKsJHylYkC0GgVyFVhOI0vcZZBcP5T+NtOmyjVBWdxS413HL
-D+8w+3wG0bOP8EyOeRnuf0KLXGBangte0ZFIRd28GXpo5UrcA/r5000e2RTHmhC4
-8YPMIoi+q9XZoF5R0Z069QIDAQABo4IB2jCCAdYwEgYDVR0TAQH/BAgwBgEB/wIB
-ADAdBgNVHQ4EFgQUFFXEOeA9LtFVLkiWsNh+FCIGk7wwCwYDVR0PBAQDAgGGMBIG
-CSsGAQQBgjcVAQQFAgMFAAUwIwYJKwYBBAGCNxUCBBYEFM7FoL4P/nlmdZEP8PeS
-WzWYqBWzMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMB8GA1UdIwQYMBaAFMbb
-u8DYIBmS8WD8iPFYf7wbTo8aMIGjBgNVHR8EgZswgZgwgZWggZKggY+GNmh0dHA6
-Ly9tc2NybC5taWNyb3NvZnQuY29tL3BraS9tc2NvcnAvY3JsL21zd3d3KDQpLmNy
-bIY0aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9tc2NvcnAvY3JsL21zd3d3
-KDQpLmNybIYfaHR0cDovL2NvcnBwa2kvY3JsL21zd3d3KDQpLmNybDB5BggrBgEF
-BQcBAQRtMGswPAYIKwYBBQUHMAKGMGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w
-a2kvbXNjb3JwL21zd3d3KDQpLmNydDArBggrBgEFBQcwAoYfaHR0cDovL2NvcnBw
-a2kvYWlhL21zd3d3KDQpLmNydDANBgkqhkiG9w0BAQUFAAOCAgEAempuzk/VLM4N
-H9TAbFtCjKc95iGmyx2bHbEk9m2cbGxXjBre+N4cJoIYYmhLrZ6L712ov1NjM73b
-m8fb2Fy8Yw8Cmwc8VtarPZT2yzGr8MhNUDVuZswaKfjCY3H7RYv/XKc7AOMd25WP
-/M0WTT4Bna6hl9dUaDGwv5SZFFIJ17FLo4FR2H7IkOOI/WcUPAHeDXUewp4qRPE/
-560xZrLSeNH2lKnOAwwXxwnXSo5WOF5AQXh1nRdbBV9Nu7yI6jH1QV6fKf6oFU2Y
-IOjpnJ0FihVB6XoZ0wNOUMzPEEQcTfIoVoc+t0iK02wcmTLgBgbYU703dHvvPTcn
-IfdI2mscx8l9MjUOdklIIve0FhCxRPqHpEeKjM95gllbXmWgQxAXiog+A62fEo5d
-M7nfeEyiweSlhj1cv+2dyhzyS5saKYkk3ocCnOMCyD0M+4gJx4n4b/zT3rcujyN+
-7m20PbBTjcdTT1+AxOs75rON2hhKUqqrk2MDCpnEJsNK4TuRyDUtm9r+AxaZ4XRK
-MT8InY1Xl9hzrIK6MVERYH46kxg6odwpzJ8Urn4dREBiMy6Gzq8mtyXvpYEcmeGL
-zz1aT7qNNbQ0qqbPb6RpOMHlUWOIhVWJC71T5WK1pynAc3P9zOm8BkUYvIyJvCbR
-bufCGVng4FAtVZ1advxSVRoa4GyuFZ8=
------END CERTIFICATE-----
--- a/share/ca-certs/Verisign_RSA_Secure_Server_CA.pem	Sat Feb 02 18:29:35 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzEL
-MAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMu
-MS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9y
-aXR5MB4XDTk0MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UE
-BhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD
-VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGb
-MA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6O
-LDfO6zV4ZFQD5YRAUcm/jwjiioII0haGN1XpsSECrXZogZoFokvJSyVmIlZs
-iAeP94FZbYQHZXATcXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJVCxzOmmC
-sZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZIhvcNAQECBQADfgBl3X7hsuyw
-4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3YQO2WxZpO8ZECAyIUwxr
-l0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc1/p3yjkWWW8O6tO1
-g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==
------END CERTIFICATE-----

mercurial