changeset 22525:86c18b2a16cc

merge of '541f6529c3dbec16782707ce37eb8206f95fc92e' and 'e4c829c5c55062700c14f234887b29ade8239b63'
author Etan Reisner <pidgin@unreliablesource.net>
date Tue, 04 Mar 2008 02:48:30 +0000
parents d9105ead88dc (diff) 2f7b42cc612c (current diff)
children deb07e7d8679
files
diffstat 27 files changed, 258 insertions(+), 161 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Fri Feb 29 04:12:32 2008 +0000
+++ b/COPYRIGHT	Tue Mar 04 02:48:30 2008 +0000
@@ -327,6 +327,7 @@
 Peter Ruibal
 Sam S.
 Thanumalayan S.
+Tomasz Sałaciński <tsalacinski@gmail.com>
 Pradyumna Sampath
 Arvind Samptur
 Tom Samstag
--- a/ChangeLog	Fri Feb 29 04:12:32 2008 +0000
+++ b/ChangeLog	Tue Mar 04 02:48:30 2008 +0000
@@ -1,6 +1,6 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
-version 2.4.0 (??/??/2008):
+version 2.4.0 (02/29/2008):
 	libpurple:
 	* Added support for offline messages for AIM accounts (thanks to
 	  Matthew Goldstein)
@@ -29,7 +29,7 @@
 
 	Pidgin:
 	* Added the ability to theme conversation name colors (red and blue)
-	  through your GTK+ theme, and exposed those theme settings to the 
+	  through your GTK+ theme, and exposed those theme settings to the
 	  Pidgin GTK+ Theme Control plugin (Dustin Howett)
 	* Fixed having multiple alias edit areas in the infopane (Elliott Sales
 	  de Andrade)
@@ -62,7 +62,7 @@
 		NOTE: Due to the way this release was made, it is possible that
 		      bugs marked as fixed in 2.3.1 will not be fixed until the
 		      next release.
-	
+
 	* Fixed a number of MSN bugs introduced in 2.3.0, resolving problems
 	  connecting to MSN and random local display name changes
 	* Going idle on MySpaceIM will no longer clear your status and message.
--- a/ChangeLog.API	Fri Feb 29 04:12:32 2008 +0000
+++ b/ChangeLog.API	Tue Mar 04 02:48:30 2008 +0000
@@ -1,6 +1,6 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
-version 2.4.0 (??/??/????):
+version 2.4.0 (02/29/2008):
 	libpurple:
 		Added:
 		* purple_certificate_add_ca_search_path. (Florian Quèze)
--- a/ChangeLog.win32	Fri Feb 29 04:12:32 2008 +0000
+++ b/ChangeLog.win32	Tue Mar 04 02:48:30 2008 +0000
@@ -1,3 +1,11 @@
+version 2.4.0 (02/29/2008):
+	* Updated GTK+ to 2.12.8
+	* Updated include Meanwhile library to include patches referenced at:
+	  https://sourceforge.net/tracker/?func=detail&atid=656718&aid=1626349&group_id=110565
+	* Build the xmpp protocol with SASL support (and include Cyrus SASL
+	  2.1.22).
+
+
 version 2.3.1 (12/7/2007):
 	* No changes
 
--- a/Makefile.am	Fri Feb 29 04:12:32 2008 +0000
+++ b/Makefile.am	Tue Mar 04 02:48:30 2008 +0000
@@ -35,9 +35,6 @@
 apps_in_files = pidgin.desktop.in
 apps_DATA = $(apps_in_files:.desktop.in=.desktop)
 @INTLTOOL_DESKTOP_RULE@
-endif
-
-if ENABLE_GTK
 GTK_DIR=pidgin
 endif
 
--- a/NEWS	Fri Feb 29 04:12:32 2008 +0000
+++ b/NEWS	Tue Mar 04 02:48:30 2008 +0000
@@ -1,6 +1,6 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
-2.4.0 (2/28/2008):
+2.4.0 (2/29/2008):
 	John: While this release took what seems like forever to get out the
 	door, I think it's well worth the wait, especially for Yahoo! users.
 	This release serves up some fixes for long standing bugs and adds
@@ -13,6 +13,14 @@
 	block/unblock buddies. It's now also possible to find chat rooms on
 	many services, e.g. XMPP, IRC, Yahoo! etc. Happy Leap Day!
 
+	Ka-Hing: I think all I've done for this release is committing some
+	patches written by other people.
+
+	Stu: Finally, 2.4.0 lands. I didn't do all that much except complain
+	about things I didn't like or just revert Sean's changes. I'm quite
+	pleased with how well it's turned out in the end.
+	Happy Birthday Fred, you must be nearly 10 now ;-)
+
 2.3.1 (12/7/2007):
 	Stu: I'm sorry for the MSN problems and the plugin crashes in 2.3.0.
 	Hopefully this will redeem us. This fixes a number of bugs. I'm a
--- a/configure.ac	Fri Feb 29 04:12:32 2008 +0000
+++ b/configure.ac	Tue Mar 04 02:48:30 2008 +0000
@@ -46,7 +46,7 @@
 m4_define([purple_lt_current], [4])
 m4_define([purple_major_version], [2])
 m4_define([purple_minor_version], [4])
-m4_define([purple_micro_version], [0])
+m4_define([purple_micro_version], [1])
 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], [4])
 m4_define([gnt_major_version], [2])
 m4_define([gnt_minor_version], [4])
-m4_define([gnt_micro_version], [0])
+m4_define([gnt_micro_version], [1])
 m4_define([gnt_version_suffix], [devel])
 m4_define([gnt_version],
           [gnt_major_version.gnt_minor_version.gnt_micro_version])
