propagate from branch 'im.pidgin.pidgin' (head 1e232732a9f31f155cd1b160e3af9723b583c040) openq

Tue, 12 Jan 2010 14:22:02 +0000

author
SHiNE CsyFeK <csyfek@gmail.com>
date
Tue, 12 Jan 2010 14:22:02 +0000
branch
openq
changeset 29195
60308d3345ec
parent 28695
ee4ea6de47e3 (current diff)
parent 29194
1e232732a9f3 (diff)
child 31112
9022a48eb75c

propagate from branch 'im.pidgin.pidgin' (head 1e232732a9f31f155cd1b160e3af9723b583c040)
to branch 'im.pidgin.pidgin.openq' (head ee4ea6de47e3fd941655a6445232467e2566b122)

libpurple/protocols/jabber/JEPS file | annotate | diff | comparison | revisions
libpurple/protocols/jabber/XEPS file | annotate | diff | comparison | revisions
libpurple/protocols/yahoo/libymsg.c file | annotate | diff | comparison | revisions
libpurple/protocols/yahoo/libymsg.h file | annotate | diff | comparison | revisions
--- a/AUTHORS	Wed Sep 23 14:48:57 2009 +0000
+++ b/AUTHORS	Tue Jan 12 14:22:02 2010 +0000
@@ -20,6 +20,7 @@
 Casey Harkins - Developer
 Gary 'grim' Kramlich - Developer
 Richard 'rlaager' Laager - Developer
+Sulabh 'sulabh_m' Mahajan - Developer
 Richard 'wabz' Nelson - Developer
 Christopher 'siege' O'Brien - Developer
 Bartosz Oler - Developer
--- a/COPYRIGHT	Wed Sep 23 14:48:57 2009 +0000
+++ b/COPYRIGHT	Tue Jan 12 14:22:02 2010 +0000
@@ -154,6 +154,7 @@
 David Fiander
 Rob Flynn <gaim@robflynn.com>
 Rob Foehl (rwf)
+Chris Foote
 Alan Ford
 Nathan Fredrickson
 Chris J. Friesen
@@ -268,6 +269,7 @@
 Ambrose C. Li
 Nicolas Lichtmaier
 Wesley Lin
+Shaun Lindsay
 Artem Litvinovich
 Josh Littlefield
 Daniel Ljungborg
@@ -275,6 +277,8 @@
 Lokheed
 Norberto Lopes
 Shlomi Loubaton
+Pieter Loubser
+Brian Lu
 Uli Luckas
 Matthew Luckie
 Marcus Lundblad
@@ -317,6 +321,7 @@
 Sergio Moretto
 Andrei Mozzhuhin
 Christian Muise
+MXit Lifestyle (Pty) Ltd.
 Richard Nelson
 Dennis Nezic
 Matthew A. Nicholson
@@ -405,11 +410,10 @@
 Carsten Schaar
 Toby Schaffer
 Jonathan Schleifer <js-pidgin@webkeks.org>
-Matteo Settenvini
-Colin Seymour
 Luke Schierer
 Ralph Schmieder
 David Schmitt
+Heiko Schmitt
 Mark Schneider
 Evan Schoenberg
 Gabriel Schulhof
@@ -419,6 +423,8 @@
 Peter Seebach
 Don Seiler
 Leonardo Serra
+Matteo Settenvini
+Colin Seymour
 Jim Seymour
 Javeed Shaikh
 Joe Shaw
@@ -494,6 +500,7 @@
 James Vega
 David Vermeille
 Sid Vicious
+Andrew Victor
 Jorge VillaseƱor (Masca)
 Bjoern Voigt
 Wan Hing Wah
--- a/ChangeLog	Wed Sep 23 14:48:57 2009 +0000
+++ b/ChangeLog	Tue Jan 12 14:22:02 2010 +0000
@@ -1,12 +1,158 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
-version 2.6.3 (??/??/20??):
+version 2.6.6 (??/??/20??):
+	Gadu-Gadu:
+	* Fix display of avatars after a server-side change. (Krzysztof
+	  Klinikowski)
+
+	MSN:
+	* File transfer requests will no longer cause a crash if you delete the
+	  file before the other side accepts.
+	* Recieved files will no longer hold an extra lock after completion,
+	  meaning they can be moved or deleted without complaints from your OS.
+	* Buddies who sign in from a second location will no longer cause an
+	  unnecessary chat window to open.
+	* Support setting an animated GIF as a buddy icon.
+
 	XMPP:
-	* Fix a crash when attempting to validate an invalid JID.
+	* Added support for the SCRAM-SHA-1 SASL mechanism.  This is only
+	  available when built without Cyrus SASL support.
+	* When getting info on a domain-only (server) JID, show uptime
+	  (when given by the result of the "last query") and don't show status as
+	  offline.
+
+version 2.6.5 (01/08/2010):
+	libpurple:
+	* TLS certificates are actually stored to the local cache once again
+	  (accepting a name mismatch on a certificate should now be remembered)
+
+	General:
+	* Build-time fixes for Solaris.  (Paul Townsend)
+
+	AIM and ICQ:
+	* Messages from some mobile clients are no longer displayed as
+	  Chinese characters (broken in 2.6.4)
+
+	MSN:
+	* Fix an issue allowing a remote user to download arbitrary files from
+	  a libpurple client.  (CVE-2010-0013)
+
+	XMPP:
+	* Do not crash when attempting to register for a new account on Windows.
+	* Fix file transfer with clients that do not support Entity Capabilities
+	  (e.g. Spark)
+
+version 2.6.4 (11/29/2009):
+	libpurple:
+	* Actually emit the hold signal for media calls.
+	* Fix building the GnuTLS plugin with older versions of GnuTLS.
+	* Fix DNS TXT query resolution.
+	* Don't send Proxy-Authorization headers to HTTP proxy servers until we've
+	  received a "407 Proxy Authentication Required" response from the server.
+	  (thecrux)
+	* Added "MXit" protocol plugin, supported and maintained by the MXit folks
+	  themselves (MXit Lifestyle (Pty) Ltd.)
 
 	General:
 	* New 'plugins' sub-command to 'debug' command (i.e. '/debug plugins')
 	  to announce the list of loaded plugins (in both Finch and Pidgin).
+	* Always rejoin open chats after an account reconnects.
+
+	AIM and ICQ:
+	* Better rate limit calculations and other improvements.  (Aman Gupta)
+	* More detailed error messages when messages fail to send.  (Aman Gupta)
+	* The simultaneous login account option is respected when using
+	  the clientLogin authentication method.
+	* Fix offline message retrieval (broken in 2.6.3)
+	* Fix handling of markup on some messages (broken in 2.6.2)
+	* Fix SSL when clientLogin is enabled.
+	* Fix sending and receiving Unicode characters in a Direct IM
+
+	MSN:
+	* Don't forget display names for buddies.
+	* Fix a random crash that might occur when idle.
+	* Fix more FQY 240 connection errors.
+	* Fix a crash that could occur when adding a buddy.
+	* Fix an occasional crash when sending message to an offline user.
+	* Fix a random crash that might occur when idle.
+	* Fix a crash when logging in with some long non-ASCII passwords.
+	  (Shaun Lindsay)
+	* Cache our own friendly name as the server no longer does that for
+	  us.  Users of older versions may need to re-set their friendly name
+	  as it has probably been reset.
+
+	XMPP:
+	* Users connecting to Google Talk now have an "Initiate Chat" context menu
+	  option for their buddies.  (Eion Robb)
+	* Fix a crash when attempting to validate an invalid JID.
+	* Resolve an issue when connecting to iChat Server when no resource
+	  is specified.
+	* Try to automatically find a STUN server by using an SRV lookup on the
+	  account's domain, and use that for voice and video if found and the user
+	  didn't set one manually in prefs.
+	* Fix a crash when adding a buddy without an '@'.
+	* Don't show the option to send a file to a buddy if we know for certain
+	  they don't support any file transfer method supported by libpurple.
+	* Keep the avatar on the server if one is not set locally.
+
+	Yahoo:
+	* Fix sending /buzz.
+	* Fix blocking behavior for federated (MSN/OCS/Sametime) service users.
+	  (Jason Cohen)
+	* Add support for adding OCS and Sametime buddies.  OCS users are added
+	  as "ocs/user@domain.tld" and Sametime users are added as
+	  "ibm/sametime_id".  (Jason Cohen)
+
+	Finch:
+	* The TinyURL plugin now creates shorter URLs for long non-conversation
+	  URLs, e.g. URLs to open Inbox in Yahoo/MSN protocols, or the Yahoo
+	  Captcha when joining chat rooms.
+	* Fix displaying umlauts etc. in non-utf8 locale (fix in libgnt).
+
+	Pidgin:
+	* The userlist in a multiuser chat can be styled via gtkrc by using the
+	  widget name "pidgin_conv_userlist". (Heiko Schmitt)
+	* Add a hold button to the media window.
+	* Fix a bug where the conversation backlog stops scrolling in a very busy
+	  chat room.
+	* In the Conversation "Send To" menu, offline buddies appear grayed
+	  out (but are still selectable).  Previously, only offline buddies on
+	  accounts that do not support offline messaging appeared grayed out.
+
+	Pidgin Preference and Preference Window Changes:
+	* Removed the "Use font from theme" and "Conversation Font" preferences
+	  for everyone except Windows users.  The font can be controlled from the
+	  Pidgin GTK+ Theme Control plugin.
+	* Tabs in the Preferences window are now on the left side.
+	* The Browser tab is now visible for GNOME users.
+	* Added a Proxy tab shown no matter what environment Pidgin runs in.
+	* The Browser and Proxy tabs show appropriate GNOME-specific messages and
+	  allow launching the correct applications to change the relevant GNOME
+	  preferences if found.  These were previously together on the Network
+	  tab.
+	* Moved the port range spin buttons on the Network tab to be beside the
+	  checkbox that enables/disables them.
+	* Reorganized preferences on the Status/Idle tab to have one less
+	  "section."
+	* Reorganized preferences on the Sounds tab to have one less "section."
+	* Renamed Smiley Themes tab to Themes.
+	* Moved Buddy List Theme and Status Icon Theme selectors from Interface
+	  tab to Themes tab.
+	* Moved Sound Theme selector from Sounds tab to Themes tab.
+	* Changed the Smiley Theme selector to be consistent with the other theme
+	  selectors.
+	* Rearranged tabs such that Interface is first and all remaining tabs are
+	  alphabetized in English.
+
+version 2.6.3 (10/16/2009):
+	General:
+	* Fix a crash when performing DNS queries on Unixes that use the
+	  blocking DNS lookups.  (Brian Lu)
+
+	AIM and ICQ:
+	* Fix a crash when some clients send contacts in a format we don't
+	  understand.
+	* Fix blocking and other privacy lists.  (Thanks to AOL)
 
 version 2.6.2 (09/05/2009):
 	libpurple:
--- a/ChangeLog.API	Wed Sep 23 14:48:57 2009 +0000
+++ b/ChangeLog.API	Tue Jan 12 14:22:02 2010 +0000
@@ -1,5 +1,29 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
+version 2.6.6 (??/??/2010):
+	libpurple:
+		Changed:
+		* purple_xfer_cancel_local is now called instead of
+		  purple_xfer_request_denied if an error is found when selecting
+		  a file to send. Request denied is still used when a receive
+		  request is not allowed.
+	Perl:
+		Changed:
+		* Corrected the package names for the PurpleProxyType and
+		  PurpleLogReadFlags enums to have the correct number of colons
+		  (from Purple::ProxyType::::<type> to Purple::ProxyType::<type>
+		  and Purple::Log:ReadFlags::::<type> to
+		  Purple::Log::ReadFlags::<type>)  (Chris Foote)
+
+version 2.6.5 (01/08/2010):
+	No changes
+
+version 2.6.4 (11/29/2009):
+	No changes
+
+version 2.6.3 (10/16/2009):
+	No changes
+
 version 2.6.2 (09/05/2009):
 	Perl:
 		Added:
--- a/ChangeLog.win32	Wed Sep 23 14:48:57 2009 +0000
+++ b/ChangeLog.win32	Tue Jan 12 14:22:02 2010 +0000
@@ -1,3 +1,17 @@
+
+version 2.6.6 (??/??/2010):
+	* Installer translations for: Norwegian nynorsk
+
+version 2.6.5 (01/08/2010):
+	* No changes
+
+version 2.6.4 (11/29/2009):
+	* Register URL handlers for everything that Windows knows about.  Still
+	  use the HTTP "open" handler for security reasons.
+
+version 2.6.3 (10/16/2009):
+	* No changes
+
 version 2.6.2 (09/05/2009):
 	* No changes
 
