changeset 20955:f7f1e893236c

merge of '107559a1f06aea6bcd2bc3914663a84a941f275c' and '9c0eac6528c65b06c0ac062dd0f682bf594522cb'
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Mon, 15 Oct 2007 18:56:04 +0000
parents 07b27e3522e3 (diff) 34420be6e537 (current diff)
children 2101ebd66f15
files
diffstat 40 files changed, 628 insertions(+), 299 deletions(-) [+]
line wrap: on
line diff
--- a/Doxyfile.in	Mon Oct 15 18:52:51 2007 +0000
+++ b/Doxyfile.in	Mon Oct 15 18:56:04 2007 +0000
@@ -169,7 +169,8 @@
                          "endsignalproto=@endcode" \
                          "signaldesc=@par Description:" \
                          "signals=@b Signals:" \
-                         "endsignals="
+                         "endsignals=" \
+                         "constreturn=@note The return value of this function must not be modified or freed. @return"
 
 # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources 
 # only. Doxygen will then generate output that is more tailored for C. 
@@ -858,7 +859,7 @@
 # feature is still experimental and incomplete at the 
 # moment.
 
-GENERATE_XML           = NO
+GENERATE_XML           = YES
 
 # The XML_OUTPUT tag is used to specify where the XML pages will be put. 
 # If a relative path is entered the value of OUTPUT_DIRECTORY will be 
--- a/Makefile.am	Mon Oct 15 18:52:51 2007 +0000
+++ b/Makefile.am	Mon Oct 15 18:56:04 2007 +0000
@@ -48,6 +48,13 @@
 if HAVE_DOXYGEN
 	@echo "Running doxygen..."
 	@doxygen
+if HAVE_XSLTPROC
+	@echo "Generating devhelp index..."
+	@xsltproc doxy2devhelp.xsl doc/xml/index.xml > doc/html/pidgin.devhelp
+	@echo "(Symlink doc/html to ~/.local/share/gtk-doc/html/pidgin to make devhelp see the documentation)"
+else
+	@echo "Not generating devhelp index: xsltproc was not found by configure"
+endif
 else
 	@echo "doxygen was not found during configure.  Aborting."
 	@echo;
--- a/configure.ac	Mon Oct 15 18:52:51 2007 +0000
+++ b/configure.ac	Mon Oct 15 18:56:04 2007 +0000
@@ -2101,6 +2101,10 @@
 	[AC_HELP_STRING([--enable-dot],
 		[enable graphs in doxygen via 'dot'])],
 	enable_dot="$enableval", enable_dot="yes")
+AC_ARG_ENABLE(devhelp,
+	[AC_HELP_STRING([--enable-devhelp],
+		[enable building index for devhelp documentation browser])],
+	enable_devhelp="$enableval", enable_devhelp="yes")
 
 if test "x$enable_doxygen" = xyes; then
 	AC_CHECK_PROG(DOXYGEN, doxygen, true, false)
@@ -2120,14 +2124,28 @@
 				AC_DEFINE_UNQUOTED(HAVE_DOT, 1, [whether or not we have dot])
 			fi
 		fi
+
+		if test "x$enable_devhelp" = "xyes"; then
+			AC_CHECK_PROG(XSLTPROC, xsltproc, true, false)
+
+			if test $XSLTPROC = false; then
+				enable_devhelp="no";
+				AC_MSG_WARN([*** xsltproc not found; devhelp index will not be created])
+			else
+				AC_DEFINE_UNQUOTED(HAVE_XSLTPROC, 1, [whether or not we have xsltproc for devhelp index])
+			fi
+		fi
 	fi
 else
 	enable_dot="no"
+	enable_devhelp="no"
 fi
 
 AC_SUBST(enable_doxygen)
 AC_SUBST(enable_dot)
+AC_SUBST(enable_devhelp)
 AM_CONDITIONAL(HAVE_DOXYGEN, test "x$enable_doxygen" = "xyes")
+AM_CONDITIONAL(HAVE_XSLTPROC, test "x$enable_devhelp" = "xyes")
 
 AC_ARG_ENABLE(debug, [AC_HELP_STRING([--enable-debug],
 	[compile with debugging support])], , enable_debug=no)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doxy2devhelp.xsl	Mon Oct 15 18:56:04 2007 +0000
@@ -0,0 +1,98 @@
+<xsl:stylesheet
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns:fo="http://www.w3.org/1999/XSL/Format"
+    version="1.0">
+
+<!-- Based on http://bur.st/~eleusis/devhelp/doxy2devhelp.xsl
+             (http://bur.st/~eleusis/devhelp/README)
+     which is based on http://bugzilla.gnome.org/show_bug.cgi?id=122450
+-->
+
+<xsl:output method="xml" version="1.0" indent="yes"/>
+
+<xsl:param name="reference_prefix"></xsl:param>
+
+<xsl:template match="/">
+  <book title="Pidgin Documentation"
+        name="pidgin"
+        link="{$reference_prefix}main.html">
+  <chapters>
+    <sub name="Modules" link="{$reference_prefix}modules.html">
+      <xsl:apply-templates select="doxygenindex/compound[@kind='group']">
+        <xsl:sort select="."/>
+      </xsl:apply-templates>
+    </sub>
+    <!-- annotated.html has the short descriptions beside each struct.  is
+         that more useful than being grouped alphabetically?
+      -->
+    <sub name="Structs" link="{$reference_prefix}classes.html">
+      <xsl:apply-templates select="doxygenindex/compound[@kind='struct']">
+        <xsl:sort select="."/>
+      </xsl:apply-templates>
+    </sub>
+    <!-- This is redundant given Modules -->
+    <!--
+    <sub name="Directories" link="{$reference_prefix}dirs.html">
+      <xsl:apply-templates select="doxygenindex/compound[@kind='dir']">
+        <xsl:sort select="."/>
+      </xsl:apply-templates>
+    </sub>
+    -->
+    <!-- FIXME: Some files show up here but are broken links; mostly
+                files that are under pages...
+      -->
+    <sub name="Files" link="{$reference_prefix}files.html">
+      <xsl:apply-templates select="doxygenindex/compound[@kind='file']">
+        <xsl:sort select="."/>
+      </xsl:apply-templates>
+    </sub>
+    <sub name="Signals, HOWTOs, Other" link="{$reference_prefix}pages.html">
+      <xsl:apply-templates select="doxygenindex/compound[@kind='page']">
+        <xsl:sort select="."/>
+      </xsl:apply-templates>
+    </sub>
+  </chapters>
+
+  <functions>
+    <!-- @todo: maybe select only the real functions, ie those with kind=="function"? -->
+    <xsl:apply-templates select="doxygenindex/compound/member" mode="as-function"/>
+  </functions>
+  </book>
+</xsl:template>
+
+<xsl:template match="compound">
+  <xsl:param name="name"><xsl:value-of select="name"/></xsl:param>
+  <xsl:param name="link"><xsl:value-of select="@refid"/>.html</xsl:param>
+  <sub name="{$name}" link="{$reference_prefix}{$link}">
+  <xsl:apply-templates select="member" mode="as-sub">
+    <xsl:sort select="."/>
+  </xsl:apply-templates>
+  </sub>
+</xsl:template>
+
+<xsl:template match="member" mode="as-function">
+  <!--
+  <function name="atk_set_value" link="atk-atkvalue.html#ATK-SET-VALUE"/>
+  -->
+  <xsl:param name="name"><xsl:value-of select="name"/></xsl:param>
+  <!-- Link is refid attribute of parent element + "#" + diff between refid of parent and own refid -->
+  <xsl:param name="refid_parent"><xsl:value-of select="parent::node()/@refid"/></xsl:param>
+  <xsl:param name="own_refid"><xsl:value-of select="@refid"/></xsl:param>
+  <xsl:param name="offset"><xsl:value-of select="string-length($refid_parent) + 3"/></xsl:param>
+  <xsl:param name="ref_diff"><xsl:value-of select="substring($own_refid, $offset, 33)"/></xsl:param>
+  <xsl:param name="link"><xsl:value-of select="$refid_parent"/>.html#<xsl:value-of select="$ref_diff"/></xsl:param>
+  <function name="{$name}" link="{$reference_prefix}{$link}"/>
+</xsl:template>
+
+<xsl:template match="member" mode="as-sub">
+  <xsl:param name="name"><xsl:value-of select="name"/></xsl:param>
+  <!-- Link is refid attribute of parent element + "#" + diff between refid of parent and own refid -->
+  <xsl:param name="refid_parent"><xsl:value-of select="parent::node()/@refid"/></xsl:param>
+  <xsl:param name="own_refid"><xsl:value-of select="@refid"/></xsl:param>
+  <xsl:param name="offset"><xsl:value-of select="string-length($refid_parent) + 3"/></xsl:param>
+  <xsl:param name="ref_diff"><xsl:value-of select="substring($own_refid, $offset, 33)"/></xsl:param>
+  <xsl:param name="link"><xsl:value-of select="$refid_parent"/>.html#<xsl:value-of select="$ref_diff"/></xsl:param>
+  <sub name="{$name}" link="{$reference_prefix}{$link}"/>
+</xsl:template>
+
+</xsl:stylesheet>
--- a/libpurple/buddyicon.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/buddyicon.c	Mon Oct 15 18:56:04 2007 +0000
@@ -505,37 +505,33 @@
 		purple_buddy_icon_set_data(icon, icon_data, icon_len, checksum);
 	else if (icon_data && icon_len > 0)
 	{
-		if (icon_data != NULL && icon_len > 0)
-		{
-			PurpleBuddyIcon *icon = purple_buddy_icon_new(account, username, icon_data, icon_len, checksum);
+		PurpleBuddyIcon *icon = purple_buddy_icon_new(account, username, icon_data, icon_len, checksum);
 
-			/* purple_buddy_icon_new() calls
-			 * purple_buddy_icon_set_data(), which calls
-			 * purple_buddy_icon_update(), which has the buddy list
-			 * and conversations take references as appropriate.
-			 * This function doesn't return icon, so we can't
-			 * leave a reference dangling. */
-			purple_buddy_icon_unref(icon);
-		}
-		else
+		/* purple_buddy_icon_new() calls
+		 * purple_buddy_icon_set_data(), which calls
+		 * purple_buddy_icon_update(), which has the buddy list
+		 * and conversations take references as appropriate.
+		 * This function doesn't return icon, so we can't
+		 * leave a reference dangling. */
+		purple_buddy_icon_unref(icon);
+	}
+	else
+	{
+		/* If the buddy list or a conversation was holding a
+		 * reference, we'd have found the icon in the cache.
+		 * Since we know we're deleting the icon, we only
+		 * need a subset of purple_buddy_icon_update(). */
+
+		GSList *buddies = purple_find_buddies(account, username);
+		while (buddies != NULL)
 		{
-			/* If the buddy list or a conversation was holding a
-			 * reference, we'd have found the icon in the cache.
-			 * Since we know we're deleting the icon, we only
-			 * need a subset of purple_buddy_icon_update(). */
+			PurpleBuddy *buddy = (PurpleBuddy *)buddies->data;
 
-			GSList *buddies = purple_find_buddies(account, username);
-			while (buddies != NULL)
-			{
-				PurpleBuddy *buddy = (PurpleBuddy *)buddies->data;
+			unref_filename(purple_blist_node_get_string((PurpleBlistNode *)buddy, "buddy_icon"));
+			purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "buddy_icon");
+			purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "icon_checksum");
 
-				unref_filename(purple_blist_node_get_string((PurpleBlistNode *)buddy, "buddy_icon"));
-				purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "buddy_icon");
-				purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "icon_checksum");
-
-				buddies = g_slist_delete_link(buddies, buddies);
-			}
-
+			buddies = g_slist_delete_link(buddies, buddies);
 		}
 	}
 }