--- a/doc/funniest_home_convos.txt	Fri Feb 29 04:12:32 2008 +0000
+++ b/doc/funniest_home_convos.txt	Tue Mar 04 02:48:30 2008 +0000
@@ -505,3 +505,8 @@
 17:14 <a_user> see?
 17:16 <sadrul> I think blocking in pidgin not working is not your biggest
                problem here.
+
+
+12:58 <staggered_ranks> why hasn't support for napster been removed?
+12:58 <deryni> It has.
+12:59 <staggered_ranks> oh.. ok
--- a/doc/ui-ops.dox	Fri Feb 29 04:12:32 2008 +0000
+++ b/doc/ui-ops.dox	Tue Mar 04 02:48:30 2008 +0000
@@ -10,7 +10,7 @@
    - #PurpleCoreUiOps
    - #PurpleDebugUiOps
    - #PurpleDnsQueryUiOps
-   - #PurpleEventLoopUiOps
+   - #PurpleEventLoopUiOps (without this, nothing will work and you will cry)
    - #PurpleIdleUiOps
    - #PurpleNotifyUiOps
    - #PurplePrivacyUiOps
--- a/finch/libgnt/gntwm.c	Fri Feb 29 04:12:32 2008 +0000
+++ b/finch/libgnt/gntwm.c	Tue Mar 04 02:48:30 2008 +0000
@@ -32,7 +32,14 @@
 #endif
 
 #include <glib.h>
-#include <glib/gstdio.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 <ctype.h>
 #include <gmodule.h>
 #include <stdlib.h>
--- a/libpurple/buddyicon.c	Fri Feb 29 04:12:32 2008 +0000
+++ b/libpurple/buddyicon.c	Tue Mar 04 02:48:30 2008 +0000
@@ -701,6 +701,11 @@
 	}
 	unref_filename(old_icon);
 
+	if (img)
+		g_hash_table_insert(pointer_icon_cache, account, img);
+	else
+		g_hash_table_remove(pointer_icon_cache, account);
+	
 	if (purple_account_is_connected(account))
 	{
 		PurpleConnection *gc;
@@ -724,11 +729,6 @@
 	}
 	g_free(old_icon);
 
-	if (img)
-		g_hash_table_insert(pointer_icon_cache, account, img);
-	else
-		g_hash_table_remove(pointer_icon_cache, account);
-
 	return img;
 }
 
--- a/libpurple/eventloop.h	Fri Feb 29 04:12:32 2008 +0000
+++ b/libpurple/eventloop.h	Tue Mar 04 02:48:30 2008 +0000
@@ -42,59 +42,108 @@
 
 } PurpleInputCondition;
 
+/** The type of callbacks to handle events on file descriptors, as passed to
+ *  purple_input_add().  The callback will receive the @c user_data passed to
+ *  purple_input_add(), the file descriptor on which the event occurred, and the
+ *  condition that was satisfied to cause the callback to be invoked.
+ */
 typedef void (*PurpleInputFunction)(gpointer, gint, PurpleInputCondition);
 
+/** @copydoc _PurpleEventLoopUiOps */
 typedef struct _PurpleEventLoopUiOps PurpleEventLoopUiOps;
 
+/** An abstraction of an application's mainloop; libpurple will use this to
+ *  watch file descriptors and schedule timed callbacks.  If your application
+ *  uses the glib mainloop, there is an implementation of this struct in
+ *  <tt>libpurple/example/nullclient.c</tt> which you can use verbatim.
+ */
 struct _PurpleEventLoopUiOps
 {
 	/**
-	 * Creates a callback timer with an interval measured in milliseconds.
-	 * @see g_timeout_add, purple_timeout_add
+	 * Should create a callback timer with an interval measured in
+	 * milliseconds.  The supplied @a function should be called every @a
+	 * interval seconds until it returns @c FALSE, after which it should not
+	 * be called again.
+	 *
+	 * Analogous to g_timeout_add in glib.
+	 *
+	 * @param interval the interval in <em>milliseconds</em> between calls
+	 *                 to @a function.
+	 * @param data     arbitrary data to be passed to @a function at each
+	 *                 call.
+	 * @todo Who is responsible for freeing @a data?
+	 *
+	 * @return a handle for the timeout, which can be passed to
+	 *         #timeout_remove.
+	 *
+	 * @see purple_timeout_add
 	 **/
 	guint (*timeout_add)(guint interval, GSourceFunc function, gpointer data);
 
 	/**
-	 * Removes a callback timer.
-	 * @see purple_timeout_remove, g_source_remove
+	 * Should remove a callback timer.  Analogous to g_source_remove in glib.
+	 * @param handle an identifier for a timeout, as returned by
+	 *               #timeout_add.
+	 * @return       @c TRUE if the timeout identified by @a handle was
+	 *               found and removed.
+	 * @see purple_timeout_remove
 	 */
 	gboolean (*timeout_remove)(guint handle);
 
 	/**
-	 * Adds an input handler.
-	 * @see purple_input_add, g_io_add_watch_full
+	 * Should add an input handler.  Analogous to g_io_add_watch_full in
+	 * glib.
+	 *
+	 * @param fd        a file descriptor to watch for events
+	 * @param cond      a bitwise OR of events on @a fd for which @a func
+	 *                  should be called.
+	 * @param func      a callback to fire whenever a relevant event on @a
+	 *                  fd occurs.
+	 * @param user_data arbitrary data to pass to @a fd.
+	 * @return          an identifier for this input handler, which can be
+	 *                  passed to #input_remove.
+	 *
+	 * @see purple_input_add
 	 */
 	guint (*input_add)(int fd, PurpleInputCondition cond,
-					   PurpleInputFunction func, gpointer user_data);
+	                   PurpleInputFunction func, gpointer user_data);
 
 	/**
-	 * Removes an input handler.
-	 * @see purple_input_remove, g_source_remove
+	 * Should remove an input handler.  Analogous to g_source_remove in glib.
+	 * @param handle an identifier, as returned by #input_add.
+	 * @return       @c TRUE if the input handler was found and removed.
+	 * @see purple_input_remove
 	 */
 	gboolean (*input_remove)(guint handle);
 	
 	
 	/**
-	 * Get the current error status for an input.
-	 * Implementation of this UI op is optional. Implement it if the UI's sockets
-	 * or event loop needs to customize determination of socket error status.
-	 * @see purple_input_get_error, getsockopt
+	 * If implemented, should get the current error status for an input.
+	 *
+	 * Implementation of this UI op is optional. Implement it if the UI's
+	 * sockets or event loop needs to customize determination of socket
+	 * error status.  If unimplemented, <tt>getsockopt(2)</tt> will be used
+	 * instead.
+	 *
+	 * @see purple_input_get_error
 	 */
 	int (*input_get_error)(int fd, int *error);
 
 	/**
-	 * Creates a callback timer with an interval measured in seconds.
+	 * If implemented, should create a callback timer with an interval
+	 * measured in seconds.  Analogous to g_timeout_add_seconds in glib.
 	 *
 	 * This allows UIs to group timers for better power efficiency.  For
 	 * this reason, @a interval may be rounded by up to a second.
 	 *
 	 * Implementation of this UI op is optional.  If it's not implemented,
-	 * calls to purple_timeout_add_seconds() will be serviced by the
-	 * timeout_add UI op.
+	 * calls to purple_timeout_add_seconds() will be serviced by
+	 * #timeout_add.
 	 *
-	 * @see g_timeout_add_seconds, purple_timeout_add_seconds()
+	 * @see purple_timeout_add_seconds()
 	 **/