--- a/NEWS	Wed Sep 23 14:48:57 2009 +0000
+++ b/NEWS	Tue Jan 12 14:22:02 2010 +0000
@@ -2,6 +2,36 @@
 
 Our development blog is available at: http://planet.pidgin.im
 
+2.6.6 (??/??/2010):
+
+2.6.5 (01/08/2010):
+	Paul: This release fixes a pretty serious bug in the MSN code, so we're
+	releasing this build a little earlier than planned with only major
+	bugs fixed.  See the ChangeLog for details.  Enjoy!
+
+2.6.4 (11/29/2009):
+	John:  It's release time again.  Lots of bug fixes this time around, as
+	well as a new protocol plugin developed and maintained by the MXit folks
+	folks.  Elliott and I also did a ton of work on the Preferences window,
+	which will now hopefully fit on most people's small screens.  Enjoy!
+
+	Elliott: This release has been in the works for so long, I don't really
+	remember doing any work on it.  But I do know the MSN servers gave us a
+	little bit of trouble this time around, forgetting people's friendly
+	names.  Nothing too problematic, just a touch annoying.  Also, we've got
+	a nice new Preferences dialog.  You can thank John for that mostly, with
+	a couple of tweaks by me.
+
+	Sadrul: A lot of little fixes for a lot of things! Among them, a fix
+	for a long standing issue with displaying unicode in non-utf8 locale in
+	finch. We also have a new prpl for MXit. This release is very very cool
+	altogether. Enjoy!
+
+2.6.3 (10/16/2009):
+	Mark: Someone reported a fairly serious bug in our AIM/ICQ code
+	so we're releasing a special "severe bug fix only" build.  See the
+	ChangeLog for details.  Enjoy!
+
 2.6.2 (09/05/2009):
 	Mark: Woo boy it's been a busy two weeks.  There was a lot of new code
 	in 2.6.0, and with new code comes new bugs.  The cadre of relentless
--- a/autogen.sh	Wed Sep 23 14:48:57 2009 +0000
+++ b/autogen.sh	Tue Jan 12 14:22:02 2010 +0000
@@ -83,7 +83,7 @@
 
 	OUTPUT=`mktemp autogen-XXXXXX`
 
-	printf "%s" "running ${CMD} ${@}... "
+	printf "running %s %s... " ${CMD} "$*"
 	${CMD} ${@} >${OUTPUT} 2>&1
 
 	if [ $? != 0 ] ; then
@@ -99,9 +99,17 @@
 	fi
 }
 
+cleanup () {
+	rm -f autogen-??????
+	echo
+	exit 2
+}
+
 ###############################################################################
 # We really start here, yes, very sneaky!
 ###############################################################################
+trap cleanup 2
+
 FIGLET=`which figlet 2> /dev/null`
 if [ x"${FIGLET}" != x"" ] ; then
 	${FIGLET} -f small ${PACKAGE}
@@ -143,7 +151,7 @@
 run_or_die ${INTLTOOLIZE} ${INTLTOOLIZE_FLAGS:-"-c -f --automake"}
 # This call to sed is needed to work around an annoying bug in intltool 0.40.6
 # See http://developer.pidgin.im/ticket/9520 for details
-run_or_die ${SED} "s:'\^\$\$lang\$\$':\^\$\$lang\$\$:g" -i po/Makefile.in.in
+run_or_die ${SED} -i.bak -e "s:'\^\$\$lang\$\$':\^\$\$lang\$\$:g" po/Makefile.in.in
 run_or_die ${ACLOCAL} ${ACLOCAL_FLAGS:-"-I m4macros"}
 run_or_die ${AUTOHEADER} ${AUTOHEADER_FLAGS}
 run_or_die ${AUTOMAKE} ${AUTOMAKE_FLAGS:-"-a -c --gnu"}
--- a/configure.ac	Wed Sep 23 14:48:57 2009 +0000
+++ b/configure.ac	Tue Jan 12 14:22:02 2010 +0000
@@ -46,7 +46,7 @@
 m4_define([purple_lt_current], [6])
 m4_define([purple_major_version], [2])
 m4_define([purple_minor_version], [6])
-m4_define([purple_micro_version], [3])
+m4_define([purple_micro_version], [6])
 m4_define([purple_version_suffix], [devel])
 m4_define([purple_version],
           [purple_major_version.purple_minor_version.purple_micro_version])
@@ -55,7 +55,7 @@
 m4_define([gnt_lt_current], [6])
 m4_define([gnt_major_version], [2])
 m4_define([gnt_minor_version], [6])
-m4_define([gnt_micro_version], [3])
+m4_define([gnt_micro_version], [6])
 m4_define([gnt_version_suffix], [devel])
 m4_define([gnt_version],
           [gnt_major_version.gnt_minor_version.gnt_micro_version])
@@ -144,7 +144,7 @@
 	;;
 esac
 
-ALL_LINGUAS="af am ar az be@latin bg bn bs ca ca@valencia cs da de dz el en_AU en_CA en_GB eo es et eu fa fi fr ga gl gu he hi hu hy id it ja ka km kn ko ku lo lt mk mn my_MM nb ne nl nn oc pa pl pt_BR pt ps ro ru si sk sl sq sr sr@latin sv sw ta te th tr uk ur vi xh zh_CN zh_HK zh_TW"
+ALL_LINGUAS="af am ar az be@latin bg bn bs ca ca@valencia cs da de dz el en_AU en_CA en_GB eo es et eu fa fi fr ga gl gu he hi hu hy id it ja ka km kn ko ku lo lt mk mn ms_MY my_MM nb ne nl nn oc pa pl pt_BR pt ps ro ru si sk sl sq sr sr@latin sv sw ta te th tr uk ur vi xh zh_CN zh_HK zh_TW"
 AM_GLIB_GNU_GETTEXT
 
 dnl If we don't have msgfmt, then po/ is going to fail -- ensure that
@@ -812,6 +812,10 @@
 fi
 AM_CONDITIONAL(USE_VV, test "x$enable_gstreamer" != "xno" -a "x$enable_gstinterfaces" != "xno" -a "x$enable_farsight" != "xno")
 
+dnl #######################################################################
+dnl # Check for Internationalized Domain Name support
+dnl #######################################################################
+
 AC_ARG_ENABLE(idn,
 	[AC_HELP_STRING([--disable-idn], [compile without IDN support])],
 	[enable_idn="$enableval" force_idn=$enableval], [enable_idn="yes" force_idn=no])
@@ -1078,7 +1082,7 @@
 fi
 
 if test "x$STATIC_PRPLS" = "xall" ; then
-	STATIC_PRPLS="bonjour gg irc jabber msn myspace novell oscar qq sametime silc simple yahoo zephyr"
+	STATIC_PRPLS="bonjour gg irc jabber msn myspace mxit novell oscar qq sametime silc simple yahoo zephyr"
 fi
 if test "x$have_meanwhile" != "xyes" ; then
 	STATIC_PRPLS=`echo $STATIC_PRPLS | $sedpath 's/sametime//'`
@@ -1135,6 +1139,7 @@
 		msn)		static_msn=yes ;;
 		msnp9)		static_msn=yes ;;
 		myspace)	static_myspace=yes ;;
+		mxit)		static_mxit=yes ;;
 		novell)		static_novell=yes ;;
 		oscar)		static_oscar=yes ;;
 		aim)		static_oscar=yes ;;
@@ -1155,6 +1160,7 @@
 AM_CONDITIONAL(STATIC_JABBER, test "x$static_jabber" = "xyes")
 AM_CONDITIONAL(STATIC_MSN, test "x$static_msn" = "xyes")
 AM_CONDITIONAL(STATIC_MYSPACE, test "x$static_myspace" = "xyes")
+AM_CONDITIONAL(STATIC_MXIT, test "x$static_mxit" = "xyes")
 AM_CONDITIONAL(STATIC_NOVELL, test "x$static_novell" = "xyes")
 AM_CONDITIONAL(STATIC_OSCAR, test "x$static_oscar" = "xyes")
 AM_CONDITIONAL(STATIC_QQ, test "x$static_qq" = "xyes")
@@ -1169,7 +1175,7 @@
 
 AC_ARG_WITH(dynamic_prpls, [AC_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 myspace novell oscar qq sametime silc simple yahoo zephyr"
+	DYNAMIC_PRPLS="bonjour gg irc jabber msn myspace mxit novell oscar qq sametime silc simple yahoo zephyr"
 fi
 if test "x$have_meanwhile" != "xyes"; then
 	DYNAMIC_PRPLS=`echo $DYNAMIC_PRPLS | $sedpath 's/sametime//'`
@@ -1196,6 +1202,7 @@
 		msn)		dynamic_msn=yes ;;
 		msnp9)		dynamic_msn=yes ;;
 		myspace)	dynamic_myspace=yes ;;
+		mxit)		dynamic_mxit=yes ;;
 		novell)		dynamic_novell=yes ;;
 		null)		dynamic_null=yes ;;
 		oscar)		dynamic_oscar=yes ;;
@@ -1467,7 +1474,7 @@
 		AC_CHECK_LIB(pthread, pthread_create, )
 		AC_CHECK_LIB(util, openpty, )
 		AC_CHECK_LIB(db, dbopen, )
-		PY_LIBS="-lpython$PY_VERSION -L$PY_EXEC_PREFIX/lib/python$PY_VERSION/config"
+		PY_LIBS="-L$PY_EXEC_PREFIX/lib/python$PY_VERSION/config -lpython$PY_VERSION"
 		PY_CFLAGS="-I$PY_PREFIX/include/python$PY_VERSION"
 		AC_DEFINE(USE_PYTHON, [1], [Define if python headers are available.])
 		AC_MSG_RESULT(ok)
@@ -1773,6 +1780,23 @@
         LIBS="$LIBS_save"
 fi
 
+if test "x$enable_gnutls" = "xyes"; then
+	AC_MSG_CHECKING(for GNUTLS_CERT_INSECURE_ALGORITHM)
+	LIBS_save="$LIBS"
+	LIBS="$LIBS $GNUTLS_LIBS"
+	CPPFLAGS_save="$CPPFLAGS"
+	CPPFLAGS="$CPPFLAGS $GNUTLS_CFLAGS"
+	AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <gnutls/gnutls.h>]],
+                                        [[unsigned int verify = GNUTLS_CERT_INSECURE_ALGORITHM;]])],
+	               [AC_DEFINE([HAVE_GNUTLS_CERT_INSECURE_ALGORITHM], 1,
+                                  [Define if your gnutls has the GNUTLS_CERT_INSECURE_ALGORITHM flag])
+	                AC_MSG_RESULT(yes)],
+	               [AC_MSG_RESULT(no)])
+	CPPFLAGS="$CPPFLAGS_save"
+        LIBS="$LIBS_save"
+fi
+
+
 AM_CONDITIONAL(USE_GNUTLS, test "x$enable_gnutls" = "xyes")
 
 
@@ -2247,11 +2271,15 @@
 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)
 if test "x$enable_cyrus_sasl" = "xyes" ; then
 	AC_CHECK_LIB(sasl2, sasl_client_init, [
+			AM_CONDITIONAL(USE_CYRUS_SASL, true)
 			AC_DEFINE(HAVE_CYRUS_SASL, [1], [Define to 1 if Cyrus SASL is present])
 			SASL_LIBS=-"lsasl2"
 		], [
+			AM_CONDITIONAL(USE_CYRUS_SASL, false)
 			AC_ERROR(Cyrus SASL library not found)
 		])
+else
+	AM_CONDITIONAL(USE_CYRUS_SASL, false)
 fi
 
 dnl #######################################################################
@@ -2512,6 +2540,7 @@
 		   libpurple/protocols/msn/Makefile
 		   libpurple/protocols/msnp9/Makefile
 		   libpurple/protocols/myspace/Makefile
+		   libpurple/protocols/mxit/Makefile
 		   libpurple/protocols/novell/Makefile
 		   libpurple/protocols/null/Makefile
 		   libpurple/protocols/oscar/Makefile
--- a/doc/finch.1.in	Wed Sep 23 14:48:57 2009 +0000
+++ b/doc/finch.1.in	Tue Jan 12 14:22:02 2010 +0000
@@ -114,7 +114,7 @@
 .B Ctrl \+ o \fR or \fB F10
 Bring up the menu (if there is one) for a window.
 .TP
-.B F11
+.B F11 \fR or \fB Ctrl \+ x
 Popup the context menu (if there is one) for the selected widget.
 .TP
 .B Alt \+ /
--- a/doc/pidgin.1.in	Wed Sep 23 14:48:57 2009 +0000
+++ b/doc/pidgin.1.in	Tue Jan 12 14:22:02 2010 +0000
@@ -628,6 +628,8 @@
 .br
   Richard 'rlaager' Laager (developer) <\fIrlaager@pidgin.im\fR>
 .br