--- a/libpurple/certificate.h	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/certificate.h	Mon Oct 15 18:56:04 2007 +0000
@@ -435,7 +435,7 @@
  *
  * @return TRUE if 'crt' has a valid signature made by 'issuer',
  *         otherwise FALSE
- * @TODO Find a way to give the reason (bad signature, not the issuer, etc.) 
+ * @todo Find a way to give the reason (bad signature, not the issuer, etc.) 
  */
 gboolean
 purple_certificate_signed_by(PurpleCertificate *crt, PurpleCertificate *issuer);
@@ -450,7 +450,7 @@
  * @param chain      List of PurpleCertificate instances comprising the chain,
  *                   in the order certificate, issuer, issuer's issuer, etc.
  * @return TRUE if the chain is valid. See description.
- * @TODO Specify which certificate in the chain caused a failure
+ * @todo Specify which certificate in the chain caused a failure
  */
 gboolean
 purple_certificate_check_signature_chain(GList *chain);
@@ -781,7 +781,7 @@
  * Displays a window showing X.509 certificate information
  *
  * @param crt    Certificate under an "x509" Scheme
- * @TODO Will break on CA certs, as they have no Common Name
+ * @todo Will break on CA certs, as they have no Common Name
  */
 void
 purple_certificate_display_x509(PurpleCertificate *crt);
--- a/libpurple/dnsquery.h	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/dnsquery.h	Mon Oct 15 18:56:04 2007 +0000
@@ -59,7 +59,7 @@
 	                         PurpleDnsQueryFailedCallback failed_cb);
 
 	/** Called just before @a query_data is freed; this should cancel any
-	 *  further use of @q query_data the UI would make. Unneeded if
+	 *  further use of @a query_data the UI would make. Unneeded if
 	 *  #resolve_host is not implemented.
 	 */
 	void (*destroy)(PurpleDnsQueryData *query_data);
--- a/libpurple/network.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/network.c	Mon Oct 15 18:56:04 2007 +0000
@@ -263,6 +263,7 @@
 purple_network_do_listen(unsigned short port, int socket_type, PurpleNetworkListenCallback cb, gpointer cb_data)
 {
 	int listenfd = -1;
+	int flags;
 	const int on = 1;
 	PurpleNetworkListenData *listen_data;
 	unsigned short actual_port;
@@ -340,7 +341,8 @@
 		close(listenfd);
 		return NULL;
 	}
-	fcntl(listenfd, F_SETFL, O_NONBLOCK);
+	flags = fcntl(listenfd, F_GETFL);
+	fcntl(listenfd, F_SETFL, flags | O_NONBLOCK);
 
 	actual_port = purple_network_get_port_from_fd(listenfd);
 
--- a/libpurple/notify.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/notify.c	Mon Oct 15 18:56:04 2007 +0000
@@ -688,8 +688,11 @@
 void
 purple_notify_user_info_remove_last_item(PurpleNotifyUserInfo *user_info)
 {
-	user_info->user_info_entries = g_list_remove(user_info->user_info_entries,
-												 g_list_last(user_info->user_info_entries)->data);
+	GList *last = g_list_last(user_info->user_info_entries);
+	if (last) {
+		purple_notify_user_info_entry_destroy(last->data);
+		user_info->user_info_entries = g_list_remove_link(user_info->user_info_entries, last);
+	}
 }
 
 void *