-	guint (*timeout_add_seconds)(guint interval, GSourceFunc function, gpointer data);
+	guint (*timeout_add_seconds)(guint interval, GSourceFunc function,
+	                             gpointer data);
 
 	void (*_purple_reserved2)(void);
 	void (*_purple_reserved3)(void);
@@ -118,8 +167,8 @@
  *                      milliseconds.
  * @param function	The function to call.
  * @param data		data to pass to @a function.
- * @return A handle to the timer which can be passed to 
- *         purple_timeout_remove to remove the timer.
+ * @return A handle to the timer which can be passed to
+ *         purple_timeout_remove() to remove the timer.
  */
 guint purple_timeout_add(guint interval, GSourceFunc function, gpointer data);
 
@@ -137,7 +186,7 @@
  * @param function	The function to call.
  * @param data		data to pass to @a function.
  * @return A handle to the timer which can be passed to 
- *         purple_timeout_remove to remove the timer.
+ *         purple_timeout_remove() to remove the timer.
  *
  * @since 2.1.0
  */
@@ -146,9 +195,9 @@
 /**
  * Removes a timeout handler.
  *
- * @param handle The handle, as returned by purple_timeout_add.
+ * @param handle The handle, as returned by purple_timeout_add().
  *
- * @return Something.
+ * @return @c TRUE if the handler was successfully removed.
  */
 gboolean purple_timeout_remove(guint handle);
 
@@ -164,26 +213,29 @@
  * @see g_io_add_watch_full
  */
 guint purple_input_add(int fd, PurpleInputCondition cond,
-					 PurpleInputFunction func, gpointer user_data);
+                       PurpleInputFunction func, gpointer user_data);
 
 /**
  * Removes an input handler.
  *
  * @param handle The handle of the input handler. Note that this is the return
- * value from purple_input_add, <i>not</i> the file descriptor.
+ *               value from purple_input_add(), <i>not</i> the file descriptor.
  */
 gboolean purple_input_remove(guint handle);
 
 /**
  * Get the current error status for an input.
+ *
  * The return value and error follow getsockopt() with a level of SOL_SOCKET and an
  * option name of SO_ERROR, and this is how the error is determined if the UI does not
  * implement the input_get_error UI op.
  *
  * @param fd        The input file descriptor.
- * @param error		A pointer to an int which on return will have the error, or 0 if no error.
+ * @param error     A pointer to an @c int which on return will have the error, or
+ *                  @c 0 if no error.
  *
- * @return 0 if there is no error; -1 if there is an error, in which case errno will be set.
+ * @return @c 0 if there is no error; @c -1 if there is an error, in which case
+ *         @a errno will be set.
  */
 int
 purple_input_get_error(int fd, int *error);
--- a/libpurple/plugin.c	Fri Feb 29 04:12:32 2008 +0000
+++ b/libpurple/plugin.c	Tue Mar 04 02:48:30 2008 +0000
@@ -924,7 +924,7 @@
 	g_return_val_if_fail(plugin, NULL);
 	g_return_val_if_fail(plugin->info, NULL);
 
-	return plugin->info->name;
+	return _(plugin->info->name);
 }
 
 const gchar *
@@ -940,7 +940,7 @@
 	g_return_val_if_fail(plugin, NULL);
 	g_return_val_if_fail(plugin->info, NULL);
 
-	return plugin->info->summary;
+	return _(plugin->info->summary);
 }
 
 const gchar *
@@ -948,7 +948,7 @@
 	g_return_val_if_fail(plugin, NULL);
 	g_return_val_if_fail(plugin->info, NULL);
 