+  Sulabh 'sulabh_m' Mahajan (developer)
+.br
   Richard 'wabz' Nelson (developer)
 .br
   Christopher 'siege' O'Brien (developer)
--- a/finch/finch.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/finch.c	Tue Jan 12 14:22:02 2010 +0000
@@ -19,8 +19,8 @@
  * 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 "finch.h"
-#include <internal.h>
 
 #include "account.h"
 #include "conversation.h"
--- a/finch/gntaccount.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/gntaccount.c	Tue Jan 12 14:22:02 2010 +0000
@@ -23,6 +23,8 @@
  * 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 <gnt.h>
 #include <gntbox.h>
 #include <gntbutton.h>
@@ -36,7 +38,6 @@
 #include <gntwindow.h>
 
 #include "finch.h"
-#include <internal.h>
 
 #include <account.h>
 #include <accountopt.h>
@@ -166,8 +167,7 @@
 
 	/* Alias */
 	value = gnt_entry_get_text(GNT_ENTRY(dialog->alias));
-	if (value && *value)
-		purple_account_set_alias(account, value);
+	purple_account_set_alias(account, value);
 
 	/* Remember password and password */
 	purple_account_set_remember_password(account,
--- a/finch/gntblist.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/gntblist.c	Tue Jan 12 14:22:02 2010 +0000
@@ -23,8 +23,8 @@
  * 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 "finch.h"
-#include <internal.h>
 
 #include <account.h>
 #include <blist.h>
@@ -1119,6 +1119,8 @@
 		PurpleMenuAction *act = (PurpleMenuAction *) list->data;
 		act->data = node;
 		gnt_append_menu_action(menu, act, NULL);
+		g_signal_connect_swapped(G_OBJECT(menu), "destroy",
+			G_CALLBACK(purple_menu_action_free), act);
 	}
 }
 
@@ -1368,6 +1370,8 @@
 			iter; iter = g_list_delete_link(iter, iter))
 	{
 		gnt_append_menu_action(menu, iter->data, NULL);
+		g_signal_connect_swapped(G_OBJECT(menu), "destroy",
+				G_CALLBACK(purple_menu_action_free), iter->data);
 	}
 }
 
@@ -1940,7 +1944,7 @@
 	} else if (!gnt_tree_is_searching(GNT_TREE(ggblist->tree))) {
 		if (strcmp(text, "t") == 0) {
 			finch_blist_toggle_tag_buddy(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree)));
-			gnt_bindable_perform_action_named(GNT_BINDABLE(ggblist->tree), "move-down");
+			gnt_bindable_perform_action_named(GNT_BINDABLE(ggblist->tree), "move-down", NULL);
 		} else if (strcmp(text, "a") == 0) {
 			finch_blist_place_tagged(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree)));
 		} else
--- a/finch/gntcertmgr.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/gntcertmgr.c	Tue Jan 12 14:22:02 2010 +0000
@@ -25,8 +25,8 @@
  *
  */
 
+#include <internal.h>
 #include "finch.h"
-#include <internal.h>
 
 #include "certificate.h"
 #include "debug.h"
--- a/finch/gntconn.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/gntconn.c	Tue Jan 12 14:22:02 2010 +0000
@@ -23,8 +23,8 @@
  * 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 "finch.h"
-#include <internal.h>
 
 #include "account.h"
 #include "core.h"
@@ -107,7 +107,6 @@
 {
 	FinchAutoRecon *info;
 	PurpleAccount *account = purple_connection_get_account(gc);
-	GList *list;
 
 	if (!purple_connection_error_is_fatal(reason)) {
 		info = g_hash_table_lookup(hash, account);
@@ -144,21 +143,6 @@
 		g_free(secondary);
 		purple_account_set_enabled(account, FINCH_UI, FALSE);
 	}
-
-	/* If we have any open chats, we probably want to rejoin when we get back online. */
-	list = purple_get_chats();
-	while (list) {
-		PurpleConversation *conv = list->data;
-		list = list->next;
-		if (purple_conversation_get_account(conv) != account ||
-				purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv)))
-			continue;
-		purple_conversation_set_data(conv, "want-to-rejoin", GINT_TO_POINTER(TRUE));
-		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));
-	}
 }
 
 static void
--- a/finch/gntconv.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/gntconv.c	Tue Jan 12 14:22:02 2010 +0000
@@ -23,10 +23,9 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#include <string.h>
 
+#include <internal.h>
 #include "finch.h"
-#include <internal.h>
 
 #include <cmds.h>
 #include <core.h>
@@ -367,6 +366,28 @@
 	}
 }
 
+static void
+account_signing_off(PurpleConnection *gc)
+{
+	GList *list = purple_get_chats();
+	PurpleAccount *account = purple_connection_get_account(gc);
+
+	/* We are about to sign off. See which chats we are currently in, and mark
+	 * them for rejoin on reconnect. */
+	while (list) {
+		PurpleConversation *conv = list->data;
+		if (!purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv)) &&
+				purple_conversation_get_account(conv) == account) {
+			purple_conversation_set_data(conv, "want-to-rejoin", GINT_TO_POINTER(TRUE));
+			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));
+		}
+		list = list->next;
+	}
+}
+
 static gpointer
 finch_conv_get_handle(void)
 {
@@ -642,8 +663,25 @@
 create_conv_from_userlist(GntWidget *widget, FinchConv *fc)
 {
 	PurpleAccount *account = purple_conversation_get_account(fc->active_conv);
-	char *name = gnt_tree_get_selection_data(GNT_TREE(widget));
-	purple_conversation_new(PURPLE_CONV_TYPE_IM, account, name);
+	PurpleConnection *gc = purple_account_get_connection(account);
+	PurplePluginProtocolInfo *prpl_info = NULL;
+	char *name, *realname;
+
+	if (!gc) {
+		purple_conversation_write(fc->active_conv, NULL, _("You are not connected."),
+				PURPLE_MESSAGE_SYSTEM, time(NULL));
+		return;
+	}
+
+	name = gnt_tree_get_selection_data(GNT_TREE(widget));
+
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+	if (prpl_info && PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, get_cb_real_name))
+		realname = prpl_info->get_cb_real_name(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(fc->active_conv)), name);
+	else
+		realname = NULL;
+	purple_conversation_new(PURPLE_CONV_TYPE_IM, account, realname ? realname : name);
+	g_free(realname);
 }
 
 static void
@@ -1433,6 +1471,8 @@
 					PURPLE_CALLBACK(account_signed_on_off), NULL);
 	purple_signal_connect(purple_connections_get_handle(), "signed-off", finch_conv_get_handle(),
 					PURPLE_CALLBACK(account_signed_on_off), NULL);
+	purple_signal_connect(purple_connections_get_handle(), "signing-off", finch_conv_get_handle(),
+					PURPLE_CALLBACK(account_signing_off), NULL);
 }
 
 void finch_conversation_uninit()
--- a/finch/gntdebug.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/gntdebug.c	Tue Jan 12 14:22:02 2010 +0000
@@ -23,6 +23,9 @@
  * 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 <gnt.h>
 #include <gntbox.h>
 #include <gntbutton.h>
@@ -35,7 +38,6 @@
 
 #include "gntdebug.h"
 #include "finch.h"
-#include <internal.h>
 #include "notify.h"
 #include "util.h"
 
--- a/finch/gntft.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/gntft.c	Tue Jan 12 14:22:02 2010 +0000
@@ -23,8 +23,8 @@
  * 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 "finch.h"
-#include <internal.h>
 
 #include <gnt.h>
 #include <gntbox.h>
--- a/finch/gntidle.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/gntidle.c	Tue Jan 12 14:22:02 2010 +0000
@@ -21,6 +21,8 @@
  *
  */
 
+#include <internal.h>
+
 #include "finch.h"
 #include "gntidle.h"
 #include "gntwm.h"
--- a/finch/gntlog.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/gntlog.c	Tue Jan 12 14:22:02 2010 +0000
@@ -23,8 +23,8 @@
  * 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 "finch.h"
-#include <internal.h>
 
 #include <gnt.h>
 #include <gntbox.h>
--- a/finch/gntmedia.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/gntmedia.c	Tue Jan 12 14:22:02 2010 +0000
@@ -24,8 +24,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
+#include <internal.h>
 #include "finch.h"
-#include <internal.h>
 #include "gntconv.h"
 #include "gntmedia.h"
 
--- a/finch/gntnotify.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/gntnotify.c	Tue Jan 12 14:22:02 2010 +0000
@@ -23,6 +23,8 @@
  * 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 <gnt.h>
 #include <gntbox.h>
 #include <gntbutton.h>
@@ -32,7 +34,6 @@
 #include <gntwindow.h>
 
 #include "finch.h"
-#include <internal.h>
 
 #include <util.h>
 
--- a/finch/gntplugin.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/gntplugin.c	Tue Jan 12 14:22:02 2010 +0000
@@ -23,6 +23,8 @@
  * 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 <gnt.h>
 #include <gntbox.h>
 #include <gntbutton.h>
@@ -32,7 +34,6 @@
 #include <gntutils.h>
 
 #include "finch.h"
-#include <internal.h>
 
 #include "debug.h"
 #include "notify.h"
--- a/finch/gntpounce.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/gntpounce.c	Tue Jan 12 14:22:02 2010 +0000
@@ -24,6 +24,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  *
  */
+#include <internal.h>
+
 #include <gnt.h>
 #include <gntbox.h>
 #include <gntbutton.h>
@@ -36,7 +38,6 @@
 #include <gntutils.h>
 
 #include "finch.h"
-#include <internal.h>
 
 #include "account.h"
 #include "conversation.h"
--- a/finch/gntrequest.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/gntrequest.c	Tue Jan 12 14:22:02 2010 +0000
@@ -23,6 +23,8 @@
  * 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 <gnt.h>
 #include <gntbox.h>
 #include <gntbutton.h>
@@ -35,7 +37,6 @@
 #include <gnttree.h>
 
 #include "finch.h"
-#include <internal.h>
 #include "gntrequest.h"
 #include "debug.h"
 #include "util.h"
--- a/finch/gntstatus.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/gntstatus.c	Tue Jan 12 14:22:02 2010 +0000
@@ -23,6 +23,8 @@
  * 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 <gnt.h>
 #include <gntbox.h>
 #include <gntbutton.h>
@@ -34,7 +36,6 @@
 #include <gntutils.h>
 
 #include "finch.h"
-#include <internal.h>
 
 #include <notify.h>
 #include <request.h>
--- a/finch/libgnt/gntbindable.h	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntbindable.h	Tue Jan 12 14:22:02 2010 +0000
@@ -166,7 +166,7 @@
  *
  * @return  @c TRUE if the action was performed successfully, @c FALSE otherwise.
  */