--- a/libpurple/notify.h	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/notify.h	Mon Oct 15 18:56:04 2007 +0000
@@ -539,7 +539,7 @@
 void purple_notify_user_info_prepend_pair(PurpleNotifyUserInfo *user_info, const char *label, const char *value);
 
 /**
- * Remove a PurpleNotifyUserInfoEntry from a PurpleNotifyUserInfo object
+ * Remove a PurpleNotifyUserInfoEntry from a PurpleNotifyUserInfo object without freeing the entry.
  *
  * @param user_info          The PurpleNotifyUserInfo
  * @param user_info_entry    The PurpleNotifyUserInfoEntry
--- a/libpurple/plugins/log_reader.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/plugins/log_reader.c	Mon Oct 15 18:56:04 2007 +0000
@@ -2095,159 +2095,54 @@
 #define AMSN_LOG_CONV_END "|\"LRED[You have closed the window on "
 #define AMSN_LOG_CONV_EXTRA "01 Aug 2001 00:00:00]"
 
-/* `log_dir`/username@hotmail.com/logs/buddyname@hotmail.com.log */
-/* `log_dir`/username@hotmail.com/logs/Month Year/buddyname@hotmail.com.log */
-static GList *amsn_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account)
+static GList *amsn_logger_parse_file(char *filename, const char *sn, PurpleAccount *account)
 {
 	GList *list = NULL;
-	struct amsn_logger_data *data;
-	const char *logdir;
-	char *username;
-	char *log_path;
-	char *buddy_log;
-	char *filename;
-	GDir *dir;
-	const char *name;
 	GError *error;
 	char *contents;
+	struct amsn_logger_data *data;
 	PurpleLog *log;
-	GList *files = NULL;
-	GList *f;
-
-	logdir = purple_prefs_get_string("/plugins/core/log_reader/amsn/log_directory");
-
-	/* By clearing the log directory path, this logger can be (effectively) disabled. */
-	if (!logdir || !*logdir)
-		return NULL;
-
-	/* aMSN only works with MSN/WLM */
-	if (strcmp(account->protocol_id, "prpl-msn"))
-		return NULL;
-
-	username = g_strdup(purple_normalize(account, account->username));
-	buddy_log = g_strdup_printf("%s.log", purple_normalize(account, sn));
-	log_path = g_build_filename(logdir, username, "logs", NULL);
-
-	/* First check in the top-level */
-	filename = g_build_filename(log_path, buddy_log, NULL);
-	if (g_file_test(filename, G_FILE_TEST_EXISTS))
-		files = g_list_prepend(files, filename);
-	else
-		g_free(filename);
-
-	/* Check in previous months */
-	dir = g_dir_open(log_path, 0, NULL);
-	if (dir) {
-		while ((name = g_dir_read_name(dir)) != NULL) {
-			filename = g_build_filename(log_path, name, buddy_log, NULL);
-			if (g_file_test(filename, G_FILE_TEST_EXISTS))
-				files = g_list_prepend(files, filename);
-			else
-				g_free(filename);
-		}
-		g_dir_close(dir);
-	}
-
-	g_free(log_path);
-
-	/* New versions use 'friendlier' directory names */
-	purple_util_chrreplace(username, '@', '_');
-	purple_util_chrreplace(username, '.', '_');
-
-	log_path = g_build_filename(logdir, username, "logs", NULL);
-
-	/* First check in the top-level */
-	filename = g_build_filename(log_path, buddy_log, NULL);
-	if (g_file_test(filename, G_FILE_TEST_EXISTS))
-		files = g_list_prepend(files, filename);
-	else
-		g_free(filename);
-
-	/* Check in previous months */
-	dir = g_dir_open(log_path, 0, NULL);
-	if (dir) {
-		while ((name = g_dir_read_name(dir)) != NULL) {
-			filename = g_build_filename(log_path, name, buddy_log, NULL);
-			if (g_file_test(filename, G_FILE_TEST_EXISTS))
-				files = g_list_prepend(files, filename);
-			else
-				g_free(filename);
-		}
-		g_dir_close(dir);
-	}
-
-	g_free(log_path);
-	g_free(username);
-	g_free(buddy_log);
-
-	/* Loop through files looking for logs */
-	for(f = g_list_first(files); f; f = g_list_next(f)) {
-		filename = f->data;
-		purple_debug_info("aMSN logger", "Reading %s\n", filename);
-		error = NULL;
-		if (!g_file_get_contents(filename, &contents, NULL, &error)) {
-			purple_debug_error("aMSN logger",
-			                   "Couldn't read file %s: %s \n", filename,
-			                   (error && error->message) ?
-			                    error->message : "Unknown error");
-			if (error)
-				g_error_free(error);
-		} else {
-			char *c = contents;
-			gboolean found_start = FALSE;
-			char *start_log = c;
-			int offset = 0;
-			struct tm tm;
-			while (c && *c) {
-				if (purple_str_has_prefix(c, AMSN_LOG_CONV_START)) {
-					char month[4];
-					if (sscanf(c + strlen(AMSN_LOG_CONV_START),
-					           "%u %3s %u %u:%u:%u",
-					           &tm.tm_mday, (char*)&month, &tm.tm_year,
-					           &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
-						found_start = FALSE;
-						purple_debug_error("aMSN logger",
-						                   "Error parsing start date for %s\n",
-						                   filename);
-					} else {
-						tm.tm_year -= 1900;
-
-						/* Let the C library deal with
-						 * daylight savings time.
-						 */
-						tm.tm_isdst = -1;
-						tm.tm_mon = get_month(month);
-
-						found_start = TRUE;
-						offset = c - contents;
-						start_log = c;
-					}
-				} else if (purple_str_has_prefix(c, AMSN_LOG_CONV_END) && found_start) {
-					data = g_new0(struct amsn_logger_data, 1);
-					data->path = g_strdup(filename);
-					data->offset = offset;
-					data->length = c - start_log
-					             + strlen(AMSN_LOG_CONV_END)
-					             + strlen(AMSN_LOG_CONV_EXTRA);
-					log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, mktime(&tm), NULL);
-					log->logger = amsn_logger;
-					log->logger_data = data;
-					list = g_list_prepend(list, log);
+
+	purple_debug_info("aMSN logger", "Reading %s\n", filename);
+	error = NULL;
+	if (!g_file_get_contents(filename, &contents, NULL, &error)) {
+		purple_debug_error("aMSN logger",
+		                   "Couldn't read file %s: %s \n", filename,
+		                   (error && error->message) ?
+		                    error->message : "Unknown error");
+		if (error)
+			g_error_free(error);
+	} else {
+		char *c = contents;
+		gboolean found_start = FALSE;
+		char *start_log = c;
+		int offset = 0;
+		struct tm tm;
+		while (c && *c) {
+			if (purple_str_has_prefix(c, AMSN_LOG_CONV_START)) {
+				char month[4];
+				if (sscanf(c + strlen(AMSN_LOG_CONV_START),
+				           "%u %3s %u %u:%u:%u",
+				           &tm.tm_mday, (char*)&month, &tm.tm_year,
+				           &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
 					found_start = FALSE;
-
-					purple_debug_info("aMSN logger",
-					                  "Found log for %s:"
-					                  " path = (%s),"
-					                  " offset = (%d),"
-					                  " length = (%d)\n",
-					                  sn, data->path, data->offset, data->length);
+					purple_debug_error("aMSN logger",
+					                   "Error parsing start date for %s\n",
+					                   filename);
+				} else {
+					tm.tm_year -= 1900;
+
+					/* Let the C library deal with
+					 * daylight savings time.
+					 */
+					tm.tm_isdst = -1;
+					tm.tm_mon = get_month(month);
+
+					found_start = TRUE;
+					offset = c - contents;
+					start_log = c;
 				}
-				c = strstr(c, "\n");
-				c++;
-			}
-
-			/* I've seen the file end without the AMSN_LOG_CONV_END bit */
-			if (found_start) {
+			} else if (purple_str_has_prefix(c, AMSN_LOG_CONV_END) && found_start) {
 				data = g_new0(struct amsn_logger_data, 1);
 				data->path = g_strdup(filename);
 				data->offset = offset;
@@ -2267,12 +2162,112 @@
 				                  " length = (%d)\n",
 				                  sn, data->path, data->offset, data->length);
 			}
-			g_free(contents);
+			c = strstr(c, "\n");
+			c++;
+		}
+
+		/* I've seen the file end without the AMSN_LOG_CONV_END bit */
+		if (found_start) {
+			data = g_new0(struct amsn_logger_data, 1);
+			data->path = g_strdup(filename);
+			data->offset = offset;
+			data->length = c - start_log
+				             + strlen(AMSN_LOG_CONV_END)
+				             + strlen(AMSN_LOG_CONV_EXTRA);
+			log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, mktime(&tm), NULL);
+			log->logger = amsn_logger;
+			log->logger_data = data;
+			list = g_list_prepend(list, log);
+			found_start = FALSE;
+
+			purple_debug_info("aMSN logger",
+			                  "Found log for %s:"
+			                  " path = (%s),"
+			                  " offset = (%d),"
+			                  " length = (%d)\n",
+			                  sn, data->path, data->offset, data->length);
 		}
+		g_free(contents);
+	}
+
+	return list;
+}
+
+/* `log_dir`/username@hotmail.com/logs/buddyname@hotmail.com.log */
+/* `log_dir`/username@hotmail.com/logs/Month Year/buddyname@hotmail.com.log */
+static GList *amsn_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account)
+{
+	GList *list = NULL;
+	const char *logdir;
+	char *username;
+	char *log_path;
+	char *buddy_log;
+	char *filename;
+	GDir *dir;
+	const char *name;
+
+	logdir = purple_prefs_get_string("/plugins/core/log_reader/amsn/log_directory");
+
+	/* By clearing the log directory path, this logger can be (effectively) disabled. */
+	if (!logdir || !*logdir)
+		return NULL;
+
+	/* aMSN only works with MSN/WLM */
+	if (strcmp(account->protocol_id, "prpl-msn"))
+		return NULL;
+
+	username = g_strdup(purple_normalize(account, account->username));
+	buddy_log = g_strdup_printf("%s.log", purple_normalize(account, sn));
+	log_path = g_build_filename(logdir, username, "logs", NULL);
+
+	/* First check in the top-level */
+	filename = g_build_filename(log_path, buddy_log, NULL);
+	if (g_file_test(filename, G_FILE_TEST_EXISTS))
+		list = amsn_logger_parse_file(filename, sn, account);
+	else
 		g_free(filename);
+
+	/* Check in previous months */
+	dir = g_dir_open(log_path, 0, NULL);
+	if (dir) {
+		while ((name = g_dir_read_name(dir)) != NULL) {
+			filename = g_build_filename(log_path, name, buddy_log, NULL);
+			if (g_file_test(filename, G_FILE_TEST_EXISTS))
+				list = g_list_concat(list, amsn_logger_parse_file(filename, sn, account));
+			g_free(filename);
+		}
+		g_dir_close(dir);
 	}
 
-	g_list_free(files);
+	g_free(log_path);
+
+	/* New versions use 'friendlier' directory names */
+	purple_util_chrreplace(username, '@', '_');
+	purple_util_chrreplace(username, '.', '_');
+
+	log_path = g_build_filename(logdir, username, "logs", NULL);
+
+	/* First check in the top-level */
+	filename = g_build_filename(log_path, buddy_log, NULL);
+	if (g_file_test(filename, G_FILE_TEST_EXISTS))
+		list = g_list_concat(list, amsn_logger_parse_file(filename, sn, account));
+	g_free(filename);
+
+	/* Check in previous months */
+	dir = g_dir_open(log_path, 0, NULL);
+	if (dir) {
+		while ((name = g_dir_read_name(dir)) != NULL) {
+			filename = g_build_filename(log_path, name, buddy_log, NULL);
+			if (g_file_test(filename, G_FILE_TEST_EXISTS))
+				list = g_list_concat(list, amsn_logger_parse_file(filename, sn, account));
+			g_free(filename);
+		}
+		g_dir_close(dir);
+	}
+
+	g_free(log_path);
+	g_free(username);
+	g_free(buddy_log);
 
 	return list;
 }
@@ -2428,14 +2423,16 @@
 static void
 init_plugin(PurplePlugin *plugin)
 {
+
+}
+
+static void log_reader_init_prefs() {
 	char *path;
 #ifdef _WIN32
 	char *folder;
 	gboolean found = FALSE;
 #endif
 
-	g_return_if_fail(plugin != NULL);
-
 	purple_prefs_add_none("/plugins/core/log_reader");
 
 
@@ -2676,12 +2673,16 @@
 
 	/* Calculate default aMSN log directory. */
 #ifdef _WIN32
+	path = NULL;
 	folder = wpurple_get_special_folder(CSIDL_PROFILE); /* Silly aMSN, not using CSIDL_APPDATA */
-	path = g_build_filename(folder, "amsn", NULL);
+	if (folder) {
+		path = g_build_filename(folder, "amsn", NULL);
+		g_free(folder);
+	}
 #else
 	path = g_build_filename(purple_home_dir(), ".amsn", NULL);
 #endif
-	purple_prefs_add_string("/plugins/core/log_reader/amsn/log_directory", path);
+	purple_prefs_add_string("/plugins/core/log_reader/amsn/log_directory", path ? path : "");
 	g_free(path);
 }
 
@@ -2690,6 +2691,8 @@
 {
 	g_return_val_if_fail(plugin != NULL, FALSE);
 
+	log_reader_init_prefs();
+
 	/* The names of IM clients are marked for translation at the request of
 	   translators who wanted to transliterate them.  Many translators
 	   choose to leave them alone.  Choose what's best for your language. */
--- a/libpurple/prefs.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/prefs.c	Mon Oct 15 18:56:04 2007 +0000
@@ -297,6 +297,7 @@
 						g_filename_from_utf8(pref_value, -1, NULL, NULL, NULL));
 			}
 		}