-	return plugin->info->description;
+	return _(plugin->info->description);
 }
 
 const gchar *
@@ -956,7 +956,7 @@
 	g_return_val_if_fail(plugin, NULL);
 	g_return_val_if_fail(plugin->info, NULL);
 
-	return plugin->info->author;
+	return _(plugin->info->author);
 }
 
 const gchar *
--- a/libpurple/protocols/gg/gg.c	Fri Feb 29 04:12:32 2008 +0000
+++ b/libpurple/protocols/gg/gg.c	Tue Mar 04 02:48:30 2008 +0000
@@ -2088,7 +2088,7 @@
 	OPT_PROTO_REGISTER_NOSCREENNAME,
 	NULL,				/* user_splits */
 	NULL,				/* protocol_options */
-	NO_BUDDY_ICONS,			/* icon_spec */
+	{"png", 32, 32, 96, 96, 0, PURPLE_ICON_SCALE_DISPLAY},	/* icon_spec */
 	ggp_list_icon,			/* list_icon */
 	NULL,				/* list_emblem */
 	ggp_status_text,		/* status_text */
--- a/libpurple/protocols/irc/cmds.c	Fri Feb 29 04:12:32 2008 +0000
+++ b/libpurple/protocols/irc/cmds.c	Tue Mar 04 02:48:30 2008 +0000
@@ -294,17 +294,15 @@
 	ops = g_new0(char *, i * 2 + 1);
 
 	for (i = 0; nicks[i]; i++) {
-		if (!*nicks[i]) {
-			g_free(nicks[i]);
-			continue;
+		if (*nicks[i]) {
+			ops[used++] = mode;
+			ops[used++] = nicks[i];
 		}
-		ops[used++] = mode;
-		ops[used++] = nicks[i];
 	}
 
 	irc_do_mode(irc, target, sign, ops);
 	g_free(ops);
-	g_free(nicks);  /* No, not g_strfreev */
+	g_strfreev(nicks);
 
 	return 0;
 }
--- a/libpurple/protocols/jabber/Makefile.mingw	Fri Feb 29 04:12:32 2008 +0000
+++ b/libpurple/protocols/jabber/Makefile.mingw	Tue Mar 04 02:48:30 2008 +0000
@@ -84,7 +84,6 @@
 
 ifeq ($(CYRUS_SASL), 1)
 CYRUS_SASL_TOP := $(WIN32_DEV_TOP)/cyrus-sasl-2.1.22
-CFLAGS += -DHAVE_CYRUS_SASL
 INCLUDE_PATHS += -I$(CYRUS_SASL_TOP)/include
 LIB_PATHS += -L$(CYRUS_SASL_TOP)/lib
 LIBS += -llibsasl
--- a/libpurple/protocols/msn/msnutils.c	Fri Feb 29 04:12:32 2008 +0000
+++ b/libpurple/protocols/msn/msnutils.c	Tue Mar 04 02:48:30 2008 +0000
@@ -201,6 +201,7 @@
 		else
 			*d++ = *c;
 	}
+	*d = '\0';
 
 	return buf;
 }
--- a/libpurple/protocols/msnp9/msn-utils.c	Fri Feb 29 04:12:32 2008 +0000
+++ b/libpurple/protocols/msnp9/msn-utils.c	Tue Mar 04 02:48:30 2008 +0000
@@ -163,6 +163,7 @@
 		else
 			*d++ = *c;
 	}
+	*d = '\0';
 
 	return buf;
 }
--- a/libpurple/protocols/msnp9/nexus.c	Fri Feb 29 04:12:32 2008 +0000
+++ b/libpurple/protocols/msnp9/nexus.c	Tue Mar 04 02:48:30 2008 +0000
@@ -321,7 +321,7 @@
 {
 	MsnNexus *nexus;
 	MsnSession *session;
-	char *username, *password;
+	char *username, *password, *encpass;
 	char *request_str, *head, *tail;
 	char *buffer = NULL;
 	guint32 ctint;
@@ -337,8 +337,9 @@
 	username =
 		g_strdup(purple_url_encode(purple_account_get_username(session->account)));
 
-	password =
-		g_strdup(purple_url_encode(purple_connection_get_password(session->account->gc)));
+	password = g_strndup(purple_connection_get_password(session->account->gc), 16);
+	encpass = g_strdup(purple_url_encode(password));
+	g_free(password);
 
 	ctint = strtoul((char *)g_hash_table_lookup(nexus->challenge_data, "ct"), NULL, 10) + 200;
 
@@ -368,7 +369,7 @@
 		nexus->login_host);
 
 	buffer = g_strdup_printf("%s,pwd=XXXXXXXX,%s\r\n", head, tail);
-	request_str = g_strdup_printf("%s,pwd=%s,%s\r\n", head, password, tail);
+	request_str = g_strdup_printf("%s,pwd=%s,%s\r\n", head, encpass, tail);
 
 	purple_debug_misc("msn", "Sending: {%s}\n", buffer);
 
@@ -376,7 +377,7 @@
 	g_free(head);
 	g_free(tail);
 	g_free(username);
-	g_free(password);
+	g_free(encpass);
 
 	nexus->write_buf = request_str;
 	nexus->written_len = 0;
--- a/libpurple/protocols/myspace/markup.c	Fri Feb 29 04:12:32 2008 +0000
+++ b/libpurple/protocols/myspace/markup.c	Tue Mar 04 02:48:30 2008 +0000
@@ -19,7 +19,7 @@
 
 #include "myspace.h"
 
-typedef void (*MSIM_XMLNODE_CONVERT)(MsimSession *, xmlnode *, gchar **, gchar **);
+typedef int (*MSIM_XMLNODE_CONVERT)(MsimSession *, xmlnode *, gchar **, gchar **);
 
 /* Internal functions */
 