-gboolean gnt_bindable_perform_action_named(GntBindable *bindable, const char *name, ...);
+gboolean gnt_bindable_perform_action_named(GntBindable *bindable, const char *name, ...) G_GNUC_NULL_TERMINATED;
 
 /**
  * Returns a GntTree populated with "key" -> "binding" for the widget.
--- a/finch/libgnt/gntbox.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntbox.c	Tue Jan 12 14:22:02 2010 +0000
@@ -20,6 +20,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
+#include "gntinternal.h"
 #include "gntbox.h"
 #include "gntstyle.h"
 #include "gntutils.h"
@@ -90,7 +91,7 @@
 		else
 			wbkgdset(widget->window, '\0' | gnt_color_pair(GNT_COLOR_TITLE_D));
 		mvwaddch(widget->window, 0, pos-1, ACS_RTEE | gnt_color_pair(GNT_COLOR_NORMAL));
-		mvwaddstr(widget->window, 0, pos, title);
+		mvwaddstr(widget->window, 0, pos, C_(title));
 		mvwaddch(widget->window, 0, right, ACS_LTEE | gnt_color_pair(GNT_COLOR_NORMAL));
 		g_free(title);
 	}
@@ -687,8 +688,8 @@
 		get_title_thingies(b, prev, &pos, &right);
 		mvwhline(w->window, 0, pos - 1, ACS_HLINE | gnt_color_pair(GNT_COLOR_NORMAL),
 				right - pos + 2);
-		g_free(prev);
 	}
+	g_free(prev);
 }
 
 void gnt_box_set_pad(GntBox *box, int pad)
--- a/finch/libgnt/gntbutton.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntbutton.c	Tue Jan 12 14:22:02 2010 +0000
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "gntinternal.h"
 #include "gntbutton.h"
 #include "gntstyle.h"
 #include "gntutils.h"
@@ -48,7 +49,7 @@
 		type = GNT_COLOR_NORMAL;
 
 	wbkgdset(widget->window, '\0' | gnt_color_pair(type));
-	mvwaddstr(widget->window, (small_button) ? 0 : 1, 2, button->priv->text);
+	mvwaddstr(widget->window, (small_button) ? 0 : 1, 2, C_(button->priv->text));
 	if (small_button) {
 		type = GNT_COLOR_HIGHLIGHT;
 		mvwchgat(widget->window, 0, 0, widget->priv.width, focus ? A_BOLD : A_REVERSE, type, NULL);
--- a/finch/libgnt/gntcheckbox.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntcheckbox.c	Tue Jan 12 14:22:02 2010 +0000
@@ -20,6 +20,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
+#include "gntinternal.h"
 #include "gntcheckbox.h"
 
 enum
@@ -36,21 +37,21 @@
 {
 	GntCheckBox *cb = GNT_CHECK_BOX(widget);
 	GntColorType type;
-	char *text;
+	gboolean focus = gnt_widget_has_focus(widget);
 
-	if (gnt_widget_has_focus(widget))
+	if (focus)
 		type = GNT_COLOR_HIGHLIGHT;
 	else
 		type = GNT_COLOR_NORMAL;
 
 	wbkgdset(widget->window, '\0' | gnt_color_pair(type));
 
-	text = g_strdup_printf("[%c]", cb->checked ? 'X' : ' ');
-	mvwaddstr(widget->window, 0, 0, text);
-	g_free(text);
+	mvwaddch(widget->window, 0, 0, '[');
+	mvwaddch(widget->window, 0, 1, (cb->checked ? 'X' : ' ') | (focus ? A_UNDERLINE : A_NORMAL));
+	mvwaddch(widget->window, 0, 2, ']');
 
 	wbkgdset(widget->window, '\0' | gnt_color_pair(GNT_COLOR_NORMAL));
-	mvwaddstr(widget->window, 0, 4, GNT_BUTTON(cb)->priv->text);
+	mvwaddstr(widget->window, 0, 4, C_(GNT_BUTTON(cb)->priv->text));
 	wmove(widget->window, 0, 1);
 
 	GNTDEBUG;
--- a/finch/libgnt/gntcolors.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntcolors.c	Tue Jan 12 14:22:02 2010 +0000
@@ -208,8 +208,10 @@
 				key = g_ascii_strdown(key, -1);
 				color = gnt_colors_get_color(key);
 				g_free(key);
-				if (color == -EINVAL)
+				if (color == -EINVAL) {
+					g_strfreev(list);
 					continue;
+				}
 
 				init_color(color, r, g, b);
 			}
@@ -251,8 +253,10 @@
 			int bg = gnt_colors_get_color(bgc);
 			g_free(fgc);
 			g_free(bgc);
-			if (fg == -EINVAL || bg == -EINVAL)
+			if (fg == -EINVAL || bg == -EINVAL) {
+				g_strfreev(list);
 				continue;
+			}
 
 			key = g_ascii_strdown(key, -1);
 
@@ -275,6 +279,7 @@
 			else if (strcmp(key, "urgent") == 0)
 				type = GNT_COLOR_URGENT;
 			else {
+				g_strfreev(list);
 				g_free(key);
 				continue;
 			}
--- a/finch/libgnt/gntcombobox.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntcombobox.c	Tue Jan 12 14:22:02 2010 +0000
@@ -20,6 +20,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
+#include "gntinternal.h"
 #include "gntbox.h"
 #include "gntcombobox.h"
 #include "gnttree.h"
@@ -90,7 +91,7 @@
 	s = (char*)gnt_util_onscreen_width_to_pointer(text, widget->priv.width - 4, &len);
 	*s = '\0';
 
-	mvwaddstr(widget->window, 1, 1, text);
+	mvwaddstr(widget->window, 1, 1, C_(text));
 	whline(widget->window, ' ' | gnt_color_pair(type), widget->priv.width - 4 - len);
 	mvwaddch(widget->window, 1, widget->priv.width - 3, ACS_VLINE | gnt_color_pair(GNT_COLOR_NORMAL));
 	mvwaddch(widget->window, 1, widget->priv.width - 2, ACS_DARROW | gnt_color_pair(GNT_COLOR_NORMAL));
--- a/finch/libgnt/gntentry.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntentry.c	Tue Jan 12 14:22:02 2010 +0000
@@ -23,6 +23,7 @@
 #include <ctype.h>
 #include <string.h>
 
+#include "gntinternal.h"
 #include "gntbox.h"
 #include "gntentry.h"
 #include "gntmarshal.h"
@@ -284,7 +285,7 @@
 				g_utf8_pointer_to_offset(entry->scroll, entry->end));
 	}
 	else
-		mvwprintw(widget->window, 0, 0, "%s", entry->scroll);
+		mvwprintw(widget->window, 0, 0, "%s", C_(entry->scroll));
 
 	stop = gnt_util_onscreen_width(entry->scroll, entry->end);
 	if (stop < widget->priv.width)
@@ -495,7 +496,7 @@
 {
 	GntEntry *entry = GNT_ENTRY(bind);
 	if (entry->ddown) {
-		gnt_bindable_perform_action_named(GNT_BINDABLE(entry->ddown), "move-down");
+		gnt_bindable_perform_action_named(GNT_BINDABLE(entry->ddown), "move-down", NULL);
 		return TRUE;
 	}
 	return show_suggest_dropdown(entry);
@@ -1044,8 +1045,11 @@
 		snprintf(entry->start, len + 1, "%s", text);
 	entry->end = entry->start + len;
 
-	entry->scroll = entry->start + scroll;
-	entry->cursor = entry->end - cursor;
+	if ((entry->scroll = entry->start + scroll) > entry->end)
+		entry->scroll = entry->end;
+
+	if ((entry->cursor = entry->end - cursor) > entry->end)
+		entry->cursor = entry->end;
 
 	if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(entry), GNT_WIDGET_MAPPED))
 		entry_redraw(GNT_WIDGET(entry));
--- a/finch/libgnt/gntfilesel.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntfilesel.c	Tue Jan 12 14:22:02 2010 +0000
@@ -176,9 +176,13 @@
 	splits = g_strsplit(path, G_DIR_SEPARATOR_S, -1);
 	for (i = 0, j = 0; splits[i]; i++) {
 		if (strcmp(splits[i], ".") == 0) {
+			g_free(splits[i]);
+			splits[i] = NULL;
 		} else if (strcmp(splits[i], "..") == 0) {
 			if (j)
 				j--;
+			g_free(splits[i]);
+			splits[i] = NULL;
 		} else {
 			if (i != j) {
 				g_free(splits[j]);
@@ -625,6 +629,7 @@
 
 	sel->files = gnt_tree_new_with_columns(2);  /* Name, Size */
 	gnt_tree_set_compare_func(GNT_TREE(sel->files), (GCompareFunc)g_utf8_collate);
+	gnt_tree_set_hash_fns(GNT_TREE(sel->files), g_str_hash, g_str_equal, g_free);
 	gnt_tree_set_column_titles(GNT_TREE(sel->files), "Filename", "Size");
 	gnt_tree_set_show_title(GNT_TREE(sel->files), TRUE);
 	gnt_tree_set_col_width(GNT_TREE(sel->files), 0, 25);
--- a/finch/libgnt/gntinternal.h	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntinternal.h	Tue Jan 12 14:22:02 2010 +0000
@@ -19,6 +19,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
+#include <glib.h>
 #undef G_LOG_DOMAIN
 #define G_LOG_DOMAIN "Gnt"
 
@@ -31,3 +32,14 @@
 # define gnt_warning g_warning
 #endif
 
+#ifndef G_GNUC_NULL_TERMINATED
+#	if defined(__GNUC__) && __GNUC__ >= 4
+#		define G_GNUC_NULL_TERMINATED __attribute__((__sentinel__))
+#	else
+#		define G_GNUC_NULL_TERMINATED
+#	endif
+#endif
+
+extern int gnt_need_conversation_to_locale;
+extern const char *C_(const char *x);
+
--- a/finch/libgnt/gntkeys.h	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntkeys.h	Tue Jan 12 14:22:02 2010 +0000
@@ -65,7 +65,7 @@
 #define GNT_KEY_BACKSPACE SAFE(key_backspace)
 #define GNT_KEY_DEL    SAFE(key_dc)
 #define GNT_KEY_INS    SAFE(key_ic)
-#define GNT_KEY_BACK_TAB SAFE(back_tab)
+#define GNT_KEY_BACK_TAB (back_tab ? back_tab : SAFE(key_btab))
 
 #define GNT_KEY_CTRL_A     "\001"
 #define GNT_KEY_CTRL_B     "\002"
--- a/finch/libgnt/gntlabel.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntlabel.c	Tue Jan 12 14:22:02 2010 +0000
@@ -20,6 +20,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
+#include "gntinternal.h"
 #include "gntlabel.h"
 #include "gntutils.h"
 
@@ -53,7 +54,7 @@
 	chtype flag = gnt_text_format_flag_to_chtype(label->flags);
 
 	wbkgdset(widget->window, '\0' | flag);
-	mvwaddstr(widget->window, 0, 0, label->text);
+	mvwaddstr(widget->window, 0, 0, C_(label->text));
 
 	GNTDEBUG;
 }
--- a/finch/libgnt/gntline.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntline.c	Tue Jan 12 14:22:02 2010 +0000
@@ -20,6 +20,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
+#include "gntinternal.h"
 #include "gntline.h"
 
 enum
--- a/finch/libgnt/gntmain.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntmain.c	Tue Jan 12 14:22:02 2010 +0000
@@ -82,6 +82,8 @@
 static GntWM *wm;
 static GntClipboard *clipboard;
 
+int gnt_need_conversation_to_locale;
+
 #define HOLDING_ESCAPE  (escape_stuff.timer != 0)
 
 static struct {
@@ -465,10 +467,12 @@
 #ifdef NO_WIDECHAR
 	ascii_only = TRUE;
 #else
-	if (locale && (strstr(locale, "UTF") || strstr(locale, "utf")))
+	if (locale && (strstr(locale, "UTF") || strstr(locale, "utf"))) {
 		ascii_only = FALSE;
-	else
+	} else {
 		ascii_only = TRUE;
+		gnt_need_conversation_to_locale = TRUE;
+	}
 #endif
 
 	initscr();
@@ -731,3 +735,24 @@
 #endif
 }
 
+const char *C_(const char *x)
+{
+	static char *c = NULL;
+	if (gnt_need_conversation_to_locale) {
+		GError *error = NULL;
+		g_free(c);
+		c = g_locale_from_utf8(x, -1, NULL, NULL, &error);
+		if (c == NULL || error) {
+			char *store = c;
+			c = NULL;
+			gnt_warning("Error: %s\n", error ? error->message : "(unknown)");
+			g_error_free(error);
+			error = NULL;
+			g_free(c);
+			c = store;
+		}
+		return c ? c : x;
+	} else
+		return x;
+}
+
--- a/finch/libgnt/gntmenu.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntmenu.c	Tue Jan 12 14:22:02 2010 +0000
@@ -20,6 +20,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
+#include "gntinternal.h"
 #include "gntmenu.h"
 #include "gntmenuitemcheck.h"
 
@@ -92,7 +93,7 @@
 			item->priv.x = getcurx(widget->window) + widget->priv.x;
 			item->priv.y = getcury(widget->window) + widget->priv.y + 1;
 			wbkgdset(widget->window, type);