+		g_string_free(pref_name_full, TRUE);
 	} else {
 		char *decoded;
 
--- a/libpurple/protocols/bonjour/Makefile.mingw	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/protocols/bonjour/Makefile.mingw	Mon Oct 15 18:56:04 2007 +0000
@@ -36,7 +36,6 @@
 			-I$(PIDGIN_TREE_TOP)
 
 LIB_PATHS +=		-L$(GTK_TOP)/lib \
-			-L$(BONJOUR_TOP)/lib/win32 \
 			-L$(LIBXML2_TOP)/lib \
 			-L$(PURPLE_TOP)
 
@@ -66,6 +65,7 @@
 
 ifeq ($(LINK_DNS_SD_DIRECTLY), 1)
 	CFLAGS += -DLINK_DNS_SD_DIRECTLY
+	LIB_PATHS += -L$(BONJOUR_TOP)/lib/win32 -L$(BONJOUR_TOP)/lib
 	LIBS += -ldnssd
 endif
 
--- a/libpurple/protocols/bonjour/buddy.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/protocols/bonjour/buddy.c	Mon Oct 15 18:56:04 2007 +0000
@@ -62,9 +62,11 @@
 }
 
 void
-set_bonjour_buddy_value(BonjourBuddy* buddy, const char *record_key, const char *value, uint32_t len){
+set_bonjour_buddy_value(BonjourBuddy* buddy, const char *record_key, const char *value, guint32 len){
 	gchar **fld = NULL;
 
+	g_return_if_fail(record_key != NULL);
+
 	if (!strcmp(record_key, "1st"))
 		fld = &buddy->first;
 	else if(!strcmp(record_key, "email"))
--- a/libpurple/protocols/bonjour/buddy.h	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/protocols/bonjour/buddy.h	Mon Oct 15 18:56:04 2007 +0000
@@ -83,7 +83,7 @@
 /**
  * Sets a value in the BonjourBuddy struct, destroying the old value
  */
-void set_bonjour_buddy_value(BonjourBuddy *buddy, const char *record_key, const char *value, uint32_t len);
+void set_bonjour_buddy_value(BonjourBuddy *buddy, const char *record_key, const char *value, guint32 len);
 
 /**
  * Check if all the compulsory buddy data is present.
--- a/libpurple/protocols/bonjour/jabber.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/protocols/bonjour/jabber.c	Mon Oct 15 18:56:04 2007 +0000
@@ -521,6 +521,7 @@
 	struct sockaddr_in their_addr; /* connector's address information */
 	socklen_t sin_size = sizeof(struct sockaddr);
 	int client_socket;
+	int flags;
 	BonjourBuddy *bb;
 	char *address_text = NULL;
 	PurpleBuddyList *bl = purple_get_blist();
@@ -533,7 +534,8 @@
 	if ((client_socket = accept(server_socket, (struct sockaddr *)&their_addr, &sin_size)) == -1)
 		return;
 
-	fcntl(client_socket, F_SETFL, O_NONBLOCK);
+	flags = fcntl(client_socket, F_GETFL);
+	fcntl(client_socket, F_SETFL, flags | O_NONBLOCK);
 
 	/* Look for the buddy that has opened the conversation and fill information */
 	address_text = inet_ntoa(their_addr.sin_addr);
--- a/libpurple/protocols/msn/directconn.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/protocols/msn/directconn.c	Mon Oct 15 18:56:04 2007 +0000
@@ -80,6 +80,7 @@
 create_listener(int port)
 {
 	int fd;
+	int flags;
 	const int on = 1;
 
 #if 0
@@ -155,7 +156,8 @@
 		return -1;
 	}
 
-	fcntl(fd, F_SETFL, O_NONBLOCK);
+	flags = fcntl(fd, F_GETFL);
+	fcntl(fd, F_SETFL, flags | O_NONBLOCK);
 
 	return fd;
 }
--- a/libpurple/protocols/msn/httpconn.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/protocols/msn/httpconn.c	Mon Oct 15 18:56:04 2007 +0000
@@ -169,7 +169,7 @@
 	/* Now we should be able to process the data. */
 	if ((s = purple_strcasestr(header, "X-MSN-Messenger: ")) != NULL)
 	{
-		char *full_session_id, *gw_ip, *session_action;
+		gchar *full_session_id = NULL, *gw_ip = NULL, *session_action = NULL;
 		char *t, *session_id;
 		char **elems, **cur, **tokens;
 
@@ -196,13 +196,16 @@
 		{
 			tokens = g_strsplit(*cur, "=", 2);
 
-			if (strcmp(tokens[0], "SessionID") == 0)
+			if (strcmp(tokens[0], "SessionID") == 0) {
+				g_free(full_session_id);
 				full_session_id = tokens[1];
-			else if (strcmp(tokens[0], "GW-IP") == 0)
+			} else if (strcmp(tokens[0], "GW-IP") == 0) {
+				g_free(gw_ip);
 				gw_ip = tokens[1];
-			else if (strcmp(tokens[0], "Session") == 0)
+			} else if (strcmp(tokens[0], "Session") == 0) {
+				g_free(session_action);
 				session_action = tokens[1];
-			else
+			} else
 				g_free(tokens[1]);
 
 			g_free(tokens[0]);
@@ -684,6 +687,17 @@
 
 	g_free(httpconn->host);
 
+	while (httpconn->queue != NULL) {
+		MsnHttpQueueData *queue_data;
+
+		queue_data = (MsnHttpQueueData *) httpconn->queue->data;
+
+		httpconn->queue = g_list_remove_link(httpconn->queue, httpconn->queue);
+
+		g_free(queue_data->body);
+		g_free(queue_data);
+	}
+
 	purple_circ_buffer_destroy(httpconn->tx_buf);
 	if (httpconn->tx_handler > 0)
 		purple_input_remove(httpconn->tx_handler);
--- a/libpurple/protocols/msn/msg.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/protocols/msn/msg.c	Mon Oct 15 18:56:04 2007 +0000
@@ -664,10 +664,11 @@
 
 		tokens = g_strsplit(*cur, ": ", 2);
 
-		if (tokens[0] != NULL && tokens[1] != NULL)
+		if (tokens[0] != NULL && tokens[1] != NULL) {
 			g_hash_table_insert(table, tokens[0], tokens[1]);
-
-		g_free(tokens);
+			g_free(tokens);
+		} else
+			g_strfreev(tokens);
 	}
 
 	g_strfreev(elems);
--- a/libpurple/protocols/msn/msn.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/protocols/msn/msn.c	Mon Oct 15 18:56:04 2007 +0000
@@ -1594,7 +1594,6 @@
 	gboolean sect_info = FALSE;
 	gboolean has_contact_info = FALSE;
 	char *url_buffer;
-	GString *s, *s2;
 	int stripped_len;
 #if PHOTO_SUPPORT
 	char *photo_url_text = NULL;
@@ -1679,11 +1678,6 @@
 	purple_debug_misc("msn", "stripped = %p\n", stripped);
 	purple_debug_misc("msn", "url_buffer = %p\n", url_buffer);
 
-	/* Gonna re-use the memory we've already got for url_buffer */
-	/* No we're not. */
-	s = g_string_sized_new(strlen(url_buffer));
-	s2 = g_string_sized_new(strlen(url_buffer));
-
 	/* General section header */
 	if (has_tooltip_text)
 		purple_notify_user_info_add_section_break(user_info);
@@ -2030,7 +2024,7 @@
 		purple_debug_warning("msn", "invalid connection. ignoring buddy photo info.\n");
 		g_free(stripped);
 		g_free(url_buffer);
-		g_free(user_info);
+		purple_notify_user_info_destroy(user_info);
 		g_free(info_data->name);
 		g_free(info_data);
 		g_free(photo_url_text);
--- a/libpurple/protocols/msn/notification.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/protocols/msn/notification.c	Mon Oct 15 18:56:04 2007 +0000
@@ -262,14 +262,15 @@
 		for (cur = elems; *cur != NULL; cur++)
 		{
 			tokens = g_strsplit(*cur, "=", 2);
-			if(tokens[0]&&tokens[1])
+			if(tokens[0] && tokens[1])
 			{
 				purple_debug_info("MSNP14","challenge %p,key:%s,value:%s\n",
 									session->nexus->challenge_data,tokens[0],tokens[1]);
 				g_hash_table_insert(session->nexus->challenge_data, tokens[0], tokens[1]);
-			}
-			/* Don't free each of the tokens, only the array. */
-			g_free(tokens);
+				/* Don't free each of the tokens, only the array. */
+				g_free(tokens);
+			} else
+				g_strfreev(tokens);
 		}
 
 		g_strfreev(elems);
@@ -735,7 +736,7 @@
 	msn_cmdproc_send_trans(cmdproc, trans);
 
 	g_free(payload);
-	g_free(tokens);
+	g_strfreev(tokens);
 }
 
 static void