@@ -28,8 +28,8 @@
 static guint msim_height_to_point(MsimSession *session, guint height);
 static guint msim_point_to_height(MsimSession *session, guint point);
 
-static void msim_markup_tag_to_html(MsimSession *, xmlnode *root, gchar **begin, gchar **end);
-static void html_tag_to_msim_markup(MsimSession *, xmlnode *root, gchar **begin, gchar **end);
+static int msim_markup_tag_to_html(MsimSession *, xmlnode *root, gchar **begin, gchar **end);
+static int html_tag_to_msim_markup(MsimSession *, xmlnode *root, gchar **begin, gchar **end);
 static gchar *msim_convert_xml(MsimSession *, const gchar *raw, MSIM_XMLNODE_CONVERT f);
 static gchar *msim_convert_smileys_to_markup(gchar *before);
 static double msim_round(double round);
@@ -396,11 +396,11 @@
 }
 
 /** Convert an individual msim markup tag to HTML. */
-static void 
+static int 
 msim_markup_tag_to_html(MsimSession *session, xmlnode *root, gchar **begin, 
 		gchar **end)
 {
-	g_return_if_fail(root != NULL);
+	g_return_val_if_fail(root != NULL, 0);
 
 	if (g_str_equal(root->name, "f")) {
 		msim_markup_f_to_html(session, root, begin, end);
@@ -421,13 +421,16 @@
 		*begin = g_strdup("");
 		*end = g_strdup("");
 	}
+	return 0;
 }
 
 /** Convert an individual HTML tag to msim markup. */
-static void 
+static int 
 html_tag_to_msim_markup(MsimSession *session, xmlnode *root, gchar **begin, 
 		gchar **end)
 {
+	int ret = 0;
+
 	if (!purple_utf8_strcasecmp(root->name, "root") ||
 	    !purple_utf8_strcasecmp(root->name, "html")) {
 		*begin = g_strdup("");
@@ -437,11 +440,39 @@
 	 * within another one, and only the inner-most formatting will be 
 	 * applied to the text. */
 	} else if (!purple_utf8_strcasecmp(root->name, "b")) {
-		*begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_BOLD);
-		*end = g_strdup("</f>");
+		if (root->child->type == XMLNODE_TYPE_DATA) {
+			*begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_BOLD);
+			*end = g_strdup("</f>");
+		} else {
+			if (!purple_utf8_strcasecmp(root->child->name,"i")) {
+				ret++;
+				if (root->child->child->type == XMLNODE_TYPE_DATA) {
+					*begin = g_strdup_printf("<f s='%d'>", (MSIM_TEXT_BOLD + MSIM_TEXT_ITALIC));
+					*end = g_strdup("</f>");
+				} else {
+					if (!purple_utf8_strcasecmp(root->child->child->name,"u")) {
+						ret++;
+						*begin = g_strdup_printf("<f s='%d'>", (MSIM_TEXT_BOLD + MSIM_TEXT_ITALIC + MSIM_TEXT_UNDERLINE));
+						*end = g_strdup("</f>");
+					}
+				}
+			} else if (!purple_utf8_strcasecmp(root->child->name,"u")) {
+				ret++;
+				*begin = g_strdup_printf("<f s='%d'>", (MSIM_TEXT_BOLD + MSIM_TEXT_UNDERLINE));
+				*end = g_strdup("</f>");
+			}
+		}
 	} else if (!purple_utf8_strcasecmp(root->name, "i")) {
-		*begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_ITALIC);
-		*end = g_strdup("</f>");
+		if (root->child->type == XMLNODE_TYPE_DATA) {
+			*begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_ITALIC);
+			*end = g_strdup("</f>");
+		} else {
+			if (!purple_utf8_strcasecmp(root->child->name,"u")) {
+				ret++;
+				*begin = g_strdup_printf("<f s='%d'>", (MSIM_TEXT_ITALIC + MSIM_TEXT_UNDERLINE));
+				*end = g_strdup("</f>");
+			}
+		}
 	} else if (!purple_utf8_strcasecmp(root->name, "u")) {
 		*begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_UNDERLINE);
 		*end = g_strdup("</f>");
@@ -524,6 +555,7 @@
 		msim_unrecognized(NULL, NULL, err);
 		g_free(err);
 	}
+	return ret;
 }
 
 /** Convert an xmlnode of msim markup or HTML to an HTML string or msim markup.
@@ -533,11 +565,12 @@
  * @return An HTML string. Caller frees.
  */
 static gchar *