-			wprintw(widget->window, " %s   ", item->text);
+			wprintw(widget->window, " %s   ", C_(item->text));
 		}
 	} else {
 		org_draw(widget);
--- a/finch/libgnt/gntmenuitem.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntmenuitem.c	Tue Jan 12 14:22:02 2010 +0000
@@ -20,6 +20,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
+#include "gntinternal.h"
 #include "gntmenu.h"
 #include "gntmenuitem.h"
 
--- a/finch/libgnt/gntmenuitemcheck.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntmenuitemcheck.c	Tue Jan 12 14:22:02 2010 +0000
@@ -20,6 +20,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
+#include "gntinternal.h"
 #include "gntmenuitemcheck.h"
 
 static GntMenuItemClass *parent_class = NULL;
--- a/finch/libgnt/gntprogressbar.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntprogressbar.c	Tue Jan 12 14:22:02 2010 +0000
@@ -20,6 +20,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  **/
 
+#include "gntinternal.h"
 #include "gntprogressbar.h"
 #include "gntutils.h"
 
--- a/finch/libgnt/gntslider.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntslider.c	Tue Jan 12 14:22:02 2010 +0000
@@ -20,6 +20,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
+#include "gntinternal.h"
 #include "gntcolors.h"
 #include "gntkeys.h"
 #include "gntslider.h"
--- a/finch/libgnt/gnttextview.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gnttextview.c	Tue Jan 12 14:22:02 2010 +0000
@@ -67,6 +67,12 @@
 
 static void reset_text_view(GntTextView *view);
 
+static gboolean
+text_view_contains(GntTextView *view, const char *str)
+{
+	return (str >= view->string->str && str < view->string->str + view->string->len);
+}
+
 static void
 gnt_text_view_draw(GntWidget *widget)
 {
@@ -109,10 +115,10 @@
 			char back = *end;
 			chtype fl = seg->flags;
 			*end = '\0';
-			if (select_start < view->string->str + seg->start && select_end > view->string->str + seg->end) {
+			if (select_start && select_start < view->string->str + seg->start && select_end > view->string->str + seg->end) {
 				fl |= A_REVERSE;
 				wattrset(widget->window, fl);
-				wprintw(widget->window, "%s", (view->string->str + seg->start));
+				wprintw(widget->window, "%s", C_(view->string->str + seg->start));
 			} else if (select_start && select_end &&
 				((select_start >= view->string->str + seg->start && select_start <= view->string->str + seg->end) ||
 				(select_end <= view->string->str + seg->end && select_start <= view->string->str + seg->start))) {
@@ -126,13 +132,13 @@
 						fl = seg->flags;
 					str = g_strndup(cur, last - cur);
 					wattrset(widget->window, fl);
-					waddstr(widget->window, str);
+					waddstr(widget->window, C_(str));
 					g_free(str);
 					cur = g_utf8_next_char(cur);
 				}
 			} else {
 				wattrset(widget->window, fl);
-				wprintw(widget->window, "%s", (view->string->str + seg->start));
+				wprintw(widget->window, "%s", C_(view->string->str + seg->start));
 			}
 			*end = back;
 		}
@@ -326,9 +332,10 @@
 		select_start = gnt_text_view_get_p(GNT_TEXT_VIEW(widget), x - widget->priv.x, y - widget->priv.y);
 		g_timeout_add(500, too_slow, NULL);
 	} else if (event == GNT_MOUSE_UP) {
-		if (select_start) {
+		GntTextView *view = GNT_TEXT_VIEW(widget);
+		if (text_view_contains(view, select_start)) {
 			GString *clip;
-			select_end = gnt_text_view_get_p(GNT_TEXT_VIEW(widget), x - widget->priv.x, y - widget->priv.y);
+			select_end = gnt_text_view_get_p(view, x - widget->priv.x, y - widget->priv.y);
 			if (select_end < select_start) {
 				gchar *t = select_start;
 				select_start = select_end;
@@ -336,7 +343,7 @@
 			}
 			if (select_start == select_end) {
 				if (double_click) {
-					clip = select_word_text(GNT_TEXT_VIEW(widget), select_start);
+					clip = select_word_text(view, select_start);
 					double_click = FALSE;
 				} else {
 					double_click = TRUE;
@@ -767,6 +774,7 @@
 							line->segments = g_list_delete_link(line->segments, segs);
 							if (line->segments == NULL) {
 								free_text_line(line, NULL);
+								line = NULL;
 								if (view->list == iter) {
 									if (inext)
 										view->list = inext;
@@ -780,7 +788,8 @@
 							seg->start = tag->start;
 							seg->end = tag->end - change;
 						}
-						line->length -= change;
+						if (line)
+							line->length -= change;
 						/* XXX: Make things work if the tagged text spans over several lines. */
 					} else {
 						/* XXX: handle the rest of the conditions */
--- a/finch/libgnt/gnttree.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gnttree.c	Tue Jan 12 14:22:02 2010 +0000
@@ -20,6 +20,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
+#include "gntinternal.h"
 #include "gntmarshal.h"
 #include "gntstyle.h"
 #include "gnttree.h"
@@ -549,7 +550,7 @@
 		}
 
 		wbkgdset(widget->window, '\0' | attr);
-		mvwaddstr(widget->window, i, pos, str);
+		mvwaddstr(widget->window, i, pos, C_(str));
 		whline(widget->window, ' ', scrcol - wr);
 		tree->bottom = row;
 		g_free(str);
@@ -815,7 +816,7 @@
 		gnt_widget_activate(widget);
 	} else if (tree->priv->search) {
 		gboolean changed = TRUE;
-		if (isalnum(*text)) {
+		if (g_unichar_isprint(*text)) {
 			tree->priv->search = g_string_append_c(tree->priv->search, *text);
 		} else if (g_utf8_collate(text, GNT_KEY_BACKSPACE) == 0) {
 			if (tree->priv->search->len)
--- a/finch/libgnt/gntutils.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntutils.c	Tue Jan 12 14:22:02 2010 +0000
@@ -20,6 +20,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
+#include "config.h"
+
 #include "gntinternal.h"
 #undef GNT_LOG_DOMAIN
 #define GNT_LOG_DOMAIN "Utils"
@@ -35,8 +37,6 @@
 #include "gntutils.h"
 #include "gntwindow.h"
 
-#include "config.h"
-
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
@@ -46,8 +46,6 @@
 #include <libxml/tree.h>
 #endif
 
-#include "config.h"
-
 void gnt_util_get_text_bound(const char *text, int *width, int *height)
 {
 	const char *s = text, *last;
@@ -374,6 +372,7 @@
 	gnt_widget_from_xmlnode(node, data, num);
 
 	xmlFreeDoc(doc);
+	xmlFreeParserCtxt(ctxt);
 	xmlCleanupParser();
 	va_end(list);
 	g_free(data);
@@ -470,6 +469,7 @@
 		xmlFreeDoc(doc);
 		ret = TRUE;
 	}
+	xmlFreeParserCtxt(ctxt);
 	xmlCleanupParser();
 	return ret;
 #endif
--- a/finch/libgnt/gntwidget.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntwidget.c	Tue Jan 12 14:22:02 2010 +0000
@@ -22,6 +22,7 @@
 
 /* Stuff brutally ripped from Gflib */
 
+#include "gntinternal.h"
 #include "gntwidget.h"
 #include "gntstyle.h"
 #include "gntmarshal.h"
--- a/finch/libgnt/gntwindow.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntwindow.c	Tue Jan 12 14:22:02 2010 +0000
@@ -20,6 +20,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
+#include "gntinternal.h"
 #include "gntstyle.h"
 #include "gntwindow.h"
 
--- a/finch/libgnt/gntws.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/gntws.c	Tue Jan 12 14:22:02 2010 +0000
@@ -1,5 +1,28 @@
+/*
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library 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 <gmodule.h>
 
+#include "gntinternal.h"
 #include "gntbox.h"
 #include "gntwidget.h"
 #include "gntwindow.h"
@@ -73,7 +96,7 @@
 		else
 			mvwhline(taskbar, 0, width * i, ' ' | gnt_color_pair(color), getmaxx(stdscr) - width * i);
 		title = GNT_BOX(w)->title;
-		mvwprintw(taskbar, 0, width * i, "%s", title ? title : "<gnt>");
+		mvwprintw(taskbar, 0, width * i, "%s", title ? C_(title) : "<gnt>");
 		if (i)
 			mvwaddch(taskbar, 0, width *i - 1, ACS_VLINE | A_STANDOUT | gnt_color_pair(GNT_COLOR_NORMAL));
 	}
--- a/finch/libgnt/wms/irssi.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/wms/irssi.c	Tue Jan 12 14:22:02 2010 +0000
@@ -33,6 +33,8 @@
 #include <string.h>
 #include <sys/types.h>
 
+#include "gntinternal.h"
+
 #include "gnt.h"
 #include "gntbox.h"
 #include "gntmenu.h"
--- a/finch/libgnt/wms/s.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/libgnt/wms/s.c	Tue Jan 12 14:22:02 2010 +0000
@@ -1,8 +1,8 @@
+#include "internal.h"
+
 #include <string.h>
 #include <sys/types.h>
 
-#include "internal.h"
-
 #include "gnt.h"
 #include "gntbox.h"
 #include "gntmenu.h"
--- a/finch/plugins/gnttinyurl.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/finch/plugins/gnttinyurl.c	Tue Jan 12 14:22:02 2010 +0000
@@ -41,7 +41,10 @@
 #include <gntconv.h>
 
 #include <gntplugin.h>
+
+#include <gntlabel.h>
 #include <gnttextview.h>
+#include <gntwindow.h>
 
 static int tag_num = 0;
 
@@ -52,6 +55,8 @@
 	int num;
 } CbInfo;
 
+static void process_urls(PurpleConversation *conv, GList *urls);
+
 /* 3 functions from util.c */
 static gboolean
 badchar(char c)
@@ -83,7 +88,8 @@
 	return FALSE;
 }
 
-static GList *extract_urls(char *text) {
+static GList *extract_urls(const char *text)
+{
 	const char *t, *c, *q = NULL;
 	char *url_buf;
 	GList *ret = NULL;
@@ -142,7 +148,9 @@
 					url_buf = g_strndup(c, t - c);
 					if (!g_list_find_custom(ret, url_buf, (GCompareFunc)strcmp)) {
 						purple_debug_info("TinyURL", "Added URL %s\n", url_buf);
-						ret = g_list_append(ret, g_strdup(url_buf));
+						ret = g_list_append(ret, url_buf);
+					} else {
+						g_free(url_buf);
 					}
 					c = t;
 					break;
@@ -173,6 +181,8 @@
 						if (!g_list_find_custom(ret, url_buf, (GCompareFunc)strcmp)) {
 							purple_debug_info("TinyURL", "Added URL %s\n", url_buf);
 							ret = g_list_append(ret, url_buf);
+						} else {
+							g_free(url_buf);
 						}
 						c = t;
 						break;
@@ -207,10 +217,12 @@
 			gnt_text_view_tag_change(tv, data->tag, str, FALSE);
 			g_free(str);
 			g_free(data->tag);
+			g_free(data);
 			return;
 		}
 	}
 	g_free(data->tag);
+	g_free(data);
 	purple_debug_info("TinyURL", "Conversation no longer exists... :(\n");
 }
 
@@ -219,13 +231,14 @@
 	g_free(data);
 }
 
-static gboolean receiving_msg(PurpleAccount *account, char **sender, char **message,
-				PurpleConversation *conv, PurpleMessageFlags *flags) {
+static gboolean writing_msg(PurpleAccount *account, char *sender, char **message,
+				PurpleConversation *conv, PurpleMessageFlags flags)
+{
 	GString *t;
-	GList *iter, *urls;
+	GList *iter, *urls, *next;
 	int c = 0;
 
-	if (!(*flags & PURPLE_MESSAGE_RECV) || *flags & PURPLE_MESSAGE_INVISIBLE)
+	if ((flags & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_INVISIBLE)))
 		return FALSE;
 
 	urls = purple_conversation_get_data(conv, "TinyURLs");
@@ -238,7 +251,8 @@
 
 	t = g_string_new(*message);
 	g_free(*message);
-	for (iter = urls; iter; iter = iter->next) {
+	for (iter = urls; iter; iter = next) {
+		next = iter->next;
 		if (g_utf8_strlen((char *)iter->data, -1) >= purple_prefs_get_int(PREF_LENGTH)) {
 			int pos, x = 0;
 			gchar *j, *s, *str, *orig;
@@ -256,36 +270,40 @@
 			g_free(str);
 			continue;
 		} else {
-			if (iter->prev) {
-				iter = iter->prev;
-				g_free(iter->next->data);
-				urls = g_list_delete_link(urls, iter->next);
-			} else {
-				g_free(iter->data);
-				g_list_free(urls);
-				urls = NULL;
-			}
+			g_free(iter->data);
+			urls = g_list_delete_link(urls, iter);
 		}
 	}
 	*message = t->str;
 	g_string_free(t, FALSE);
 	if (conv == NULL)
-		conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, *sender);
+		conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender);
 	purple_conversation_set_data(conv, "TinyURLs", urls);
 	return FALSE;
 }
 
-static void received_msg(PurpleAccount *account, char *sender, char *message,
-				PurpleConversation *conv, PurpleMessageFlags flags) {
+static void wrote_msg(PurpleAccount *account, char *sender, char *message,
+				PurpleConversation *conv, PurpleMessageFlags flags)
+{
+	GList *urls;
+
+	urls = purple_conversation_get_data(conv, "TinyURLs");
+	if ((flags & PURPLE_MESSAGE_SEND) || urls == NULL)
+		return;
+
+	process_urls(conv, urls);
+	purple_conversation_set_data(conv, "TinyURLs", NULL);
+}
+
+/* Frees 'urls' */
+static void
+process_urls(PurpleConversation *conv, GList *urls)
+{
+	GList *iter;
 	int c;
-	GList *urls, *iter;
 	FinchConv *fconv = FINCH_CONV(conv);
 	GntTextView *tv = GNT_TEXT_VIEW(fconv->tv);
 
-	urls = purple_conversation_get_data(conv, "TinyURLs");
-	if (!(flags & PURPLE_MESSAGE_RECV) || urls == NULL)
-		return;
-
 	for (iter = urls, c = 0; iter; iter = iter->next) {
 		int i;
 		CbInfo *cbdata;
@@ -312,7 +330,6 @@
 		g_free(url);
 	}
 	g_list_free(urls);
-	purple_conversation_set_data(conv, "TinyURLs", NULL);
 }
 
 static void
@@ -324,20 +341,75 @@
 	g_list_free(urls);
 }
 
+static void tinyurl_notify_fetch_cb(PurpleUtilFetchUrlData *urldata, gpointer cbdata,
+		const gchar *urltext, gsize len, const gchar *error)
+{
+	GntWidget *win = cbdata;
+	GntWidget *label = g_object_get_data(G_OBJECT(win), "info-widget");
+	char *message;
+
+	message = g_strdup_printf(_("TinyURL for above: %s"), urltext);
+	gnt_label_set_text(GNT_LABEL(label), message);
+	g_free(message);
+
+	g_signal_handlers_disconnect_matched(G_OBJECT(win), G_SIGNAL_MATCH_FUNC,
+			0, 0, NULL,
+			G_CALLBACK(purple_util_fetch_url_cancel), NULL);
+}
+
+static void *
+tinyurl_notify_uri(const char *uri)
+{
+	char *fullurl = NULL;
+	GntWidget *win;
+	PurpleUtilFetchUrlData *urlcb;
+
+	/* XXX: The following expects that finch_notify_message gets called. This
+	 * may not always happen, e.g. when another plugin sets its own
+	 * notify_message. So tread carefully. */
+	win = purple_notify_message(NULL, PURPLE_NOTIFY_URI, _("URI"), uri,
+			_("Please wait while TinyURL fetches a shorter URL ..."), NULL, NULL);
+	if (!GNT_IS_WINDOW(win) || !g_object_get_data(G_OBJECT(win), "info-widget"))
+		return win;
+
+	if (g_ascii_strncasecmp(uri, "http://", 7) && g_ascii_strncasecmp(uri, "https://", 8)) {
+		fullurl = g_strdup_printf("%shttp%%3A%%2F%%2F%s",
+				purple_prefs_get_string(PREF_URL), purple_url_encode(uri));
+	} else {
+		fullurl = g_strdup_printf("%s%s", purple_prefs_get_string(PREF_URL),
+				purple_url_encode(uri));
+	}
+
+	/* Store the return value of _fetch_url and destroy that when win is
+	   destroyed, so that the callback for _fetch_url does not try to molest a
+	   non-existent window */
+	urlcb = purple_util_fetch_url(fullurl, TRUE, "finch", FALSE, tinyurl_notify_fetch_cb, win);
+	g_free(fullurl);
+	g_signal_connect_swapped(G_OBJECT(win), "destroy",
+			G_CALLBACK(purple_util_fetch_url_cancel), urlcb);
+
+	return win;
+}
+
 static gboolean
-plugin_load(PurplePlugin *plugin) {
+plugin_load(PurplePlugin *plugin)
+{
+	PurpleNotifyUiOps *ops = purple_notify_get_ui_ops();
+	plugin->extra = ops->notify_uri;
+	ops->notify_uri = tinyurl_notify_uri;
+
 	purple_signal_connect(purple_conversations_get_handle(),
 			"wrote-im-msg",
-			plugin, PURPLE_CALLBACK(received_msg), NULL);
+			plugin, PURPLE_CALLBACK(wrote_msg), NULL);
 	purple_signal_connect(purple_conversations_get_handle(),
 			"wrote-chat-msg",
-			plugin, PURPLE_CALLBACK(received_msg), NULL);
+			plugin, PURPLE_CALLBACK(wrote_msg), NULL);
 	purple_signal_connect(purple_conversations_get_handle(),
-			"receiving-im-msg",
-			plugin, PURPLE_CALLBACK(receiving_msg), NULL);
+			"writing-im-msg",
+			plugin, PURPLE_CALLBACK(writing_msg), NULL);
 	purple_signal_connect(purple_conversations_get_handle(),
-			"receiving-chat-msg",
-			plugin, PURPLE_CALLBACK(receiving_msg), NULL);
+			"writing-chat-msg",
+			plugin, PURPLE_CALLBACK(writing_msg), NULL);
 	purple_signal_connect(purple_conversations_get_handle(),
 			"deleting-conversation",
 			plugin, PURPLE_CALLBACK(free_conv_urls), NULL);
@@ -345,6 +417,15 @@
 	return TRUE;
 }
 