--- a/libpurple/protocols/msn/servconn.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/protocols/msn/servconn.c	Mon Oct 15 18:56:04 2007 +0000
@@ -480,6 +480,7 @@
 create_listener(int port)
 {
 	int fd;
+	int flags;
 	const int on = 1;
 
 #if 0
@@ -555,7 +556,8 @@
 		return -1;
 	}
 
-	fcntl(fd, F_SETFL, O_NONBLOCK);
+	flags = fcntl(fd, F_GETFL);
+	fcntl(fd, F_SETFL, flags | O_NONBLOCK);
 
 	return fd;
 }
--- a/libpurple/protocols/msn/slplink.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/protocols/msn/slplink.c	Mon Oct 15 18:56:04 2007 +0000
@@ -120,6 +120,8 @@
 	while (slplink->slp_calls != NULL)
 		msn_slp_call_destroy(slplink->slp_calls->data);
 
+	g_queue_free(slplink->slp_msg_queue);
+
 	session->slplinks =
 		g_list_remove(session->slplinks, slplink);
 
--- a/libpurple/protocols/msn/switchboard.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/protocols/msn/switchboard.c	Mon Oct 15 18:56:04 2007 +0000
@@ -108,8 +108,8 @@
 	g_free(swboard->auth_key);
 	g_free(swboard->session_id);
 
-	for (l = swboard->users; l != NULL; l = l->next)
-		g_free(l->data);
+	for (; swboard->users; swboard->users = g_list_remove_link(swboard->users, swboard->users))
+		g_free(swboard->users->data);
 
 	session = swboard->session;
 	session->switches = g_list_remove(session->switches, swboard);
--- a/libpurple/protocols/oscar/oscar.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Mon Oct 15 18:56:04 2007 +0000
@@ -5006,6 +5006,7 @@
 					g = purple_group_new(gname_utf8);
 					purple_blist_add_group(g, NULL);
 				}
+				g_free(gname_utf8);
 			} break;
 
 			case 0x0002: { /* Permit buddy */
--- a/libpurple/protocols/oscar/peer.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/protocols/oscar/peer.c	Mon Oct 15 18:56:04 2007 +0000
@@ -607,6 +607,7 @@
 	PurpleConnection *gc;
 	struct sockaddr addr;
 	socklen_t addrlen = sizeof(addr);
+	int flags;
 
 	conn = data;
 	od = conn->od;
@@ -633,7 +634,8 @@
 		return;
 	}
 
-	fcntl(conn->fd, F_SETFL, O_NONBLOCK);
+	flags = fcntl(conn->fd, F_GETFL);
+	fcntl(conn->fd, F_SETFL, flags | O_NONBLOCK);
 	purple_input_remove(conn->watcher_incoming);
 
 	peer_connection_finalize_connection(conn);
--- a/libpurple/protocols/qq/qq_proxy.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/protocols/qq/qq_proxy.c	Mon Oct 15 18:56:04 2007 +0000
@@ -258,6 +258,7 @@
 static gint _qq_proxy_none(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen)
 {
 	gint fd = -1;
+	int flags;
 
 	purple_debug(PURPLE_DEBUG_INFO, "QQ", "Using UDP without proxy\n");
 	fd = socket(PF_INET, SOCK_DGRAM, 0);
@@ -269,7 +270,8 @@
 	}
 
 	/* we use non-blocking mode to speed up connection */
-	fcntl(fd, F_SETFL, O_NONBLOCK);
+	flags = fcntl(fd, F_GETFL);
+	fcntl(fd, F_SETFL, flags | O_NONBLOCK);
 
 	/* From Unix-socket-FAQ: http://www.faqs.org/faqs/unix-faq/socket/
 	 *
@@ -301,7 +303,8 @@
 		}		/* if errno */
 	} else {		/* connect returns 0 */
 		purple_debug(PURPLE_DEBUG_INFO, "QQ", "Connected.\n");
-		fcntl(fd, F_SETFL, 0);
+		flags = fcntl(fd, F_GETFL);
+		fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
 		phb->func(phb->data, fd, NULL);
 	}
 
--- a/libpurple/protocols/qq/udp_proxy_s5.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/protocols/qq/udp_proxy_s5.c	Mon Oct 15 18:56:04 2007 +0000
@@ -33,6 +33,7 @@
 	struct sockaddr_in sin;
 	int len, error;
 	socklen_t errlen;
+	int flags;
 
 	purple_input_remove(phb->inpa);
 	purple_debug(PURPLE_DEBUG_INFO, "socks5 proxy", "Able to read again.\n");
@@ -89,7 +90,8 @@
 		close(phb->udpsock);
 		return;
 	}
-	fcntl(phb->udpsock, F_SETFL, 0);
+	flags = fcntl(phb->udpsock, F_GETFL);
+	fcntl(phb->udpsock, F_SETFL, flags & ~O_NONBLOCK);
 
 	if (phb->account == NULL || purple_account_get_connection(phb->account) != NULL) {
 		phb->func(phb->data, phb->udpsock, NULL);
@@ -106,6 +108,7 @@
 	struct sockaddr_in sin, ctlsin;
 	int port; 
 	socklen_t ctllen;
+	int flags;
 
 	purple_debug(PURPLE_DEBUG_INFO, "s5_sendconnect", "remote host is %s:%d\n", phb->host, phb->port);
 
@@ -133,7 +136,8 @@
 		return;
 	}
 
-	fcntl(phb->udpsock, F_SETFL, O_NONBLOCK);
+	flags = fcntl(phb->udpsock, F_GETFL);
+	fcntl(phb->udpsock, F_SETFL, flags | O_NONBLOCK);
 
 	port = g_ntohs(ctlsin.sin_port) + 1;
 	while (1) {
@@ -287,6 +291,7 @@
 	struct PHB *phb = data;
 	socklen_t len;
 	int error = ETIMEDOUT;
+	int flags;
 
 	purple_debug(PURPLE_DEBUG_INFO, "socks5 proxy", "Connected.\n");
 
@@ -306,7 +311,8 @@
 		g_free(phb);
 		return;
 	}
-	fcntl(source, F_SETFL, 0);
+	flags = fcntl(source, F_GETFL);
+	fcntl(source, F_SETFL, flags & ~O_NONBLOCK);
 
 	i = 0;
 	buf[0] = 0x05;		/* SOCKS version 5 */
@@ -343,6 +349,8 @@
 gint qq_proxy_socks5(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen)
 {
 	gint fd;
+	int flags;
+
 	purple_debug(PURPLE_DEBUG_INFO, "QQ",
 		   "Connecting to %s:%d via %s:%d using SOCKS5\n",
 		   phb->host, phb->port, purple_proxy_info_get_host(phb->gpi), purple_proxy_info_get_port(phb->gpi));
@@ -352,7 +360,8 @@
 
 	purple_debug(PURPLE_DEBUG_INFO, "QQ", "proxy_sock5 return fd=%d\n", fd);
 
-	fcntl(fd, F_SETFL, O_NONBLOCK);
+	flags = fcntl(fd, F_GETFL);
+	fcntl(fd, F_SETFL, flags | O_NONBLOCK);
 	if (connect(fd, addr, addrlen) < 0) {
 		if ((errno == EINPROGRESS) || (errno == EINTR)) {
 			purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Connect in asynchronous mode.\n");
@@ -363,7 +372,8 @@
 		}
 	} else {
 		purple_debug(PURPLE_DEBUG_MISC, "QQ", "Connect in blocking mode.\n");
-		fcntl(fd, F_SETFL, 0);
+		flags = fcntl(fd, F_GETFL);
+		fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
 		_qq_s5_canwrite(phb, fd, PURPLE_INPUT_WRITE);
 	}
 
--- a/libpurple/protocols/simple/simple.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/protocols/simple/simple.c	Mon Oct 15 18:56:04 2007 +0000
@@ -80,14 +80,15 @@
 static gboolean process_register_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc);
 static void send_notify(struct simple_account_data *sip, struct simple_watcher *);
 