-msim_convert_xmlnode(MsimSession *session, xmlnode *root, MSIM_XMLNODE_CONVERT f)
+msim_convert_xmlnode(MsimSession *session, xmlnode *root, MSIM_XMLNODE_CONVERT f, int nodes_processed)
 {
 	xmlnode *node;
 	gchar *begin, *inner, *end;
 	GString *final;
+	int descended = nodes_processed;
 
 	if (!root || !root->name) {
 		return g_strdup("");
@@ -550,36 +583,37 @@
 
 	final = g_string_new("");
 
-	f(session, root, &begin, &end);
+	if (descended == 0) /* We've not formatted this yet.. :) */
+		descended = f(session, root, &begin, &end); /* Get the value that our format function has already descended for us */
 	
 	g_string_append(final, begin);
 
 	/* Loop over all child nodes. */
 	for (node = root->child; node != NULL; node = node->next) {
 		switch (node->type) {
-		case XMLNODE_TYPE_ATTRIB:
-			/* Attributes handled above. */
-			break;
-
-		case XMLNODE_TYPE_TAG:
-			/* A tag or tag with attributes. Recursively descend. */
-			inner = msim_convert_xmlnode(session, node, f);
-			g_return_val_if_fail(inner != NULL, NULL);
+			case XMLNODE_TYPE_ATTRIB:
+				/* Attributes handled above. */
+				break;
 
-			purple_debug_info("msim", " ** node name=%s\n", 
-					(node && node->name) ? node->name : "(NULL)");
-			break;
-	
-		case XMLNODE_TYPE_DATA:
-			/* Literal text. */
-			inner = g_strndup(node->data, node->data_sz);
-			purple_debug_info("msim", " ** node data=%s\n", 
-					inner ? inner : "(NULL)");
-			break;
-			
-		default:
-			purple_debug_info("msim",
-					"msim_convert_xmlnode: strange node\n");
+			case XMLNODE_TYPE_TAG:
+				/* A tag or tag with attributes. Recursively descend. */
+				inner = msim_convert_xmlnode(session, node, f, descended);
+				g_return_val_if_fail(inner != NULL, NULL);
+		
+				purple_debug_info("msim", " ** node name=%s\n", 
+						(node && node->name) ? node->name : "(NULL)");
+				break;
+		
+			case XMLNODE_TYPE_DATA:
+				/* Literal text. */
+				inner = g_strndup(node->data, node->data_sz);
+				purple_debug_info("msim", " ** node data=%s\n", 
+						inner ? inner : "(NULL)");
+				break;
+		
+			default:
+				purple_debug_info("msim",
+						"msim_convert_xmlnode: strange node\n");
 		}
 
 		if (inner) {
@@ -629,7 +663,7 @@
 
 	g_free(enclosed_raw);
 
-	str = msim_convert_xmlnode(session, root, f);
+	str = msim_convert_xmlnode(session, root, f, 0);
 	g_return_val_if_fail(str != NULL, NULL);
 	purple_debug_info("msim", "msim_markup_to_html: returning %s\n", str);
 
--- a/libpurple/protocols/oscar/oscar.c	Fri Feb 29 04:12:32 2008 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Tue Mar 04 02:48:30 2008 +0000
@@ -202,7 +202,7 @@
 void oscar_set_info(PurpleConnection *gc, const char *info);
 static void oscar_set_info_and_status(PurpleAccount *account, gboolean setinfo, const char *rawinfo, gboolean setstatus, PurpleStatus *status);
 static void oscar_set_extendedstatus(PurpleConnection *gc);
-static void oscar_format_screenname(PurpleConnection *gc, const char *nick); 
+static void oscar_format_screenname(PurpleConnection *gc, const char *nick);
 static gboolean purple_ssi_rerequestdata(gpointer data);
 
 static void oscar_free_name_data(struct name_data *data) {
@@ -1040,8 +1040,8 @@
 	if (conn->type == SNAC_FAMILY_AUTH)
 	{
 		aim_request_login(od, conn, purple_account_get_username(account));
-		purple_debug_info("oscar", "Screen name sent, waiting for response\n");
-		purple_connection_update_progress(gc, _("Screen name sent"), 1, OSCAR_CONNECT_STEPS);
+		purple_debug_info("oscar", "Username sent, waiting for response\n");
+		purple_connection_update_progress(gc, _("Username sent"), 1, OSCAR_CONNECT_STEPS);
 		ck[1] = 0x65;
 	}
 	else if (conn->type == SNAC_FAMILY_LOCATE)
@@ -1303,7 +1303,7 @@
 
 	if (!aim_snvalid(purple_account_get_username(account))) {
 		gchar *buf;
-		buf = g_strdup_printf(_("Unable to login: Could not sign on as %s because the screen name is invalid.  Screen names must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), purple_account_get_username(account));
+		buf = g_strdup_printf(_("Unable to login: Could not sign on as %s because the username is invalid.  Usernames must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), purple_account_get_username(account));
 		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, buf);
 		g_free(buf);
 		return;
@@ -1382,14 +1382,14 @@
 	va_end(ap);
 
 	purple_debug_info("oscar",
-			   "inside auth_resp (Screen name: %s)\n", info->sn);
+			   "inside auth_resp (Username: %s)\n", info->sn);
 
 	if (info->errorcode || !info->bosip || !info->cookielen || !info->cookie) {
 		char buf[256];
 		switch (info->errorcode) {
 		case 0x01:
 			/* Unregistered screen name */
-			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_INVALID_USERNAME, _("Invalid screen name."));
+			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_INVALID_USERNAME, _("Invalid username."));
 			break;
 		case 0x05:
 			/* Incorrect password */
@@ -2953,7 +2953,7 @@
 	va_end(ap);
 
 	user_info = purple_notify_user_info_new();
-	purple_notify_user_info_add_pair(user_info, _("Screen Name"), userinfo->sn);
+	purple_notify_user_info_add_pair(user_info, _("Username"), userinfo->sn);
 
 	tmp = g_strdup_printf("%d", (int)((userinfo->warnlevel/10.0) + 0.5));
 	purple_notify_user_info_add_pair(user_info, _("Warning Level"), tmp);
@@ -3941,12 +3941,12 @@
 	gchar *secondary;
 	int i, num;
 	va_list ap;
-	char *email, *SNs;
+	char *email, *usernames;
 
 	va_start(ap, fr);
 	email = va_arg(ap, char *);
 	num = va_arg(ap, int);
-	SNs = va_arg(ap, char *);
+	usernames = va_arg(ap, char *);
 	va_end(ap);
 
 	results = purple_notify_searchresults_new();
@@ -3961,17 +3961,17 @@
 	}
 
 	secondary = g_strdup_printf(
-					dngettext(PACKAGE, "The following screen name is associated with %s",
-						 "The following screen names are associated with %s",
+					dngettext(PACKAGE, "The following username is associated with %s",
+						 "The following usernames are associated with %s",
 						 num),
 					email);
 
-	column = purple_notify_searchresults_column_new(_("Screen name"));
+	column = purple_notify_searchresults_column_new(_("Username"));
 	purple_notify_searchresults_column_add(results, column);
 
 	for (i = 0; i < num; i++) {
-		GList *row = NULL;
-		row = g_list_append(row, g_strdup(&SNs[i * (MAXSNLEN + 1)]));
+		GList *row;
+		row = g_list_append(NULL, g_strdup(&usernames[i * (MAXSNLEN + 1)]));
 		purple_notify_searchresults_row_add(results, row);
 	}
 	purple_notify_searchresults_button_add(results, PURPLE_NOTIFY_BUTTON_ADD,
@@ -4046,32 +4046,23 @@
 
 	if ((err > 0) && (url != NULL)) {
 		char *dialog_msg;
-		char *dialog_top = g_strdup_printf(_("Error Changing Account Info"));
-		switch (err) {
-			case 0x0001: {
-				dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to format screen name because the requested screen name differs from the original."), err);
-			} break;
-			case 0x0006: {
-				dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to format screen name because it is invalid."), err);
-			} break;
-			case 0x000b: {
-				dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to format screen name because the requested screen name is too long."), err);
-			} break;
-			case 0x001d: {
-				dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to change e-mail address because there is already a request pending for this screen name."), err);
-			} break;
-			case 0x0021: {
-				dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to change e-mail address because the given address has too many screen names associated with it."), err);
-			} break;
-			case 0x0023: {
-				dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to change e-mail address because the given address is invalid."), err);
-			} break;
-			default: {
-				dialog_msg = g_strdup_printf(_("Error 0x%04x: Unknown error."), err);
-			} break;
-		}
-		purple_notify_error(gc, NULL, dialog_top, dialog_msg);
-		g_free(dialog_top);
+
+		if (err == 0x0001)
+			dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to format username because the requested name differs from the original."), err);
+		else if (err == 0x0006)
+			dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to format username because it is invalid."), err);
+		else if (err == 0x00b)
+			dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to format username because the requested name is too long."), err);
+		else if (err == 0x001d)
+			dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to change e-mail address because there is already a request pending for this username."), err);
+		else if (err == 0x0021)
+			dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to change e-mail address because the given address has too many usernames associated with it."), err);
+		else if (err == 0x0023)
+			dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to change e-mail address because the given address is invalid."), err);
+		else
+			dialog_msg = g_strdup_printf(_("Error 0x%04x: Unknown error."), err);
+		purple_notify_error(gc, NULL,
+				_("Error Changing Account Info"), dialog_msg);
 		g_free(dialog_msg);
 		return 1;
 	}
@@ -4514,7 +4505,6 @@
 {
 	PurpleConnection *gc = purple_account_get_connection(account);
 	OscarData *od = gc->proto_data;
-	PurplePresence *presence;
 	PurpleStatusType *status_type;
 	PurpleStatusPrimitive primitive;
 
@@ -4530,7 +4520,6 @@
 
 	status_type = purple_status_get_type(status);
 	primitive = purple_status_type_get_primitive(status_type);
-	presence = purple_account_get_presence(account);
 
 	if (!setinfo)
 	{
@@ -4680,7 +4669,7 @@
 
 	if (!aim_snvalid(buddy->name)) {
 		gchar *buf;
-		buf = g_strdup_printf(_("Could not add the buddy %s because the screen name is invalid.  Screen names must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), buddy->name);
+		buf = g_strdup_printf(_("Could not add the buddy %s because the username is invalid.  Usernames must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), buddy->name);
 		if (!purple_conv_present_error(buddy->name, account, buf))
 			purple_notify_error(gc, NULL, _("Unable To Add"), buf);
 		g_free(buf);
@@ -6232,7 +6221,7 @@
 		}
 	} else {
 		purple_notify_error(gc, NULL, _("The new formatting is invalid."),
-						  _("Screen name formatting can change only capitalization and whitespace."));
+						  _("Username formatting can change only capitalization and whitespace."));
 	}
 }
 
@@ -6631,7 +6620,7 @@
 	g_return_val_if_fail(str != NULL, NULL);
 
 	/* copy str to buf and skip all blanks */
-	for (i=0, j=0; str[j] && i < BUF_LEN; i++, j++)
+	for (i=0, j=0; str[j] && i < BUF_LEN - 1; i++, j++)
 	{
 		while (str[j] == ' ')
 			j++;
@@ -6651,18 +6640,7 @@
 gboolean
 oscar_offline_message(const PurpleBuddy *buddy)
 {
-	OscarData *od = NULL;
-	PurpleAccount *account;
-	PurpleConnection *gc = NULL;
-
-	account = purple_buddy_get_account(buddy);
-	if (account != NULL) {
-		gc = purple_account_get_connection(account);
-		if (gc != NULL)
-			od = (OscarData *)gc->proto_data;
-	}
-
-	return (od != NULL && od->icq && aim_snvalid_icq(purple_account_get_username(account)));
+	return TRUE;
 }
 
 /* TODO: Find somewhere to put this instead of including it in a bunch of places.
--- a/libpurple/protocols/zephyr/zephyr.c	Fri Feb 29 04:12:32 2008 +0000
+++ b/libpurple/protocols/zephyr/zephyr.c	Tue Mar 04 02:48:30 2008 +0000
@@ -2235,6 +2235,9 @@
 	char *tmp;
 
 	gc = purple_account_get_connection(account);
+	if (gc == NULL)
+		return NULL;
+
 	tmp = local_zephyr_normalize(gc->proto_data, who);
 
 	if (strlen(tmp) >= sizeof(buf)) {
--- a/libpurple/win32/global.mak	Fri Feb 29 04:12:32 2008 +0000
+++ b/libpurple/win32/global.mak	Tue Mar 04 02:48:30 2008 +0000
@@ -16,7 +16,7 @@
 GTK_BIN ?= $(GTK_TOP)/bin
 BONJOUR_TOP ?= $(WIN32_DEV_TOP)/Bonjour_SDK
 LIBXML2_TOP ?= $(WIN32_DEV_TOP)/libxml2-2.6.30
-MEANWHILE_TOP ?= $(WIN32_DEV_TOP)/meanwhile-1.0.2
+MEANWHILE_TOP ?= $(WIN32_DEV_TOP)/meanwhile-1.0.2_daa1
 NSPR_TOP ?= $(WIN32_DEV_TOP)/nspr-4.6.4
 NSS_TOP ?= $(WIN32_DEV_TOP)/nss-3.11.4
 PERL_LIB_TOP ?= $(WIN32_DEV_TOP)/perl58
@@ -77,6 +77,12 @@
 DISPLAY_VERSION := $(PIDGIN_VERSION)
 endif
 
+CYRUS_SASL ?= 1
+
+ifeq ($(CYRUS_SASL), 1)
+DEFINES += -DHAVE_CYRUS_SASL
+endif
+
 DEFINES += -DHAVE_CONFIG_H
 
 # Use -g flag when building debug version of Pidgin (including plugins).
--- a/pidgin/gtkdialogs.c	Fri Feb 29 04:12:32 2008 +0000
+++ b/pidgin/gtkdialogs.c	Tue Mar 04 02:48:30 2008 +0000
@@ -207,7 +207,7 @@
 	{N_("Albanian"),            "sq", "Besnik Bleta", "besnik@programeshqip.org"},
 	{N_("Serbian"),             "sr", "Miloš Popović", "gpopac@gmail.com"},
 	{N_("Serbian"),             "sr@Latn", "Miloš Popović", "gpopac@gmail.com"},
-	{"Sinhala",                 "si", "Danishka Navin", "snavin@redhat.com"},
+	{N_("Sinhala"),             "si", "Danishka Navin", "snavin@redhat.com"},
 	{N_("Swedish"),             "sv", "Peter Hjalmarsson", "xake@telia.com"},
 	{N_("Tamil"),               "ta", "Viveka Nathan K", "vivekanathan@users.sourceforge.net"},
 	{N_("Telugu"),              "te", "Mr. Subbaramaih", "info.gist@cdac.in"},
--- a/pidgin/gtkplugin.c	Fri Feb 29 04:12:32 2008 +0000
+++ b/pidgin/gtkplugin.c	Tue Mar 04 02:48:30 2008 +0000
@@ -559,10 +559,10 @@
 
 	gtk_tree_model_get(model, &iter, 2, &plugin, -1);
 
-	markup = g_strdup_printf("<span size='x-large' weight='bold'>%s</span>\n<b>Description:</b> %s\n<b>Author:</b> %s",
+	markup = g_strdup_printf("<span size='x-large' weight='bold'>%s</span>\n<b>%s:</b> %s\n<b>%s:</b> %s",
 			name = g_markup_escape_text(purple_plugin_get_name(plugin), -1),
-			desc = g_markup_escape_text(purple_plugin_get_description(plugin), -1),
-			author = g_markup_escape_text(purple_plugin_get_author(plugin), -1));
+			_("Description"), desc = g_markup_escape_text(purple_plugin_get_description(plugin), -1),
+			_("Author"), author = g_markup_escape_text(purple_plugin_get_author(plugin), -1));
 
 	layout = gtk_widget_create_pango_layout(tipwindow, NULL);
 	pango_layout_set_markup(layout, markup, -1);
--- a/pidgin/plugins/notify.c	Fri Feb 29 04:12:32 2008 +0000
+++ b/pidgin/plugins/notify.c	Tue Mar 04 02:48:30 2008 +0000
@@ -842,8 +842,6 @@
 	                    PURPLE_CALLBACK(chat_sent_im), NULL);
 	purple_signal_connect(conv_handle, "conversation-created", plugin,
 	                    PURPLE_CALLBACK(conv_created), NULL);
-	purple_signal_connect(conv_handle, "chat-joined", plugin,
-	                    PURPLE_CALLBACK(conv_created), NULL);
 	purple_signal_connect(conv_handle, "deleting-conversation", plugin,
 	                    PURPLE_CALLBACK(deleting_conv), NULL);
 #if 0
--- a/pidgin/win32/winpidgin.c	Fri Feb 29 04:12:32 2008 +0000
+++ b/pidgin/win32/winpidgin.c	Tue Mar 04 02:48:30 2008 +0000
@@ -456,7 +456,7 @@
 
 				printf("An instance of Pidgin is already running.\n");
 
-				if((msg_win = FindWindowEx(HWND_MESSAGE, NULL, TEXT("WinpidginMsgWinCls"), NULL)))
+				if((msg_win = FindWindowEx(NULL, NULL, TEXT("WinpidginMsgWinCls"), NULL)))
 					if(SendMessage(msg_win, PIDGIN_WM_FOCUS_REQUEST, (WPARAM) NULL, (LPARAM) NULL))
 						return FALSE;