+static gboolean
+plugin_unload(PurplePlugin *plugin)
+{
+	PurpleNotifyUiOps *ops = purple_notify_get_ui_ops();
+	if (ops->notify_uri == tinyurl_notify_uri)
+		ops->notify_uri = plugin->extra;
+	return TRUE;
+}
+
 static PurplePluginPrefFrame *
 get_plugin_pref_frame(PurplePlugin *plugin) {
 
@@ -394,7 +475,7 @@
 	"Richard Nelson <wabz@whatsbeef.net>",
 	PURPLE_WEBSITE,
 	plugin_load,
-	NULL,
+	plugin_unload,
 	NULL,
 	NULL,
 	NULL,
--- a/libpurple/Makefile.am	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/Makefile.am	Tue Jan 12 14:22:02 2010 +0000
@@ -32,7 +32,7 @@
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = purple.pc
 
-SUBDIRS = $(GCONF_DIR) plugins protocols tests . example
+SUBDIRS = $(GCONF_DIR) plugins protocols . tests example
 
 purple_coresources = \
 	account.c \
--- a/libpurple/account.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/account.c	Tue Jan 12 14:22:02 2010 +0000
@@ -1050,9 +1050,22 @@
 	if(account->system_log)
 		purple_log_free(account->system_log);
 
+	while (account->deny) {
+		g_free(account->deny->data);
+		account->deny = g_slist_delete_link(account->deny, account->deny);
+	}
+
+	while (account->permit) {
+		g_free(account->permit->data);
+		account->permit = g_slist_delete_link(account->permit, account->permit);
+	}
+
 	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
 	PURPLE_DBUS_UNREGISTER_POINTER(priv->current_error);
-	g_free(priv->current_error);
+	if (priv->current_error) {
+		g_free(priv->current_error->description);
+		g_free(priv->current_error);
+	}
 	g_free(priv);
 
 	PURPLE_DBUS_UNREGISTER_POINTER(account);
@@ -1328,7 +1341,8 @@
 
 	handles = g_list_remove(handles, info);
 
-	info->auth_cb(info->userdata);
+	if (info->auth_cb != NULL)
+		info->auth_cb(info->userdata);
 
 	purple_signal_emit(purple_accounts_get_handle(),
 			"account-authorization-granted", info->account, info->user);
@@ -1343,7 +1357,8 @@
 
 	handles = g_list_remove(handles, info);
 
-	info->deny_cb(info->userdata);
+	if (info->deny_cb != NULL)
+		info->deny_cb(info->userdata);
 
 	purple_signal_emit(purple_accounts_get_handle(),
 			"account-authorization-denied", info->account, info->user);
@@ -1370,10 +1385,12 @@
 				"account-authorization-requested", account, remote_user));
 
 	if (plugin_return > 0) {
-		auth_cb(user_data);
+		if (auth_cb != NULL)
+			auth_cb(user_data);
 		return NULL;
 	} else if (plugin_return < 0) {
-		deny_cb(user_data);
+		if (deny_cb != NULL)
+			deny_cb(user_data);
 		return NULL;
 	}
 
@@ -2298,7 +2315,7 @@
 
 	gc = purple_account_get_connection(account);
 	if (gc != NULL)
-	        prpl = purple_connection_get_prpl(gc);
+		prpl = purple_connection_get_prpl(gc);
 
 	if (prpl != NULL)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
@@ -2315,7 +2332,7 @@
 	PurplePlugin *prpl = NULL;
 
 	if (gc != NULL)
-	        prpl = purple_connection_get_prpl(gc);
+		prpl = purple_connection_get_prpl(gc);
 
 	if (prpl != NULL)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
@@ -2354,7 +2371,7 @@
 	PurplePlugin *prpl = NULL;
 
 	if (gc != NULL)
-	        prpl = purple_connection_get_prpl(gc);
+		prpl = purple_connection_get_prpl(gc);
 
 	if (prpl != NULL)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
@@ -2371,7 +2388,7 @@
 	PurplePlugin *prpl = NULL;
 
 	if (gc != NULL)
-	        prpl = purple_connection_get_prpl(gc);
+		prpl = purple_connection_get_prpl(gc);
 
 	if (prpl != NULL)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
@@ -2399,7 +2416,7 @@
 	PurplePlugin *prpl = NULL;
 
 	if (gc != NULL)
-	        prpl = purple_connection_get_prpl(gc);
+		prpl = purple_connection_get_prpl(gc);
 
 	if (prpl != NULL)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
@@ -2419,7 +2436,7 @@
 	purple_account_set_password(account, new_pw);
 
 	if (gc != NULL)
-	        prpl = purple_connection_get_prpl(gc);
+		prpl = purple_connection_get_prpl(gc);
 
 	if (prpl != NULL)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
--- a/libpurple/blist.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/blist.c	Tue Jan 12 14:22:02 2010 +0000
@@ -2009,18 +2009,14 @@
 
 	ops = purple_blist_get_ui_ops();
 