-static void send_publish(struct simple_account_data *sip);
+static void send_open_publish(struct simple_account_data *sip);
+static void send_closed_publish(struct simple_account_data *sip);
 
 static void do_notifies(struct simple_account_data *sip) {
 	GSList *tmp = sip->watcher;
 	purple_debug_info("simple", "do_notifies()\n");
 	if((sip->republish != -1) || sip->republish < time(NULL)) {
 		if(purple_account_get_bool(sip->account, "dopublish", TRUE)) {
-			send_publish(sip);
+			send_open_publish(sip);
 		}
 	}
 
@@ -1020,7 +1021,7 @@
 		case 200:
 			if(sip->registerstatus < SIMPLE_REGISTER_COMPLETE) { /* registered */
 				if(purple_account_get_bool(sip->account, "dopublish", TRUE)) {
-					send_publish(sip);
+					send_open_publish(sip);
 				}
 			}
 			sip->registerstatus = SIMPLE_REGISTER_COMPLETE;
@@ -1072,7 +1073,7 @@
 static void process_incoming_notify(struct simple_account_data *sip, struct sipmsg *msg) {
 	gchar *from;
 	gchar *fromhdr;
-	gchar *tmp2;
+	gchar *basicstatus_data;
 	xmlnode *pidf;
 	xmlnode *basicstatus = NULL, *tuple, *status;
 	gboolean isonline = FALSE;
@@ -1085,8 +1086,9 @@
 
 	if(!pidf) {
 		purple_debug_info("simple", "process_incoming_notify: no parseable pidf\n");
+		purple_prpl_got_user_status(sip->account, from, "offline", NULL);
+		send_sip_response(sip->gc, msg, 200, "OK", NULL);
 		g_free(from);
-		send_sip_response(sip->gc, msg, 200, "OK", NULL);
 		return;
 	}
 
@@ -1101,27 +1103,28 @@
 		return;
 	}
 
-	tmp2 = xmlnode_get_data(basicstatus);
+	basicstatus_data = xmlnode_get_data(basicstatus);
 
-	if(!tmp2) {
+	if(!basicstatus_data) {
 		purple_debug_info("simple", "process_incoming_notify: no basic data found\n");
 		xmlnode_free(pidf);
 		g_free(from);
 		return;
 	}
 
-	if(strstr(tmp2, "open")) {
+	if(strstr(basicstatus_data, "open"))
 		isonline = TRUE;
-	}
+
 
-	g_free(tmp2);
-
-	if(isonline) purple_prpl_got_user_status(sip->account, from, "available", NULL);
-	else purple_prpl_got_user_status(sip->account, from, "offline", NULL);
+	if(isonline) 
+		purple_prpl_got_user_status(sip->account, from, "available", NULL);
+	else 
+		purple_prpl_got_user_status(sip->account, from, "offline", NULL);
 
 	xmlnode_free(pidf);
+	g_free(from);
+	g_free(basicstatus_data);
 
-	g_free(from);
 	send_sip_response(sip->gc, msg, 200, "OK", NULL);
 }
 
@@ -1188,28 +1191,27 @@
 	return doc;
 }
 
-
-
-static gchar* gen_pidf(struct simple_account_data *sip) {
+static gchar* gen_pidf(struct simple_account_data *sip, gboolean open) {
 	gchar *doc = g_strdup_printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
 			"<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n"
 			"xmlns:im=\"urn:ietf:params:xml:ns:pidf:im\"\n"
 			"entity=\"sip:%s@%s\">\n"
 			"<tuple id=\"bs35r9f\">\n"
 			"<status>\n"
-			"<basic>open</basic>\n"
+			"<basic>%s</basic>\n"
 			"</status>\n"
 			"<note>%s</note>\n"
 			"</tuple>\n"
 			"</presence>",
 			sip->username,
 			sip->servername,
-			sip->status);
+			(open == TRUE) ? "open" : "closed",
+			(open == TRUE) ? sip->status : "");
 	return doc;
 }
 
 static void send_notify(struct simple_account_data *sip, struct simple_watcher *watcher) {
-	gchar *doc = watcher->needsxpidf ? gen_xpidf(sip) : gen_pidf(sip);
+	gchar *doc = watcher->needsxpidf ? gen_xpidf(sip) : gen_pidf(sip, TRUE);
 	gchar *hdr = watcher->needsxpidf ? "Event: presence\r\nContent-Type: application/xpidf+xml\r\n" : "Event: presence\r\nContent-Type: application/pidf+xml\r\n";
 	send_sip_request(sip->gc, "NOTIFY", watcher->name, watcher->name, hdr, doc, &watcher->dialog, NULL);
 	g_free(doc);
@@ -1223,9 +1225,9 @@
 	return TRUE;
 }
 