-	if (!purplebuddylist->root) {
-		purplebuddylist->root = gnode;
-
-		key = g_utf8_collate_key(group->name, -1);
-		g_hash_table_insert(groups_cache, key, group);
-		return;
+	/* if we're moving to overtop of ourselves, do nothing */
+	if (gnode == node) {
+		if (!purplebuddylist->root)
+			node = NULL;
+		else
+			return;
 	}
 
-	/* if we're moving to overtop of ourselves, do nothing */
-	if (gnode == node)
-		return;
-
 	if (purple_find_group(group->name)) {
 		/* This is just being moved */
 
--- a/libpurple/certificate.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/certificate.c	Tue Jan 12 14:22:02 2010 +0000
@@ -26,8 +26,6 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
-#include <glib.h>
-
 #include "internal.h"
 #include "certificate.h"
 #include "dbus-maybe.h"
@@ -97,8 +95,8 @@
 			         "automatically checked.");
 			break;
 		case PURPLE_CERTIFICATE_CA_UNKNOWN:
-			return _("The root certificate this one claims to be issued by is "
-			         "unknown.");
+			return _("The certificate is not trusted because no certificate "
+			         "that can verify it is currently trusted.");
 			break;
 		case PURPLE_CERTIFICATE_NOT_ACTIVATED:
 			return _("The certificate is not valid yet.");
@@ -1402,13 +1400,15 @@
 		if (flags & PURPLE_CERTIFICATE_NAME_MISMATCH) {
 			gchar *sn = purple_certificate_get_subject_name(peer_crt);
 
-			g_string_append_printf(errors, _("The certificate claims to be "
-						"from \"%s\" instead. This could mean that you are "
-						"not connecting to the service you believe you are."),
-						sn);
-			g_free(sn);
+			if (sn) {
+				g_string_append_printf(errors, _("The certificate claims to be "
+							"from \"%s\" instead. This could mean that you are "
+							"not connecting to the service you believe you are."),
+							sn);
+				g_free(sn);
 
-			flags &= ~PURPLE_CERTIFICATE_NAME_MISMATCH;
+				flags &= ~PURPLE_CERTIFICATE_NAME_MISMATCH;
+			}
 		}
 
 		while (i != PURPLE_CERTIFICATE_LAST) {
@@ -1431,9 +1431,8 @@
 	tls_peers = purple_certificate_find_pool(x509_tls_cached.scheme_name,
 						 "tls_peers");
 	if (tls_peers) {
-		if (!purple_certificate_pool_contains(tls_peers, vrq->subject_name) &&
-		        !purple_certificate_pool_store(tls_peers,vrq->subject_name,
-		                                       peer_crt)) {
+		if (!purple_certificate_pool_store(tls_peers,vrq->subject_name,
+		                                   peer_crt)) {
 			purple_debug_error("certificate/x509/tls_cached",
 			                   "FAILED to cache peer certificate\n");
 		}
--- a/libpurple/cipher.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/cipher.c	Tue Jan 12 14:22:02 2010 +0000
@@ -50,10 +50,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#include <glib.h>
-#include <string.h>
-#include <stdio.h>
-
 #include "internal.h"
 #include "cipher.h"
 #include "dbus-maybe.h"
--- a/libpurple/cmds.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/cmds.c	Tue Jan 12 14:22:02 2010 +0000
@@ -21,8 +21,6 @@
  *
  */
 
-#include <string.h>
-
 #include "internal.h"
 
 #include "account.h"
--- a/libpurple/conversation.h	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/conversation.h	Tue Jan 12 14:22:02 2010 +0000
@@ -368,7 +368,8 @@
  * @param type    The type of conversation.
  * @param account The account opening the conversation window on the purple
  *                user's end.
- * @param name    The name of the conversation.
+ * @param name    The name of the conversation.  For PURPLE_CONV_TYPE_IM,
+ *                this is the name of the buddy.
  *
  * @return The new conversation.
  */
@@ -1025,7 +1026,8 @@
 GList *purple_conv_chat_set_users(PurpleConvChat *chat, GList *users);
 
 /**
- * Returns a list of users in the chat room.
+ * Returns a list of users in the chat room.  The members of the list
+ * are PurpleConvChatBuddy objects.
  *
  * @param chat The chat.
  *
--- a/libpurple/dbus-server.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/dbus-server.c	Tue Jan 12 14:22:02 2010 +0000
@@ -25,14 +25,16 @@
 #define DBUS_API_SUBJECT_TO_CHANGE
 #endif
 
+/* Allow the code below to see deprecated functions, so we can continue to
+ * export them via DBus. */
+#undef PURPLE_DISABLE_DEPRECATED
+
+#include "internal.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-/* Allow the code below to see deprecated functions, so we can continue to
- * export them via DBus. */
-#undef PURPLE_DISABLE_DEPRECATED
-
 #include "account.h"
 #include "blist.h"
 #include "conversation.h"
@@ -42,7 +44,6 @@
 #include "dbus-bindings.h"
 #include "debug.h"
 #include "core.h"
-#include "internal.h"
 #include "savedstatuses.h"
 #include "smiley.h"
 #include "util.h"
@@ -600,7 +601,6 @@
 {
 	static DBusObjectPathVTable vtable = {NULL, &purple_dbus_dispatch, NULL, NULL, NULL, NULL};
 	DBusError error;
-	int result;
 
 	dbus_error_init(&error);
 	purple_dbus_connection = dbus_bus_get(DBUS_BUS_STARTER, &error);
@@ -624,16 +624,15 @@
 		return;
 	}
 
-	dbus_request_name_reply =
-	result = dbus_bus_request_name(purple_dbus_connection,
+	dbus_request_name_reply = dbus_bus_request_name(purple_dbus_connection,
 			DBUS_SERVICE_PURPLE, 0, &error);
 
 	if (dbus_error_is_set(&error))
 	{
 		dbus_connection_unref(purple_dbus_connection);
-		dbus_error_free(&error);
 		purple_dbus_connection = NULL;
 		init_error = g_strdup_printf(N_("Failed to get serv name: %s"), error.name);
+		dbus_error_free(&error);
 		return;
 	}
 
--- a/libpurple/debug.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/debug.c	Tue Jan 12 14:22:02 2010 +0000
@@ -23,8 +23,8 @@
  * 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 "debug.h"
-#include "internal.h"
 #include "prefs.h"
 #include "util.h"
 
--- a/libpurple/desktopitem.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/desktopitem.c	Tue Jan 12 14:22:02 2010 +0000
@@ -53,12 +53,12 @@
  * Boston, MA 02111-1301, USA.
  */
 
+#include "internal.h"
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
 #include "desktopitem.h"
-#include "internal.h"
 
 struct _PurpleDesktopItem {
 	int refcount;
--- a/libpurple/dnsquery.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/dnsquery.c	Tue Jan 12 14:22:02 2010 +0000
@@ -172,6 +172,7 @@
 	return FALSE;
 }
 
+#ifdef USE_IDN
 static gboolean
 dns_str_is_ascii(const char *name)
 {
@@ -183,6 +184,7 @@
 
 	return TRUE;
 }
+#endif
 
 #if defined(PURPLE_DNSQUERY_USE_FORK)
 
@@ -293,12 +295,11 @@
 			rc = purple_network_convert_idn_to_ascii(dns_params.hostname, &hostname);
 			if (rc != 0) {
 				write_to_parent(child_out, &rc, sizeof(rc));
-				close(child_out);
 				if (show_debug)
 					fprintf(stderr, "dns[%d] Error: IDN conversion returned "
 							"%d\n", getpid(), rc);
 				dns_params.hostname[0] = '\0';
-				continue;
+				break;
 			}
 		} else /* intentional to execute the g_strdup */
 #endif
@@ -323,12 +324,13 @@
 		rc = getaddrinfo(hostname, servname, &hints, &res);
 		write_to_parent(child_out, &rc, sizeof(rc));
 		if (rc != 0) {
-			close(child_out);
 			if (show_debug)
 				printf("dns[%d] Error: getaddrinfo returned %d\n",
 					getpid(), rc);
 			dns_params.hostname[0] = '\0';
-			continue;
+			g_free(hostname);
+			hostname = NULL;
+			break;
 		}
 		tmp = res;
 		while (res) {
@@ -774,11 +776,8 @@
 	if (!dns_str_is_ascii(query_data->hostname)) {
 		rc = purple_network_convert_idn_to_ascii(query_data->hostname, &hostname);
 		if (rc != 0) {
-			/* FIXME: Dirty 2.6.0 string freeze hack */
-			char tmp[8];
-			g_snprintf(tmp, sizeof(tmp), "%d", rc);
-			query_data->error_message = g_strdup_printf(_("Error resolving %s:\n%s"),
-					query_data->hostname, tmp);
+			query_data->error_message = g_strdup_printf(_("Error converting %s "
+					"to punycode: %d"), query_data->hostname, rc);
 			/* back to main thread */
 			purple_timeout_add(0, dns_main_thread_cb, query_data);
 			return 0;
@@ -918,7 +917,6 @@
 	PurpleDnsQueryData *query_data;
 	struct sockaddr_in sin;
 	GSList *hosts = NULL;
-	char *hostname;
 
 	query_data = data;
 	query_data->timeout = 0;
@@ -931,6 +929,7 @@
 
 	if (!inet_aton(query_data->hostname, &sin.sin_addr)) {
 		struct hostent *hp;
+		gchar *hostname;
 #ifdef USE_IDN
 		if (!dns_str_is_ascii(query_data->hostname)) {
 			int ret = purple_network_convert_idn_to_ascii(query_data->hostname,
@@ -951,16 +950,17 @@
 			g_snprintf(message, sizeof(message), _("Error resolving %s: %d"),
 					query_data->hostname, h_errno);
 			purple_dnsquery_failed(query_data, message);
+			g_free(hostname);
 			return FALSE;
 		}
 		memset(&sin, 0, sizeof(struct sockaddr_in));
 		memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
 		sin.sin_family = hp->h_addrtype;
+		g_free(hostname);
 	} else
 		sin.sin_family = AF_INET;
 	sin.sin_port = htons(query_data->port);
 
-	g_free(hostname);
 	hosts = g_slist_append(hosts, GINT_TO_POINTER(sizeof(sin)));
 	hosts = g_slist_append(hosts, g_memdup(&sin, sizeof(sin)));
 
--- a/libpurple/dnsquery.h	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/dnsquery.h	Tue Jan 12 14:22:02 2010 +0000
@@ -30,6 +30,11 @@
 #include "eventloop.h"
 #include "account.h"
 
+/**
+ * An opaque structure representing a DNS query.  The hostname and port
+ * associated with the query can be retrieved using
+ * purple_dnsquery_get_host() and purple_dnsquery_get_port().
+ */
 typedef struct _PurpleDnsQueryData PurpleDnsQueryData;
 
 /**
--- a/libpurple/dnssrv.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/dnssrv.c	Tue Jan 12 14:22:02 2010 +0000
@@ -248,6 +248,7 @@
 	return list;
 }
 
+#ifdef USE_IDN
 static gboolean
 dns_str_is_ascii(const char *name)
 {
@@ -259,8 +260,60 @@
 
 	return TRUE;
 }
+#endif
 
 #ifndef _WIN32
+static void
+write_to_parent(int in, int out, gconstpointer data, gsize size)
+{
+	const guchar *buf = data;
+	gssize w;
+
+	do {
+		w = write(out, buf, size);
+		if (w > 0) {
+			buf += w;
+			size -= w;
+		} else if (w < 0 && errno == EINTR) {
+			/* Let's try some more; */
+			w = 1;
+		}
+	} while (size > 0 && w > 0);
+
+	if (size != 0) {
+		/* An error occurred */
+		close(out);
+		close(in);
+		_exit(0);
+	}
+}
+
+/* Read size bytes to data. Dies if an error occurs. */
+static void
+read_from_parent(int in, int out, gpointer data, gsize size)
+{
+	guchar *buf = data;
+	gssize r;
+
+	do {
+		r = read(in, data, size);
+		if (r > 0) {
+			buf += r;
+			size -= r;
+		} else if (r < 0 && errno == EINTR) {
+			/* Let's try some more; */
+			r = 1;
+		}
+	} while (size > 0 && r > 0);
+
+	if (size != 0) {
+		/* An error occurred */
+		close(out);
+		close(in);
+		_exit(0);
+	}
+}
+
 
 G_GNUC_NORETURN static void
 resolve(int in, int out)
@@ -279,16 +332,12 @@
 	purple_restore_default_signal_handlers();
 #endif
 
-	if (read(in, &query, sizeof(query)) <= 0) {
-		close(out);
-		close(in);
-		_exit(0);
-	}
+	read_from_parent(in, out, &query, sizeof(query));
 
 	size = res_query( query.query, C_IN, query.type, (u_char*)&answer, sizeof( answer));
 	if (size == -1) {
-		write(out, &(query.type), sizeof(query.type));
-		write(out, &size, sizeof(int));
+		write_to_parent(in, out, &(query.type), sizeof(query.type));
+		write_to_parent(in, out, &size, sizeof(size));
 		close(out);
 		close(in);
 		_exit(0);
@@ -353,16 +402,18 @@
 	if (query.type == T_SRV)
 		ret = purple_srv_sort(ret);
 
-	/* TODO: Check return value */
-	write(out, &(query.type), sizeof(query.type));
-	write(out, &size, sizeof(size));
+	write_to_parent(in, out, &(query.type), sizeof(query.type));
+	write_to_parent(in, out, &size, sizeof(size));
 	while (ret != NULL)
 	{
-		/* TODO: Check return value */
 		if (query.type == T_SRV)
-			write(out, ret->data, sizeof(PurpleSrvResponse));
-		if (query.type == T_TXT)
-			write(out, ret->data, sizeof(PurpleTxtResponse));
+			write_to_parent(in, out, ret->data, sizeof(PurpleSrvResponse));
+		if (query.type == T_TXT) {
+			PurpleTxtResponse *response = ret->data;
+			gsize l = strlen(response->content) + 1 /* null byte */;
+			write_to_parent(in, out, &l, sizeof(l));
+			write_to_parent(in, out, response->content, l);
+		}
 
 		g_free(ret->data);
 		ret = g_list_remove(ret, ret->data);
@@ -429,21 +480,38 @@
 					PurpleTxtCallback cb = query_data->cb.txt;
 					ssize_t red;
 					purple_debug_info("dnssrv","found %d TXT entries\n", size);
-					res = g_new0(PurpleTxtResponse, 1);
 					for (i = 0; i < size; i++) {
-						red = read(source, res, sizeof(PurpleTxtResponse));
-						if (red != sizeof(PurpleTxtResponse)) {
+						gsize len;
+
+						red = read(source, &len, sizeof(len));
+						if (red != sizeof(len)) {
 							purple_debug_error("dnssrv","unable to read txt "
-									"response: %s\n", g_strerror(errno));
+									"response length: %s\n", g_strerror(errno));
 							size = 0;
-							g_free(res);
 							g_list_foreach(responses, (GFunc)purple_txt_response_destroy, NULL);
 							g_list_free(responses);
 							responses = NULL;
 							break;
 						}
+
+						res = g_new0(PurpleTxtResponse, 1);
+						res->content = g_new0(gchar, len);
+
+						red = read(source, res->content, len);
+						if (red != len) {
+							purple_debug_error("dnssrv","unable to read txt "
+									"response: %s\n", g_strerror(errno));
+							size = 0;
+							purple_txt_response_destroy(res);
+							g_list_foreach(responses, (GFunc)purple_txt_response_destroy, NULL);
+							g_list_free(responses);
+							responses = NULL;
+							break;
+						}
+						responses = g_list_prepend(responses, res);
 					}
 
+					responses = g_list_reverse(responses);
 					cb(responses, query_data->extradata);
 				} else {
 					purple_debug_error("dnssrv", "type unknown of DNS result entry; errno is %i\n", errno);
@@ -674,6 +742,7 @@
 
 	internal_query.type = T_SRV;
 	strncpy(internal_query.query, query, 255);
+	internal_query.query[255] = '\0';
 
 	if (write(in[1], &internal_query, sizeof(internal_query)) < 0)
 		purple_debug_error("dnssrv", "Could not write to SRV resolver\n");
@@ -787,6 +856,7 @@
 
 	internal_query.type = T_TXT;
 	strncpy(internal_query.query, query, 255);
+	internal_query.query[255] = '\0';
 
 	if (write(in[1], &internal_query, sizeof(internal_query)) < 0)
 		purple_debug_error("dnssrv", "Could not write to TXT resolver\n");
--- a/libpurple/eventloop.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/eventloop.c	Tue Jan 12 14:22:02 2010 +0000
@@ -23,8 +23,8 @@
  * 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 "eventloop.h"
-#include "internal.h"
 
 static PurpleEventLoopUiOps *eventloop_ui_ops = NULL;
 
--- a/libpurple/ft.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/ft.c	Tue Jan 12 14:22:02 2010 +0000
@@ -69,6 +69,30 @@
 	g_free(priv);
 }
 
+static const gchar *
+purple_xfer_status_type_to_string(PurpleXferStatusType type)
+{
+	static const struct {
+		PurpleXferStatusType type;
+		const char *name;
+	} type_names[] = {
+		{ PURPLE_XFER_STATUS_UNKNOWN, "unknown" },
+		{ PURPLE_XFER_STATUS_NOT_STARTED, "not started" },
+		{ PURPLE_XFER_STATUS_ACCEPTED, "accepted" },
+		{ PURPLE_XFER_STATUS_STARTED, "started" },
+		{ PURPLE_XFER_STATUS_DONE, "done" },
+		{ PURPLE_XFER_STATUS_CANCEL_LOCAL, "cancelled locally" },
+		{ PURPLE_XFER_STATUS_CANCEL_REMOTE, "cancelled remotely" }
+	};
+	int i;
+
+	for (i = 0; i < G_N_ELEMENTS(type_names); ++i)
+		if (type_names[i].type == type)
+			return type_names[i].name;
+
+	return "invalid state";
+}
+
 GList *
 purple_xfers_get_all()
 {
@@ -109,6 +133,10 @@
 		ui_ops->new_xfer(xfer);
 
 	xfers = g_list_prepend(xfers, xfer);
+
+	if (purple_debug_is_verbose())
+		purple_debug_info("xfer", "new %p [%d]\n", xfer, xfer->ref);
+
 	return xfer;
 }
 
@@ -119,6 +147,9 @@
 
 	g_return_if_fail(xfer != NULL);
 
+	if (purple_debug_is_verbose())
+		purple_debug_info("xfer", "destroyed %p [%d]\n", xfer, xfer->ref);
+
 	/* Close the file browser, if it's open */
 	purple_request_close_with_handle(xfer);
 
@@ -148,6 +179,9 @@
 	g_return_if_fail(xfer != NULL);
 
 	xfer->ref++;
+
+	if (purple_debug_is_verbose())
+		purple_debug_info("xfer", "ref'd %p [%d]\n", xfer, xfer->ref);
 }
 
 void
@@ -158,6 +192,9 @@
 
 	xfer->ref--;
 
+	if (purple_debug_is_verbose())
+		purple_debug_info("xfer", "unref'd %p [%d]\n", xfer, xfer->ref);
+
 	if (xfer->ref == 0)
 		purple_xfer_destroy(xfer);
 }
@@ -167,6 +204,11 @@
 {
 	g_return_if_fail(xfer != NULL);
 
+	if (purple_debug_is_verbose())
+		purple_debug_info("xfer", "Changing status of xfer %p from %s to %s\n",
+				xfer, purple_xfer_status_type_to_string(xfer->status),
+				purple_xfer_status_type_to_string(status));
+
 	if (xfer->status == status)
 		return;
 
@@ -229,7 +271,7 @@
 	escaped = g_markup_escape_text(message, -1);
 
 	if (is_error)
-		flags = PURPLE_MESSAGE_ERROR;
+		flags |= PURPLE_MESSAGE_ERROR;
 
 	purple_conversation_write(conv, NULL, escaped, flags, time(NULL));
 	g_free(escaped);
@@ -268,14 +310,16 @@
 purple_xfer_choose_file_ok_cb(void *user_data, const char *filename)
 {
 	PurpleXfer *xfer;
+	PurpleXferType type;
 	struct stat st;
 	gchar *dir;
 
 	xfer = (PurpleXfer *)user_data;
+	type = purple_xfer_get_type(xfer);
 
 	if (g_stat(filename, &st) != 0) {
 		/* File not found. */
-		if (purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE) {
+		if (type == PURPLE_XFER_RECEIVE) {
 #ifndef _WIN32
 			int mode = W_OK;
 #else
@@ -297,29 +341,26 @@
 		}
 		else {
 			purple_xfer_show_file_error(xfer, filename);
-			purple_xfer_request_denied(xfer);
+			purple_xfer_cancel_local(xfer);
 		}
 	}
-	else if ((purple_xfer_get_type(xfer) == PURPLE_XFER_SEND) &&
-			 (st.st_size == 0)) {
+	else if ((type == PURPLE_XFER_SEND) && (st.st_size == 0)) {
 
 		purple_notify_error(NULL, NULL,
 						  _("Cannot send a file of 0 bytes."), NULL);
 
-		purple_xfer_request_denied(xfer);
+		purple_xfer_cancel_local(xfer);
 	}
-	else if ((purple_xfer_get_type(xfer) == PURPLE_XFER_SEND) &&
-			 S_ISDIR(st.st_mode)) {
+	else if ((type == PURPLE_XFER_SEND) && S_ISDIR(st.st_mode)) {
 		/*
 		 * XXX - Sending a directory should be valid for some protocols.
 		 */
 		purple_notify_error(NULL, NULL,
 						  _("Cannot send a directory."), NULL);
 
-		purple_xfer_request_denied(xfer);
+		purple_xfer_cancel_local(xfer);
 	}
-	else if ((purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE) &&
-			 S_ISDIR(st.st_mode)) {
+	else if ((type == PURPLE_XFER_RECEIVE) && S_ISDIR(st.st_mode)) {
 		char *msg, *utf8;
 		utf8 = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);
 		msg = g_strdup_printf(
@@ -329,6 +370,23 @@
 		g_free(msg);
 		purple_xfer_request_denied(xfer);
 	}
+	else if (type == PURPLE_XFER_SEND) {
+#ifndef _WIN32
+		int mode = R_OK;
+#else
+		int mode = F_OK;
+#endif
+
+		if (g_access(filename, mode) == 0) {
+			purple_xfer_request_accepted(xfer, filename);
+		} else {
+			purple_xfer_ref(xfer);
+			purple_notify_message(
+				NULL, PURPLE_NOTIFY_MSG_ERROR, NULL,
+				_("File is not readable."), NULL,
+				(PurpleNotifyCloseCallback)purple_xfer_choose_file, xfer);
+		}
+	}
 	else {
 		purple_xfer_request_accepted(xfer, filename);
 	}
@@ -342,7 +400,11 @@
 	PurpleXfer *xfer = (PurpleXfer *)user_data;
 
 	purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_CANCEL_LOCAL);
-	purple_xfer_request_denied(xfer);
+	if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND)
+		purple_xfer_cancel_local(xfer);
+	else
+		purple_xfer_request_denied(xfer);
+	purple_xfer_unref(xfer);
 }
 
 static int
@@ -506,6 +568,8 @@
 	type = purple_xfer_get_type(xfer);
 	account = purple_xfer_get_account(xfer);
 
+	purple_debug_misc("xfer", "request accepted for %p\n", xfer); 
+
 	if (!filename && type == PURPLE_XFER_RECEIVE) {
 		xfer->status = PURPLE_XFER_STATUS_ACCEPTED;
 		xfer->ops.init(xfer);
@@ -583,6 +647,8 @@
 {
 	g_return_if_fail(xfer != NULL);
 
+	purple_debug_misc("xfer", "xfer %p denied\n", xfer);
+
 	if (xfer->ops.request_denied != NULL)
 		xfer->ops.request_denied(xfer);
 
@@ -1030,7 +1096,7 @@
 				 * watcher.
 				 */
 				if (xfer->watcher != 0) {
-					purple_timeout_remove(xfer->watcher);
+					purple_input_remove(xfer->watcher);
 					xfer->watcher = 0;
 				}
 
@@ -1111,6 +1177,8 @@
 
 			purple_input_remove(xfer->watcher);
 			xfer->watcher = 0;
+
+			purple_debug_misc("xfer", "prpl is ready on ft %p, waiting for UI\n", xfer);
 			return;
 		}
 	}
@@ -1173,8 +1241,12 @@
 	priv = g_hash_table_lookup(xfers_data, xfer);
 	priv->ready |= PURPLE_XFER_READY_UI;
 
-	if (0 == (priv->ready & PURPLE_XFER_READY_PRPL))
+	if (0 == (priv->ready & PURPLE_XFER_READY_PRPL)) {
+		purple_debug_misc("xfer", "UI is ready on ft %p, waiting for prpl\n", xfer);
 		return;
+	}
+
+	purple_debug_misc("xfer", "UI (and prpl) ready on ft %p, so proceeding\n", xfer);
 
 	type = purple_xfer_get_type(xfer);
 	if (type == PURPLE_XFER_SEND)
@@ -1201,8 +1273,12 @@
 	priv->ready |= PURPLE_XFER_READY_PRPL;
 
 	/* I don't think fwrite/fread are ever *not* ready */
-	if (xfer->dest_fp == NULL && 0 == (priv->ready & PURPLE_XFER_READY_UI))
+	if (xfer->dest_fp == NULL && 0 == (priv->ready & PURPLE_XFER_READY_UI)) {
+		purple_debug_misc("xfer", "prpl is ready on ft %p, waiting for UI\n", xfer);
 		return;
+	}
+
+	purple_debug_misc("xfer", "Prpl (and UI) ready on ft %p, so proceeding\n", xfer);
 
 	priv->ready = PURPLE_XFER_READY_NONE;
 
--- a/libpurple/ft.h	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/ft.h	Tue Jan 12 14:22:02 2010 +0000
@@ -160,7 +160,10 @@
 
 	PurpleXferStatusType status;    /**< File Transfer's status.             */
 
-	/* I/O operations. */
+	/** I/O operations, which should be set by the prpl using
+	 *  purple_xfer_set_init_fnc() and friends.  Setting #init is
+	 *  mandatory; all others are optional.
+	 */
 	struct
 	{
 		void (*init)(PurpleXfer *xfer);
@@ -674,7 +677,7 @@
 void purple_xfer_ui_ready(PurpleXfer *xfer);
 
 /**
- * Allows the prpl to signal it's readh to send/receive data (depending on
+ * Allows the prpl to signal it's ready to send/receive data (depending on
  * the direction of the file transfer. Used when the prpl provides read/write
  * ops and cannot/does not provide a raw fd to the core.
  *
--- a/libpurple/imgstore.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/imgstore.c	Tue Jan 12 14:22:02 2010 +0000
@@ -25,7 +25,6 @@
  *
 */
 
-#include <glib.h>
 #include "internal.h"
 
 #include "dbus-maybe.h"
--- a/libpurple/media.c	Wed Sep 23 14:48:57 2009 +0000
+++ b/libpurple/media.c	Tue Jan 12 14:22:02 2010 +0000
@@ -24,8 +24,6 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
-#include <string.h>
-
 #include "internal.h"
 
 #include "account.h"
@@ -103,6 +101,8 @@
 	gboolean initiator;
 	gboolean accepted;
 	gboolean candidates_prepared;
+	gboolean held;
+	gboolean paused;
 
 	GList *active_local_candidates;
 	GList *active_remote_candidates;
@@ -281,7 +281,7 @@
 			{ PURPLE_MEDIA_INFO_HOLD,
 					"PURPLE_MEDIA_INFO_HOLD", "hold" },
 			{ PURPLE_MEDIA_INFO_UNHOLD,
-					"PURPLE_MEDIA_INFO_HOLD", "unhold" },
+					"PURPLE_MEDIA_INFO_UNHOLD", "unhold" },
 			{ 0, NULL, NULL }
 		};
 		type = g_enum_register_static("PurpleMediaInfoType", values);
@@ -2279,7 +2279,8 @@
 					stream->session->type), NULL);
 			stream->accepted = TRUE;
 
-			if (stream->remote_candidates != NULL) {
+			if (stream->remote_candidates != NULL &&
+					stream->initiator == FALSE) {
 				GError *err = NULL;
 				fs_stream_set_remote_candidates(stream->stream,
 						stream->remote_candidates, &err);
@@ -2330,11 +2331,46 @@
 		for (; streams; streams = g_list_delete_link(streams, streams)) {
 			PurpleMediaStream *stream = streams->data;