-static void send_publish(struct simple_account_data *sip) {
+static void send_open_publish(struct simple_account_data *sip) {
 	gchar *uri = g_strdup_printf("sip:%s@%s", sip->username, sip->servername);
-	gchar *doc = gen_pidf(sip);
+	gchar *doc = gen_pidf(sip, TRUE);
 	send_sip_request(sip->gc, "PUBLISH", uri, uri,
 		"Expires: 600\r\nEvent: presence\r\n"
 		"Content-Type: application/pidf+xml\r\n",
@@ -1235,6 +1237,18 @@
 	g_free(doc);
 }
 
+static void send_closed_publish(struct simple_account_data *sip) {
+	gchar *uri = g_strdup_printf("sip:%s@%s", sip->username, sip->servername);
+	gchar *doc = gen_pidf(sip, FALSE);
+	send_sip_request(sip->gc, "PUBLISH", uri, uri,
+		"Expires: 600\r\nEvent: presence\r\n"
+		"Content-Type: application/pidf+xml\r\n",
+		doc, NULL, process_publish_response);
+	/*sip->republish = time(NULL) + 500;*/
+	g_free(uri);
+	g_free(doc);
+}
+
 static void process_incoming_subscribe(struct simple_account_data *sip, struct sipmsg *msg) {
 	const char *from_hdr = sipmsg_find_header(msg, "From");
 	gchar *from = parse_from(from_hdr);
@@ -1738,7 +1752,14 @@
 	if(sip) {
 		/* unregister */
 		if (sip->registerstatus == SIMPLE_REGISTER_COMPLETE)
+		{
+			if(purple_account_get_bool(sip->account, 
+				"dopublish", 
+				TRUE))
+				send_closed_publish(sip);
+			
 			do_register_exp(sip, 0);
+		}
 		connection_free_all(sip);
 
 		if (sip->query_data != NULL)
--- a/libpurple/proxy.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/proxy.c	Mon Oct 15 18:56:04 2007 +0000
@@ -449,6 +449,8 @@
 static void
 proxy_connect_none(PurpleProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen)
 {
+	int flags;
+
 	purple_debug_info("proxy", "Connecting to %s:%d with no proxy\n",
 			connect_data->host, connect_data->port);
 
@@ -460,7 +462,8 @@
 		return;
 	}
 
-	fcntl(connect_data->fd, F_SETFL, O_NONBLOCK);
+	flags = fcntl(connect_data->fd, F_GETFL);
+	fcntl(connect_data->fd, F_SETFL, flags | O_NONBLOCK);
 #ifndef _WIN32
 	fcntl(connect_data->fd, F_SETFD, FD_CLOEXEC);
 #endif
@@ -881,6 +884,8 @@
 static void
 proxy_connect_http(PurpleProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen)
 {
+	int flags;
+
 	purple_debug_info("proxy",
 			   "Connecting to %s:%d via %s:%d using HTTP\n",
 			   connect_data->host, connect_data->port,
@@ -895,14 +900,16 @@
 		return;
 	}
 
-	fcntl(connect_data->fd, F_SETFL, O_NONBLOCK);
+	flags = fcntl(connect_data->fd, F_GETFL);
+	fcntl(connect_data->fd, F_SETFL, flags | O_NONBLOCK);
 #ifndef _WIN32
 	fcntl(connect_data->fd, F_SETFD, FD_CLOEXEC);
 #endif
 
 	if (connect(connect_data->fd, addr, addrlen) != 0)
 	{
-		if ((errno == EINPROGRESS) || (errno == EINTR)) {
+		if ((errno == EINPROGRESS) || (errno == EINTR))
+		{
 			purple_debug_info("proxy", "Connection in progress\n");
 
 			if (connect_data->port != 80)
@@ -1036,6 +1043,8 @@
 static void
 proxy_connect_socks4(PurpleProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen)
 {
+	int flags;
+
 	purple_debug_info("proxy",
 			   "Connecting to %s:%d via %s:%d using SOCKS4\n",
 			   connect_data->host, connect_data->port,
@@ -1050,7 +1059,8 @@
 		return;
 	}
 
-	fcntl(connect_data->fd, F_SETFL, O_NONBLOCK);
+	flags = fcntl(connect_data->fd, F_GETFL);
+	fcntl(connect_data->fd, F_SETFL, flags | O_NONBLOCK);
 #ifndef _WIN32
 	fcntl(connect_data->fd, F_SETFD, FD_CLOEXEC);
 #endif
@@ -1604,6 +1614,8 @@
 static void
 proxy_connect_socks5(PurpleProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen)
 {
+	int flags;
+
 	purple_debug_info("proxy",
 			   "Connecting to %s:%d via %s:%d using SOCKS5\n",
 			   connect_data->host, connect_data->port,
@@ -1618,7 +1630,8 @@
 		return;
 	}
 
-	fcntl(connect_data->fd, F_SETFL, O_NONBLOCK);
+	flags = fcntl(connect_data->fd, F_GETFL);
+	fcntl(connect_data->fd, F_SETFL, flags | O_NONBLOCK);
 #ifndef _WIN32
 	fcntl(connect_data->fd, F_SETFD, FD_CLOEXEC);
 #endif
--- a/libpurple/prpl.h	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/prpl.h	Mon Oct 15 18:56:04 2007 +0000
@@ -297,12 +297,13 @@
 	/** new user registration */
 	void (*register_user)(PurpleAccount *);
 
-	/** Deprecated and vestigal; use #get_cb_real_name and #get_info
-	 *  instead.
+	/**
+	 * @deprecated Use #PurplePluginProtocolInfo.get_info instead.
 	 */
 	void (*get_cb_info)(PurpleConnection *, int, const char *who);
-	/** Also deprecated and vestigal; use #get_cb_real_name and
-	 *  #status_text instead.
+	/**
+	 * @deprecated Use #PurplePluginProtocolInfo.get_cb_real_name and
+	 *             #PurplePluginProtocolInfo.status_text instead.
 	 */
 	void (*get_cb_away)(PurpleConnection *, int, const char *who);
 
--- a/libpurple/util.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/util.c	Mon Oct 15 18:56:04 2007 +0000
@@ -2565,6 +2565,8 @@
 	purple_debug_info("util", "Writing file %s\n",
 					filename_full);
 
+	g_return_val_if_fail((size >= -1), FALSE);
+
 	filename_temp = g_strdup_printf("%s.save", filename_full);
 
 	/* Remove an old temporary file, if one exists */
@@ -2590,7 +2592,7 @@
 	}
 
 	/* Write to file */
-	real_size = (size == -1) ? strlen(data) : size;
+	real_size = (size == -1) ? strlen(data) : (size_t) size;
 	byteswritten = fwrite(data, 1, real_size, file);
 
 	/* Close file */
--- a/libpurple/win32/global.mak	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/win32/global.mak	Mon Oct 15 18:56:04 2007 +0000
@@ -11,7 +11,7 @@
 # Locations of our various dependencies
 WIN32_DEV_TOP ?= $(PIDGIN_TREE_TOP)/../win32-dev
 ASPELL_TOP ?= $(WIN32_DEV_TOP)/aspell-dev-0-50-3-3
-GTKSPELL_TOP ?= $(WIN32_DEV_TOP)/gtkspell-2.0.11
+GTKSPELL_TOP ?= $(WIN32_DEV_TOP)/gtkspell-2.0.11-daa1
 GTK_TOP ?= $(WIN32_DEV_TOP)/gtk_2_0
 GTK_BIN ?= $(GTK_TOP)/bin
 BONJOUR_TOP ?= $(WIN32_DEV_TOP)/Bonjour_SDK
@@ -22,6 +22,7 @@
 PERL_LIB_TOP ?= $(WIN32_DEV_TOP)/perl58
 SILC_TOOLKIT ?= $(WIN32_DEV_TOP)/silc-toolkit-1.1.2
 TCL_LIB_TOP ?= $(WIN32_DEV_TOP)/tcl-8.4.5
+GSTREAMER_TOP ?= $(WIN32_DEV_TOP)/gstreamer-0.10.13
 
 # Where we installing this stuff to?
 PIDGIN_INSTALL_DIR := $(PIDGIN_TREE_TOP)/win32-install-dir
--- a/libpurple/win32/libc_interface.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/win32/libc_interface.c	Mon Oct 15 18:56:04 2007 +0000
@@ -138,12 +138,22 @@
 
 /* fcntl.h */
 /* This is not a full implementation of fcntl. Update as needed.. */
-int wpurple_fcntl(int socket, int command, int val) {
+int wpurple_fcntl(int socket, int command, ...) {
+
 	switch( command ) {
+	case F_GETFL:
+		return 0;
+
 	case F_SETFL:
 	{
+		va_list args;
+		int val;
 		int ret=0;
 
+		va_start(args, command);
+		val = va_arg(args, int);
+		va_end(args);
+
 		switch( val ) {
 		case O_NONBLOCK:
 		{
@@ -152,7 +162,7 @@
 			break;
 		}
 		case 0:
-	        {
+		{
 			u_long imode=0;
 			ret = ioctlsocket(socket, FIONBIO, &imode);
 			break;
--- a/libpurple/win32/libc_interface.h	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/win32/libc_interface.h	Mon Oct 15 18:56:04 2007 +0000
@@ -75,8 +75,8 @@
 wpurple_ioctl( fd, command, val )
 
 /* fcntl.h */
-#define fcntl( fd, command, val ) \
-wpurple_fcntl( fd, command, val )
+#define fcntl( fd, command, ... ) \
+wpurple_fcntl( fd, command, ##__VA_ARGS__ )
 
 /* arpa/inet.h */
 #define inet_aton( name, addr ) \
--- a/libpurple/win32/libc_internal.h	Mon Oct 15 18:52:51 2007 +0000
+++ b/libpurple/win32/libc_internal.h	Mon Oct 15 18:56:04 2007 +0000
@@ -49,9 +49,10 @@
 char* wpurple_strerror( int errornum );
 
 /* fcntl.h */
-int wpurple_fcntl(int socket, int command, int val);
-#define F_SETFL 1
-#define O_NONBLOCK 1
+int wpurple_fcntl(int socket, int command, ...);
+#define F_GETFL 3
+#define F_SETFL 4
+#define O_NONBLOCK 04000
 
 /* sys/ioctl.h */
 #define SIOCGIFCONF 0x8912 /* get iface list */
--- a/pidgin/gtkblist.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/pidgin/gtkblist.c	Mon Oct 15 18:56:04 2007 +0000
@@ -3907,7 +3907,7 @@
 			convs = pidgin_conversations_find_unseen_list(PURPLE_CONV_TYPE_IM,
 															PIDGIN_UNSEEN_TEXT, TRUE, 1);
 			if (convs) {
-				purple_conversation_present((PurpleConversation*)convs->data);
+				pidgin_conv_present_conversation((PurpleConversation*)convs->data);
 				g_list_free(convs);
 			}
 			break;
--- a/pidgin/gtkconv.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/pidgin/gtkconv.c	Mon Oct 15 18:56:04 2007 +0000
@@ -2853,8 +2853,7 @@
 		if (gtkconv != NULL && gtkconv->active_conv != conv)
 			continue;
 		if (gtkconv == NULL) {
-			if (!hidden_only ||
-					!purple_conversation_get_data(conv, "unseen-count"))
+			if (!purple_conversation_get_data(conv, "unseen-count"))
 				continue;
 			r = g_list_prepend(r, conv);
 			c++;
@@ -3524,6 +3523,7 @@
 
 		if (b == item_buddy) {
 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
+			g_list_free(child);
 			break;
 		}
 	}
@@ -6572,10 +6572,13 @@
 			style = "color=\"#c4a000\"";
 		} else if (gtkconv->unseen_state == PIDGIN_UNSEEN_NICK)	{
 			atk_object_set_description(accessibility_obj, _("Nick Said"));
-			style = "color=\"#204a87\"";
+			style = "color=\"#cc0000\"";
 		} else if (gtkconv->unseen_state == PIDGIN_UNSEEN_TEXT)	{
 			atk_object_set_description(accessibility_obj, _("Unread Messages"));
-			style = "color=\"#cc0000\"";
+			if (gtkconv->active_conv->type == PURPLE_CONV_TYPE_CHAT)
+				style = "color=\"#204a87\" weight=\"bold\"";
+			else
+				style = "color=\"#cc0000\" weight=\"bold\"";
 		} else if (gtkconv->unseen_state == PIDGIN_UNSEEN_EVENT) {
 			atk_object_set_description(accessibility_obj, _("New Event"));
 			style = "color=\"#888a85\"";
--- a/pidgin/gtkdocklet.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/pidgin/gtkdocklet.c	Mon Oct 15 18:56:04 2007 +0000
@@ -38,6 +38,7 @@
 #include "gtkprefs.h"
 #include "gtksavedstatuses.h"
 #include "gtksound.h"
+#include "gtkstatusbox.h"
 #include "gtkutils.h"
 #include "pidginstock.h"
 #include "gtkdocklet.h"
@@ -144,15 +145,22 @@
 		if (ui_ops->set_tooltip) {
 			GString *tooltip_text = g_string_new("");
 			for (l = convs, count = 0 ; l != NULL ; l = l->next, count++) {
-				if (PIDGIN_IS_PIDGIN_CONVERSATION(l->data)) {
-					PidginConversation *gtkconv = PIDGIN_CONVERSATION((PurpleConversation *)l->data);
-					if (count == DOCKLET_TOOLTIP_LINE_LIMIT - 1)
-						g_string_append(tooltip_text, _("Right-click for more unread messages...\n"));
-					else
-						g_string_append_printf(tooltip_text,
-							ngettext("%d unread message from %s\n", "%d unread messages from %s\n", gtkconv->unseen_count),
-							gtkconv->unseen_count,
-							gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)));
+				PurpleConversation *conv = (PurpleConversation *)l->data;
+				PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
+
+				if (count == DOCKLET_TOOLTIP_LINE_LIMIT - 1) {
+					g_string_append(tooltip_text, _("Right-click for more unread messages...\n"));
+				} else if(gtkconv) {
+					g_string_append_printf(tooltip_text,
+						ngettext("%d unread message from %s\n", "%d unread messages from %s\n", gtkconv->unseen_count),
+						gtkconv->unseen_count,
+						gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)));
+				} else {
+					g_string_append_printf(tooltip_text,
+						ngettext("%d unread message from %s\n", "%d unread messages from %s\n",
+						GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count"))),
+						GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count")),
+						purple_conversation_get_name(conv));
 				}
 			}
 
@@ -356,6 +364,10 @@
 }
 #endif
 
+/* There is a lot of code here for handling the status submenu, much of
+ * which is duplicated from the gtkstatusbox. It'd be nice to add API
+ * somewhere to simplify this (either in the statusbox, or in libpurple).
+ */
 static void
 show_custom_status_editor_cb(GtkMenuItem *menuitem, gpointer user_data)
 {
@@ -369,6 +381,70 @@
 		purple_savedstatus_is_transient(saved_status) ? saved_status : NULL);
 }
 
+static PurpleSavedStatus *
+create_transient_status(PurpleStatusPrimitive primitive, PurpleStatusType *status_type)
+{
+	PurpleSavedStatus *saved_status = purple_savedstatus_new(NULL, primitive);
+
+	if(status_type != NULL) {
+		GList *tmp, *active_accts = purple_accounts_get_all_active();
+		for (tmp = active_accts; tmp != NULL; tmp = tmp->next) {
+			purple_savedstatus_set_substatus(saved_status,
+				(PurpleAccount*) tmp->data, status_type, NULL);
+		}
+		g_list_free(active_accts);
+	}
+
+	return saved_status;
+}
+
+static void
+activate_status_account_cb(GtkMenuItem *menuitem, gpointer user_data)
+{
+	PurpleStatusType *status_type;
+	PurpleStatusPrimitive primitive;
+	PurpleSavedStatus *saved_status = NULL;
+	GList *iter = purple_savedstatuses_get_all();
+	GList *tmp, *active_accts = purple_accounts_get_all_active();
+
+	status_type = (PurpleStatusType *)user_data;
+	primitive = purple_status_type_get_primitive(status_type);
+
+	for (; iter != NULL; iter = iter->next) {
+		PurpleSavedStatus *ss = iter->data;
+		if ((purple_savedstatus_get_type(ss) == primitive) && purple_savedstatus_is_transient(ss) &&
+			purple_savedstatus_has_substatuses(ss))
+		{
+			gboolean found = FALSE;
+			/* The currently enabled accounts must have substatuses for all the active accts */
+			for(tmp = active_accts; tmp != NULL; tmp = tmp->next) {
+				PurpleAccount *acct = tmp->data;
+				PurpleSavedStatusSub *sub = purple_savedstatus_get_substatus(ss, acct);
+				if (sub) {
+					const PurpleStatusType *sub_type = purple_savedstatus_substatus_get_type(sub);
+					const char *subtype_status_id = purple_status_type_get_id(sub_type);
+					if (subtype_status_id && !strcmp(subtype_status_id,
+							purple_status_type_get_id(status_type)))
+						found = TRUE;
+				}
+			}
+			if (!found)
+				continue;
+			saved_status = ss;
+			break;
+		}
+	}
+
+	g_list_free(active_accts);
+
+	/* Create a new transient saved status if we weren't able to find one */
+	if (saved_status == NULL)
+		saved_status = create_transient_status(primitive, status_type);
+
+	/* Set the status for each account */
+	purple_savedstatus_activate(saved_status);
+}
+
 static void
 activate_status_primitive_cb(GtkMenuItem *menuitem, gpointer user_data)
 {
@@ -382,7 +458,7 @@
 
 	/* Create a new transient saved status if we weren't able to find one */
 	if (saved_status == NULL)
-		saved_status = purple_savedstatus_new(NULL, primitive);
+		saved_status = create_transient_status(primitive, NULL);
 
 	/* Set the status for each account */
 	purple_savedstatus_activate(saved_status);
@@ -425,31 +501,67 @@
 	return menuitem;
 }
 
+static void
+add_account_statuses(GtkWidget *menu, PurpleAccount *account)
+{
+	GList *l;
+
+	for (l = purple_account_get_status_types(account); l != NULL; l = l->next) {
+		PurpleStatusType *status_type = (PurpleStatusType *)l->data;
+		PurpleStatusPrimitive prim;
+
+		if (!purple_status_type_is_user_settable(status_type))
+			continue;
+
+		prim = purple_status_type_get_primitive(status_type);
+
+		new_menu_item_with_status_icon(menu,
+			purple_status_type_get_name(status_type),
+			prim, G_CALLBACK(activate_status_account_cb),
+			status_type, 0, 0, NULL);
+	}
+}
+
 static GtkWidget *
 docklet_status_submenu()
 {
 	GtkWidget *submenu, *menuitem;
 	GList *popular_statuses, *cur;
+	PidginStatusBox *statusbox = NULL;
 
 	submenu = gtk_menu_new();
 	menuitem = gtk_menu_item_new_with_label(_("Change Status"));
 	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
 
-	new_menu_item_with_status_icon(submenu, _("Available"),
-		PURPLE_STATUS_AVAILABLE, G_CALLBACK(activate_status_primitive_cb),
-		GINT_TO_POINTER(PURPLE_STATUS_AVAILABLE), 0, 0, NULL);
+	if(pidgin_blist_get_default_gtk_blist() != NULL) {
+		statusbox = PIDGIN_STATUS_BOX(pidgin_blist_get_default_gtk_blist()->statusbox);
+	}
 
-	new_menu_item_with_status_icon(submenu, _("Away"),
-		PURPLE_STATUS_AWAY, G_CALLBACK(activate_status_primitive_cb),
-		GINT_TO_POINTER(PURPLE_STATUS_AWAY), 0, 0, NULL);
+	if(statusbox && statusbox->account != NULL) {
+		add_account_statuses(submenu, statusbox->account);
+	} else if(statusbox && statusbox->token_status_account != NULL) {
+		add_account_statuses(submenu, statusbox->token_status_account);
+	} else {
+		new_menu_item_with_status_icon(submenu, _("Available"),
+			PURPLE_STATUS_AVAILABLE, G_CALLBACK(activate_status_primitive_cb),
+			GINT_TO_POINTER(PURPLE_STATUS_AVAILABLE), 0, 0, NULL);
 
-	new_menu_item_with_status_icon(submenu, _("Invisible"),
-		PURPLE_STATUS_INVISIBLE, G_CALLBACK(activate_status_primitive_cb),
-		GINT_TO_POINTER(PURPLE_STATUS_INVISIBLE), 0, 0, NULL);
+		new_menu_item_with_status_icon(submenu, _("Away"),
+			PURPLE_STATUS_AWAY, G_CALLBACK(activate_status_primitive_cb),
+			GINT_TO_POINTER(PURPLE_STATUS_AWAY), 0, 0, NULL);
+
+		new_menu_item_with_status_icon(submenu, _("Do not disturb"),
+			PURPLE_STATUS_UNAVAILABLE, G_CALLBACK(activate_status_primitive_cb),
+			GINT_TO_POINTER(PURPLE_STATUS_UNAVAILABLE), 0, 0, NULL);
 
-	new_menu_item_with_status_icon(submenu, _("Offline"),
-		PURPLE_STATUS_OFFLINE, G_CALLBACK(activate_status_primitive_cb),
-		GINT_TO_POINTER(PURPLE_STATUS_OFFLINE), 0, 0, NULL);
+		new_menu_item_with_status_icon(submenu, _("Invisible"),
+			PURPLE_STATUS_INVISIBLE, G_CALLBACK(activate_status_primitive_cb),
+			GINT_TO_POINTER(PURPLE_STATUS_INVISIBLE), 0, 0, NULL);
+
+		new_menu_item_with_status_icon(submenu, _("Offline"),
+			PURPLE_STATUS_OFFLINE, G_CALLBACK(activate_status_primitive_cb),
+			GINT_TO_POINTER(PURPLE_STATUS_OFFLINE), 0, 0, NULL);
+	}
 
 	popular_statuses = purple_savedstatuses_get_popular(6);
 	if (popular_statuses != NULL)
@@ -653,7 +765,7 @@
 			if (pending) {
 				GList *l = get_pending_list(1);
 				if (l != NULL) {
-					purple_conversation_present((PurpleConversation *)l->data);
+					pidgin_conv_present_conversation((PurpleConversation *)l->data);
 					g_list_free(l);
 				}
 			} else {
--- a/pidgin/gtkutils.c	Mon Oct 15 18:52:51 2007 +0000
+++ b/pidgin/gtkutils.c	Mon Oct 15 18:56:04 2007 +0000
@@ -850,16 +850,14 @@
 gboolean
 pidgin_check_if_dir(const char *path, GtkFileSelection *filesel)
 {
-	char *dirname;
+	char *dirname = NULL;
 
 	if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
 		/* append a / if needed */
 		if (path[strlen(path) - 1] != G_DIR_SEPARATOR) {
 			dirname = g_strconcat(path, G_DIR_SEPARATOR_S, NULL);
-		} else {
-			dirname = g_strdup(path);
 		}
-		gtk_file_selection_set_filename(filesel, dirname);
+		gtk_file_selection_set_filename(filesel, (dirname != NULL) ? dirname : path);
 		g_free(dirname);
 		return TRUE;
 	}
@@ -1178,14 +1176,15 @@
 	label = gtk_widget_get_accessible (l);
 
 	/* Make sure mnemonics work */
-        gtk_label_set_mnemonic_widget(GTK_LABEL(l), w);
-	
+	gtk_label_set_mnemonic_widget(GTK_LABEL(l), w);
+
 	/* Create the labeled-by relation */
 	set = atk_object_ref_relation_set (acc);
 	rel_obj[0] = label;
 	relation = atk_relation_new (rel_obj, 1, ATK_RELATION_LABELLED_BY);
 	atk_relation_set_add (set, relation);
 	g_object_unref (relation);
+	g_object_unref(set);
 
 	/* Create the label-for relation */
 	set = atk_object_ref_relation_set (label);
@@ -1193,6 +1192,7 @@
 	relation = atk_relation_new (rel_obj, 1, ATK_RELATION_LABEL_FOR);
 	atk_relation_set_add (set, relation);
 	g_object_unref (relation);
+	g_object_unref(set);
 }
 
 void