changeset 22141:04bdf1ff5d2a

merge of '43413f6662ecd55ea083fbbacb3f16c01843e655' and 'cd29baac3f6b045ec50d2511b143b39f8884b36d'
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Thu, 17 Jan 2008 08:12:37 +0000
parents 6ab421173406 (current diff) c69f472ff683 (diff)
children 6edcab92fb1d
files
diffstat 54 files changed, 690 insertions(+), 188 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Thu Jan 17 08:01:02 2008 +0000
+++ b/COPYRIGHT	Thu Jan 17 08:12:37 2008 +0000
@@ -270,6 +270,7 @@
 Padraig O'Briain
 Christopher O'Brien (siege)
 Jon Oberheide
+Yusuke Odate
 Ruediger Oertel
 Gudmundur Bjarni Olafsson
 Bartosz Oler
@@ -427,6 +428,7 @@
 Andrew Whewell
 Simon Wilkinson
 Dan Willemsen
+Justin Williams (Jaywalker)
 Jason Willis
 Matt Wilson
 Dan Winship
--- a/ChangeLog	Thu Jan 17 08:01:02 2008 +0000
+++ b/ChangeLog	Thu Jan 17 08:12:37 2008 +0000
@@ -9,7 +9,10 @@
 	  now required to use Bonjour.
 	* Partial support for viewing ICQ status notes (Collin from
 	  ComBOTS GmbH).
+	* Support for /notice on IRC.
 	* Support for Yahoo Messenger 7.0+ file transfer method (Thanumalayan S.)
+	* Support for retrieving full names and addresses from the address book
+	  on Yahoo! Japan (Yusuke Odate)
 
 	Pidgin:
 	* Added the ability to theme conversation name colors (red and blue)
@@ -23,14 +26,14 @@
 	Finch:
 	* Color is used in the buddylist to indicate status, and the conversation
 	  window to indicate various message attributes. Look at the sample gntrc
-	  file in the man-page for details.
+	  file in the man page for details.
 	* The default keybinding for dump-screen is now M-D and uses a file
 	  request dialog. M-d will properly delete-forward-word, and M-f has been
 	  fixed to imitate readline's behavior.
 	* New bindings alt+tab and alt+shift+tab to help navigating between the
-	  higlighted windows (details on the man-page).
+	  higlighted windows (details on the man page).
 	* Recently signed on (or off) buddies blink in the buddy list.
-	* New action 'Room List' in the action-list can be used to get the list of
+	* New action 'Room List' in the action list can be used to get the list of
 	  available chat rooms for an online account.
 
 version 2.3.1 (12/7/2007):
--- a/ChangeLog.API	Thu Jan 17 08:01:02 2008 +0000
+++ b/ChangeLog.API	Thu Jan 17 08:12:37 2008 +0000
@@ -18,6 +18,18 @@
 			* purple_roomlist_field_get_type
 			* purple_roomlist_field_get_label
 			* purple_roomlist_field_get_hidden
+		* unlocalized_name field in PurpleAttentionType for UIs that need it.
+		* Some accessor and mutator functions for PurpleAttentionType:
+			* purple_attention_type_set_name
+			* purple_attention_type_set_incoming_desc
+			* purple_attention_type_set_outgoing_desc
+			* purple_attention_type_set_icon_name
+			* purple_attention_type_set_unlocalized_name
+			* purple_attention_type_get_name
+			* purple_attention_type_get_incoming_desc
+			* purple_attention_type_get_outgoing_desc
+			* purple_attention_type_get_icon_name
+			* purple_attention_type_get_unlocalized_name
 
 	Pidgin:
 		Added:
--- a/libpurple/account.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/account.c	Thu Jan 17 08:12:37 2008 +0000
@@ -752,7 +752,7 @@
 
 	current_error = g_new0(PurpleConnectionErrorInfo, 1);
 	current_error->type = type;
-	current_error->description = g_strdup(description);
+	current_error->description = description;
 
 	set_current_error(account, current_error);
 }
--- a/libpurple/account.h	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/account.h	Thu Jan 17 08:12:37 2008 +0000
@@ -410,37 +410,34 @@
 void purple_account_set_status_types(PurpleAccount *account, GList *status_types);
 
 /**
- * Activates or deactivates a status.  All changes to the statuses of
- * an account go through this function or purple_account_set_status_list.
- *
- * Only independent statuses can be deactivated with this. To deactivate
- * an exclusive status, activate a different (and exclusive?) status.
+ * Variadic version of purple_account_set_status_list(); the variadic list
+ * replaces @a attrs, and should be <tt>NULL</tt>-terminated.
  *
- * @param account   The account.
- * @param status_id The ID of the status.
- * @param active    The active state.
- * @param ...       Pairs of attributes for the new status passed in
- *                  as a NULL-terminated list of id/value pairs.
+ * @copydoc purple_account_set_status_list()
  */
 void purple_account_set_status(PurpleAccount *account, const char *status_id,
-							 gboolean active, ...) G_GNUC_NULL_TERMINATED;
+	gboolean active, ...) G_GNUC_NULL_TERMINATED;
 
 
 /**
  * Activates or deactivates a status.  All changes to the statuses of
- * an account go through this function or purple_account_set_status.
+ * an account go through this function or purple_account_set_status().
  *
- * Only independent statuses can be deactivated with this. To deactivate
- * an exclusive status, activate a different (and exclusive?) status.
+ * You can only deactivate an exclusive status by activating another exclusive
+ * status.  So, if @a status_id is an exclusive status and @a active is @c
+ * FALSE, this function does nothing.
  *
  * @param account   The account.
  * @param status_id The ID of the status.
- * @param active    The active state.
- * @param attrs		A list of attributes in key/value pairs
+ * @param active    Whether @a status_id is to be activated (<tt>TRUE</tt>) or
+ *                  deactivated (<tt>FALSE</tt>).
+ * @param attrs     A list of <tt>const char *</tt> attribute names followed by
+ *                  <tt>const char *</tt> attribute values for the status.
+ *                  (For example, one pair might be <tt>"message"</tt> followed
+ *                  by <tt>"hello, talk to me!"</tt>.)
  */
 void purple_account_set_status_list(PurpleAccount *account,
-								  const char *status_id,
-								  gboolean active, GList *attrs);
+	const char *status_id, gboolean active, GList *attrs);
 
 /**
  * Clears all protocol-specific settings on an account.
--- a/libpurple/dbus-analyze-functions.py	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/dbus-analyze-functions.py	Thu Jan 17 08:12:37 2008 +0000
@@ -525,9 +525,10 @@
             try:
                 self.processfunction(functiontext, paramtexts)
             except MyException:
-                sys.stderr.write(myline + "\n")
+#                sys.stderr.write(myline + "\n")
+                 pass
             except:
-                sys.stderr.write(myline + "\n")
+#                sys.stderr.write(myline + "\n")
                 raise
 
         self.flush()
@@ -586,7 +587,7 @@
 else:
     fprefix = ""
 
-sys.stderr.write("%s: Functions not exported:\n" % sys.argv[0])
+#sys.stderr.write("%s: Functions not exported:\n" % sys.argv[0])
 
 if "client" in options:
     bindings = ClientBindingSet(sys.stdin, fprefix,
--- a/libpurple/dnsquery.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/dnsquery.c	Thu Jan 17 08:12:37 2008 +0000
@@ -159,6 +159,24 @@
 }
 #endif
 
+static void
+write_to_parent(int fd, const void *buf, size_t count)
+{
+	ssize_t written;
+
+	written = write(fd, buf, count);
+	if (written != count) {
+		if (written < 0)
+			fprintf(stderr, "dns[%d]: Error writing data to "
+					"parent: %s\n", getpid(), strerror(errno));
+		else
+			fprintf(stderr, "dns[%d]: Error: Tried to write %"
+					G_GSIZE_FORMAT " bytes to parent but instead "
+					"wrote %" G_GSIZE_FORMAT " bytes\n",
+					getpid(), count, written);
+	}
+}
+
 G_GNUC_NORETURN static void
 purple_dnsquery_resolver_run(int child_out, int child_in, gboolean show_debug)
 {
@@ -201,7 +219,8 @@
 		}
 		rc = read(child_in, &dns_params, sizeof(dns_params_t));
 		if (rc < 0) {
-			perror("read()");
+			fprintf(stderr, "dns[%d]: Error: Could not read dns_params: "
+					"%s\n", getpid(), strerror(errno));
 			break;
 		}
 		if (rc == 0) {
@@ -210,11 +229,13 @@
 			_exit(0);
 		}
 		if (dns_params.hostname[0] == '\0') {
-			printf("dns[%d]: hostname = \"\" (port = %d)!!!\n", getpid(), dns_params.port);
+			fprintf(stderr, "dns[%d]: Error: Parent requested resolution "
+					"of an empty hostname (port = %d)!!!\n", getpid(),
+					dns_params.port);
 			_exit(1);
 		}
 		/* Tell our parent that we read the data successfully */
-		write(child_out, &ch, sizeof(ch));
+		write_to_parent(child_out, &ch, sizeof(ch));
 
 		/* We have the hostname and port, now resolve the IP */
 
@@ -230,7 +251,7 @@
 		 */
 		hints.ai_socktype = SOCK_STREAM;
 		rc = getaddrinfo(dns_params.hostname, servname, &hints, &res);
-		write(child_out, &rc, sizeof(rc));
+		write_to_parent(child_out, &rc, sizeof(rc));
 		if (rc != 0) {
 			close(child_out);
 			if (show_debug)
@@ -242,17 +263,17 @@
 		tmp = res;
 		while (res) {
 			size_t ai_addrlen = res->ai_addrlen;
-			write(child_out, &ai_addrlen, sizeof(ai_addrlen));
-			write(child_out, res->ai_addr, res->ai_addrlen);
+			write_to_parent(child_out, &ai_addrlen, sizeof(ai_addrlen));
+			write_to_parent(child_out, res->ai_addr, res->ai_addrlen);
 			res = res->ai_next;
 		}
 		freeaddrinfo(tmp);
-		write(child_out, &zero, sizeof(zero));
+		write_to_parent(child_out, &zero, sizeof(zero));
 #else
 		if (!inet_aton(dns_params.hostname, &sin.sin_addr)) {
 			struct hostent *hp;
 			if (!(hp = gethostbyname(dns_params.hostname))) {
-				write(child_out, &h_errno, sizeof(int));
+				write_to_parent(child_out, &h_errno, sizeof(int));
 				close(child_out);
 				if (show_debug)
 					printf("DNS Error: %d\n", h_errno);
@@ -265,10 +286,10 @@
 			sin.sin_family = AF_INET;
 
 		sin.sin_port = htons(dns_params.port);
-		write(child_out, &zero, sizeof(zero));
-		write(child_out, &addrlen, sizeof(addrlen));
-		write(child_out, &sin, addrlen);
-		write(child_out, &zero, sizeof(zero));
+		write_to_parent(child_out, &zero, sizeof(zero));
+		write_to_parent(child_out, &addrlen, sizeof(addrlen));
+		write_to_parent(child_out, &sin, addrlen);
+		write_to_parent(child_out, &zero, sizeof(zero));
 #endif
 		dns_params.hostname[0] = '\0';
 	}
--- a/libpurple/dnssrv.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/dnssrv.c	Thu Jan 17 08:12:37 2008 +0000
@@ -200,12 +200,20 @@
 	PurpleSrvCallback cb = query_data->cb;
 	int status;
 
-	if (read(source, &size, sizeof(int)) > 0)
+	if (read(source, &size, sizeof(int)) == sizeof(int))
 	{
+		ssize_t red;
 		purple_debug_info("dnssrv","found %d SRV entries\n", size);
 		tmp = res = g_new0(PurpleSrvResponse, size);
 		for (i = 0; i < size; i++) {
-			read(source, tmp++, sizeof(PurpleSrvResponse));
+			red = read(source, tmp++, sizeof(PurpleSrvResponse));
+			if (red != sizeof(PurpleSrvResponse)) {
+				purple_debug_error("dnssrv","unable to read srv "
+						"response: %s\n", g_strerror(errno));
+				size = 0;
+				g_free(res);
+				res = NULL;
+			}
 		}
 	}
 	else
@@ -350,9 +358,12 @@
 	/* Child */
 	if (pid == 0)
 	{
+		g_free(query);
+
 		close(out[0]);
 		close(in[1]);
 		resolve(in[0], out[1]);
+		/* resolve() does not return */
 	}
 
 	close(out[1]);
--- a/libpurple/example/nullclient.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/example/nullclient.c	Thu Jan 17 08:12:37 2008 +0000
@@ -268,6 +268,7 @@
 	GMainLoop *loop = g_main_loop_new(NULL, FALSE);
 	PurpleAccount *account;
 	PurpleSavedStatus *status;
+	char *res;
 
 	/* libpurple's built-in DNS resolution forks processes to perform
 	 * blocking lookups without blocking the main process.  It does not
@@ -290,12 +291,20 @@
 		}
 	}
 	printf("Select the protocol [0-%d]: ", i-1);
-	fgets(name, sizeof(name), stdin);
+	res = fgets(name, sizeof(name), stdin);
+	if (!res) {
+		fprintf(stderr, "Failed to gets protocol selection.");
+		abort();
+	}
 	sscanf(name, "%d", &num);
 	prpl = g_list_nth_data(names, num);
 
 	printf("Username: ");
-	fgets(name, sizeof(name), stdin);
+	res = fgets(name, sizeof(name), stdin);
+	if (!res) {
+		fprintf(stderr, "Failed to read user name.");
+		abort();
+	}
 	name[strlen(name) - 1] = 0;  /* strip the \n at the end */
 
 	/* Create the account */
--- a/libpurple/ft.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/ft.c	Thu Jan 17 08:12:37 2008 +0000
@@ -32,6 +32,7 @@
 #include "proxy.h"
 #include "request.h"
 #include "util.h"
+#include "debug.h"
 
 #define FT_INITIAL_BUFFER_SIZE 4096
 #define FT_MAX_BUFFER_SIZE     65535
@@ -903,7 +904,12 @@
 	if (condition & PURPLE_INPUT_READ) {
 		r = purple_xfer_read(xfer, &buffer);
 		if (r > 0) {
-			fwrite(buffer, 1, r, xfer->dest_fp);
+			const size_t wc = fwrite(buffer, 1, r, xfer->dest_fp);
+			if (wc != r) {
+				purple_debug_error("filetransfer", "Unable to write whole buffer.\n");
+				purple_xfer_cancel_remote(xfer);
+				return;
+			}
 		} else if(r < 0) {
 			purple_xfer_cancel_remote(xfer);
 			return;
@@ -911,6 +917,7 @@
 	}
 
 	if (condition & PURPLE_INPUT_WRITE) {
+		size_t result;
 		size_t s = MIN(purple_xfer_get_bytes_remaining(xfer), xfer->current_buffer_size);
 
 		/* this is so the prpl can keep the connection open
@@ -925,7 +932,13 @@
 
 		buffer = g_malloc0(s);
 
-		fread(buffer, 1, s, xfer->dest_fp);
+		result = fread(buffer, 1, s, xfer->dest_fp);
+		if (result != s) {
+			purple_debug_error("filetransfer", "Unable to read whole buffer.\n");
+			purple_xfer_cancel_remote(xfer);
+			g_free(buffer);
+			return;
+		}
 
 		/* Write as much as we're allowed to. */
 		r = purple_xfer_write(xfer, buffer, s);
--- a/libpurple/log.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/log.c	Thu Jan 17 08:12:37 2008 +0000
@@ -1859,11 +1859,15 @@
 
 static char * old_logger_read (PurpleLog *log, PurpleLogReadFlags *flags)
 {
+	size_t result;
 	struct old_logger_data *data = log->logger_data;
-	FILE *file = g_fopen(purple_stringref_value(data->pathref), "rb");
+	const char *path = purple_stringref_value(data->pathref);
+	FILE *file = g_fopen(path, "rb");
 	char *read = g_malloc(data->length + 1);
 	fseek(file, data->offset, SEEK_SET);
-	fread(read, data->length, 1, file);
+	result = fread(read, data->length, 1, file);
+	if (result != 1)
+		purple_debug_error("log", "Unable to read from log file: %s\n", path);
 	fclose(file);
 	read[data->length] = '\0';
 	*flags = 0;
--- a/libpurple/protocols/bonjour/jabber.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/bonjour/jabber.c	Thu Jan 17 08:12:37 2008 +0000
@@ -995,7 +995,7 @@
 			bb->conversation = NULL;
 	}
 
-	purple_timeout_add(0, _async_bonjour_jabber_close_conversation_cb, bconv);
+	bconv->close_timeout = purple_timeout_add(0, _async_bonjour_jabber_close_conversation_cb, bconv);
 }
 
 void
@@ -1054,6 +1054,9 @@
 		if (bconv->context != NULL)
 			bonjour_parser_setup(bconv);
 
+		if (bconv->close_timeout != 0)
+			purple_timeout_remove(bconv->close_timeout);
+
 		g_free(bconv->buddy_name);
 		g_free(bconv->ip);
 		g_free(bconv);
--- a/libpurple/protocols/bonjour/jabber.h	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/bonjour/jabber.h	Thu Jan 17 08:12:37 2008 +0000
@@ -47,6 +47,7 @@
 	gint socket;
 	guint rx_handler;
 	guint tx_handler;
+	guint close_timeout;
 	PurpleCircBuffer *tx_buf;
 	int sent_stream_start; /* 0 = Unsent, 1 = Partial, 2 = Complete */
 	gboolean recv_stream_start;
--- a/libpurple/protocols/irc/dcc_send.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/irc/dcc_send.c	Thu Jan 17 08:12:37 2008 +0000
@@ -51,9 +51,14 @@
  */
 static void irc_dccsend_recv_ack(PurpleXfer *xfer, const guchar *data, size_t size) {
 	unsigned long l;
+	size_t result;
 
 	l = htonl(xfer->bytes_sent);
-	write(xfer->fd, &l, sizeof(l));
+	result = write(xfer->fd, &l, sizeof(l));
+	if (result != sizeof(l)) {
+		purple_debug_error("irc", "unable to send acknowledgement: %s\n", g_strerror(errno));
+		/* TODO: We should probably close the connection here or something. */
+	}
 }
 
 static void irc_dccsend_recv_init(PurpleXfer *xfer) {
--- a/libpurple/protocols/jabber/jabber.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Thu Jan 17 08:12:37 2008 +0000
@@ -2301,14 +2301,10 @@
 GList *jabber_attention_types(PurpleAccount *account)
 {
 	static GList *types = NULL;
-	PurpleAttentionType *attn;
 
 	if (!types) {
-		attn = g_new0(PurpleAttentionType, 1);
-		attn->name = _("Buzz");
-		attn->incoming_description = _("%s has buzzed you!");
-		attn->outgoing_description = _("Buzzing %s...");
-		types = g_list_append(types, attn);
+		types = g_list_append(types, purple_attention_type_new("Buzz", _("Buzz"),
+				_("%s has buzzed you!"), _("Buzzing %s...")));
 	}
 
 	return types;
--- a/libpurple/protocols/msn/msn.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/msn/msn.c	Thu Jan 17 08:12:37 2008 +0000
@@ -122,15 +122,11 @@
 static GList *
 msn_attention_types(PurpleAccount *account)
 {
-	PurpleAttentionType *attn;
 	static GList *list = NULL;
 
 	if (!list) {
-		attn = g_new0(PurpleAttentionType, 1);
-		attn->name = _("Nudge");
-		attn->incoming_description = _("%s has nudged you!");
-		attn->outgoing_description = _("Nudging %s...");
-		list = g_list_append(list, attn);
+		list = g_list_append(list, purple_attention_type_new("Nudge", _("Nudge"),
+				_("%s has nudged you!"), _("Nudging %s...")));
 	}
 
 	return list;
@@ -355,7 +351,7 @@
 						_("Do you want to allow or disallow people on "
 						  "your buddy list to send you MSN Mobile pages "
 						  "to your cell phone or other mobile device?"),
-						-1,
+						PURPLE_DEFAULT_ACTION_NONE,
 						purple_connection_get_account(gc), NULL, NULL,
 						gc, 3,
 						_("Allow"), G_CALLBACK(enable_msn_pages_cb),
--- a/libpurple/protocols/msnp9/msn.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/msnp9/msn.c	Thu Jan 17 08:12:37 2008 +0000
@@ -122,15 +122,11 @@
 static GList *
 msn_attention_types(PurpleAccount *account)
 {
-	PurpleAttentionType *attn;
 	static GList *list = NULL;
 
 	if (!list) {
-		attn = g_new0(PurpleAttentionType, 1);
-		attn->name = _("Nudge");
-		attn->incoming_description = _("%s has nudged you!");
-		attn->outgoing_description = _("Nudging %s...");
-		list = g_list_append(list, attn);
+		list = g_list_append(list, purple_attention_type_new("Nudge", _("Nudge"),
+				_("%s has nudged you!"), _("Nudging %s...")));
 	}
 
 	return list;
--- a/libpurple/protocols/msnp9/notification.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/msnp9/notification.c	Thu Jan 17 08:12:37 2008 +0000
@@ -1012,7 +1012,7 @@
 	{
 		purple_debug_error("msn",
 						 "Error opening temp passport file: %s\n",
-						 strerror(errno));
+						 g_strerror(errno));
 	}
 	else
 	{
@@ -1061,7 +1061,7 @@
 		{
 			purple_debug_error("msn",
 							 "Error closing temp passport file: %s\n",
-							 strerror(errno));
+							 g_strerror(errno));
 
 			g_unlink(session->passport_info.file);
 			g_free(session->passport_info.file);
--- a/libpurple/protocols/msnp9/servconn.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/msnp9/servconn.c	Thu Jan 17 08:12:37 2008 +0000
@@ -392,7 +392,7 @@
 		return;
 	else if (len <= 0)
 	{
-		purple_debug_error("msn", "servconn read error, len: %d error: %s\n", len, strerror(errno));
+		purple_debug_error("msn", "servconn read error, len: %d error: %s\n", len, g_strerror(errno));
 		msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_READ);
 
 		return;
--- a/libpurple/protocols/myspace/myspace.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/myspace/myspace.c	Thu Jan 17 08:12:37 2008 +0000
@@ -2316,6 +2316,69 @@
 	msim_msg_free(blocklist_msg);
 }
 
+/**
+ * Borrowed this code from oscar_normalize. Added checking for "if userid, get name before normalizing"
+ *
+ * Basically... Returns a string that has been formated with all the spaces and caps removed.
+ */
+const char *msim_normalize(const PurpleAccount *account, const char *str) {
+	static char normalized[BUF_LEN];
+	MsimSession *session;
+	char *tmp1, *tmp2;
+	int i, j;
+	guint id;
+
+	g_return_val_if_fail(str != NULL, NULL);
+
+	if (msim_is_userid(str)) {
+		/* Have user ID, we need to get their username first :) */
+		const char *username;
+
+		/* If the account does not exist, we can't look up the user. */
+		g_return_val_if_fail(account != NULL, str);
+		g_return_val_if_fail(account->gc != NULL, str);
+		g_return_val_if_fail(account->gc->state == PURPLE_CONNECTED, str);
+
+		purple_debug_info("msim_normalize", "%s is a userid\n",str);
+
+		session = (MsimSession *)account->gc->proto_data;
+		id = atol(str);
+		username = msim_uid2username_from_blist(session, id);
+		if (!username) {
+			/* Not in buddy list... scheisse... TODO: Manual Lookup! */
+			/* Note: manual lookup using msim_lookup_user() is a problem inside 
+			 * msim_normalize(), because msim_lookup_user() calls a callback function
+			 * when the user information has been looked up, but msim_normalize() expects
+			 * the result immediately. */
+			purple_debug_info("msim_normalize", "Failure! %s is not in my list\n", str);
+			strncpy(normalized, str, BUF_LEN);
+		} else {
+			purple_debug_info("msim_normalize","%d is %s\n", id, username);
+			strncpy(normalized, username, BUF_LEN);
+		}
+	} else {
+		/* Have username. */
+		strncpy(normalized, str, BUF_LEN);
+	}
+
+	/* Strip spaces. */
+	for (i=0, j=0; normalized[j]; i++, j++) {
+		while (normalized[j] == ' ')
+			j++;
+		normalized[i] = normalized[j];
+	}
+	normalized[i] = '\0';
+
+	/* Lowercase and perform UTF-8 normalization. */
+	tmp1 = g_utf8_strdown(normalized, -1);
+	tmp2 = g_utf8_normalize(tmp1, -1, G_NORMALIZE_DEFAULT);
+	g_snprintf(normalized, sizeof(normalized), "%s", tmp2);
+	g_free(tmp2);
+	g_free(tmp1);
+
+	return normalized;
+}
+
 /** Return whether the buddy can be messaged while offline.
  *
  * The protocol supports offline messages in just the same way as online
@@ -2970,7 +3033,7 @@
 	NULL,              /* rename_group */
 	NULL,              /* buddy_free */
 	NULL,              /* convo_closed */
-	NULL,              /* normalize */
+	msim_normalize,    /* normalize */
 	NULL,              /* set_buddy_icon */
 	NULL,              /* remove_group */
 	NULL,              /* get_cb_real_name */
--- a/libpurple/protocols/myspace/myspace.h	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/myspace/myspace.h	Thu Jan 17 08:12:37 2008 +0000
@@ -180,8 +180,6 @@
 #define MSIM_CONTACT_LIST_IMPORT_ALL_FRIENDS	1
 #define MSIM_CONTACT_LIST_IMPORT_TOP_FRIENDS	2
 
-#define MsimAttentionType PurpleAttentionType
-
 /* Functions */
 gboolean msim_load(PurplePlugin *plugin);
 GList *msim_status_types(PurpleAccount *acct);
@@ -201,6 +199,8 @@
 void msim_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
 void msim_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
 
+const char *msim_normalize(const PurpleAccount *account, const char *str);
+
 gboolean msim_offline_message(const PurpleBuddy *buddy);
 
 void msim_close(PurpleConnection *gc);
--- a/libpurple/protocols/myspace/zap.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/myspace/zap.c	Thu Jan 17 08:12:37 2008 +0000
@@ -29,15 +29,12 @@
 msim_attention_types(PurpleAccount *acct)
 {
 	static GList *types = NULL;
-	MsimAttentionType* attn;
+	PurpleAttentionType* attn;
 
 	if (!types) {
-#define _MSIM_ADD_NEW_ATTENTION(icn, nme, incoming, outgoing)              \
-		attn = g_new0(MsimAttentionType, 1);                       \
-		attn->icon_name = icn;                                     \
-		attn->name = nme;                                          \
-		attn->incoming_description = incoming;                     \
-		attn->outgoing_description = outgoing;                     \
+#define _MSIM_ADD_NEW_ATTENTION(icn, ulname, nme, incoming, outgoing) \
+		attn = purple_attention_type_new(ulname, nme, incoming, outgoing); \
+		purple_attention_type_set_icon_name(attn, icn); \
 		types = g_list_append(types, attn);
 
 		/* TODO: icons for each zap */
@@ -48,37 +45,46 @@
 		 * projectile or weapon."  This term often has an electrical
 		 * connotation, for example, "he was zapped by electricity when
 		 * he put a fork in the toaster." */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Zap"), _("%s has zapped you!"), _("Zapping %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Zap", _("Zap"), _("%s has zapped you!"),
+				_("Zapping %s..."));
 
 		/* Whack means "to hit or strike someone with a sharp blow" */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Whack"), _("%s has whacked you!"), _("Whacking %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Whack", _("Whack"),
+				_("%s has whacked you!"), _("Whacking %s..."));
 
 		/* Torch means "to set on fire."  Don't worry, this doesn't
 		 * make a whole lot of sense in English, either.  Feel free
 		 * to translate it literally. */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Torch"), _("%s has torched you!"), _("Torching %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Torch", _("Torch"),
+				_("%s has torched you!"), _("Torching %s..."));
 
 		/* Smooch means "to kiss someone, often enthusiastically" */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Smooch"), _("%s has smooched you!"), _("Smooching %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Smooch", _("Smooch"),
+				_("%s has smooched you!"), _("Smooching %s..."));
 
 		/* A hug is a display of affection; wrapping your arms around someone */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Hug"), _("%s has hugged you!"), _("Hugging %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Hug", _("Hug"), _("%s has hugged you!"),
+				_("Hugging %s..."));
 
 		/* Slap means "to hit someone with an open/flat hand" */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Slap"), _("%s has slapped you!"), _("Slapping %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Slap", _("Slap"),
+				_("%s has slapped you!"), _("Slapping %s..."));
 
 		/* Goose means "to pinch someone on their butt" */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Goose"), _("%s has goosed you!"), _("Goosing %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Goose", _("Goose"),
+				_("%s has goosed you!"), _("Goosing %s..."));
 
 		/* A high-five is when two people's hands slap each other
 		 * in the air above their heads.  It is done to celebrate
 		 * something, often a victory, or to congratulate someone. */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("High-five"), _("%s has high-fived you!"), _("High-fiving %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "High-five", _("High-five"),
+				_("%s has high-fived you!"), _("High-fiving %s..."));
 
 		/* We're not entirely sure what the MySpace people mean by
 		 * this... but we think it's the equivalent of "prank."  Or, for
 		 * someone to perform a mischievous trick or practical joke. */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Punk"), _("%s has punk'd you!"), _("Punking %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Punk", _("Punk"),
+				_("%s has punk'd you!"), _("Punking %s..."));
 
 		/* Raspberry is a slang term for the vibrating sound made
 		 * when you stick your tongue out of your mouth with your
@@ -87,7 +93,8 @@
 		 * gesture, so it does not carry a harsh negative
 		 * connotation.  It is generally used in a playful tone
 		 * with friends. */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Raspberry"), _("%s has raspberried you!"), _("Raspberrying %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Raspberry", _("Raspberry"),
+				_("%s has raspberried you!"), _("Raspberrying %s..."));
 	}
 
 	return types;
@@ -99,14 +106,14 @@
 {
 	GList *types;
 	MsimSession *session;
-	MsimAttentionType *attn;
+	PurpleAttentionType *attn;
 	PurpleBuddy *buddy;
 
 	session = (MsimSession *)gc->proto_data;
 
 	/* Look for this attention type, by the code index given. */
 	types = msim_attention_types(gc->account);
-	attn = (MsimAttentionType *)g_list_nth_data(types, code);
+	attn = (PurpleAttentionType *)g_list_nth_data(types, code);
 
 	if (!attn) {
 		purple_debug_info("msim_send_attention", "got invalid zap code %d\n", code);
@@ -200,12 +207,12 @@
 	i = 0;
 	do
 	{
-		MsimAttentionType *attn;
+		PurpleAttentionType *attn;
 
-		attn = (MsimAttentionType *)types->data;
+		attn = (PurpleAttentionType *)types->data;
 
-		act = purple_menu_action_new(attn->name, PURPLE_CALLBACK(msim_send_zap_from_menu),
-				GUINT_TO_POINTER(i), NULL);
+		act = purple_menu_action_new(purple_attention_type_get_name(attn),
+				PURPLE_CALLBACK(msim_send_zap_from_menu), GUINT_TO_POINTER(i), NULL);
 		zap_menu = g_list_append(zap_menu, act);
 
 		++i;
--- a/libpurple/protocols/novell/nmfield.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/novell/nmfield.c	Thu Jan 17 08:12:37 2008 +0000
@@ -164,9 +164,7 @@
 		case NMFIELD_TYPE_BINARY:
 		case NMFIELD_TYPE_UTF8:
 		case NMFIELD_TYPE_DN:
-			if (field->ptr_value != NULL) {
-				g_free(field->ptr_value);
-			}
+			g_free(field->ptr_value);
 			break;
 
 		case NMFIELD_TYPE_ARRAY:
--- a/libpurple/protocols/novell/novell.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/novell/novell.c	Thu Jan 17 08:12:37 2008 +0000
@@ -1920,6 +1920,7 @@
 	parms = g_slist_append(parms, nm_event_get_conference(event));
 
 	/* Prompt the user */
+	/* TODO: Would it be better to use serv_got_chat_invite() here? */
 	gc = purple_account_get_connection(user->client_data);
 	purple_request_action(gc, title, primary, secondary,
 						PURPLE_DEFAULT_ACTION_NONE,
--- a/libpurple/protocols/oscar/family_buddy.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/oscar/family_buddy.c	Thu Jan 17 08:12:37 2008 +0000
@@ -219,8 +219,9 @@
 	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
 		ret = userfunc(od, conn, frame, &userinfo);
 
-	if (snac->subtype == SNAC_SUBTYPE_BUDDY_ONCOMING)
-		aim_locate_requestuserinfo(od, userinfo.sn);
+	if (snac->subtype == SNAC_SUBTYPE_BUDDY_ONCOMING && userinfo.flags & AIM_FLAG_AWAY)
+		aim_locate_autofetch_away_message(od, userinfo.sn);
+
 	aim_info_free(&userinfo);
 
 	return ret;
--- a/libpurple/protocols/oscar/family_locate.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/oscar/family_locate.c	Thu Jan 17 08:12:37 2008 +0000
@@ -386,11 +386,11 @@
 }
 
 void
-aim_locate_requestuserinfo(OscarData *od, const char *sn)
+aim_locate_autofetch_away_message(OscarData *od, const char *sn)
 {
 	struct userinfo_node *cur;
 
-	/* Make sure we haven't already requested info for this buddy */
+	/* Make sure we haven't already made an info request for this buddy */
 	for (cur = od->locate.requested; cur != NULL; cur = cur->next)
 		if (aim_sncmp(sn, cur->sn) == 0)
 			return;
@@ -401,7 +401,7 @@
 	cur->next = od->locate.requested;
 	od->locate.requested = cur;
 
-	aim_locate_getinfoshort(od, cur->sn, 0x00000003);
+	aim_locate_getinfoshort(od, cur->sn, 0x00000002);
 }
 
 aim_userinfo_t *aim_locate_finduserinfo(OscarData *od, const char *sn) {
--- a/libpurple/protocols/oscar/libaim.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/oscar/libaim.c	Thu Jan 17 08:12:37 2008 +0000
@@ -92,11 +92,11 @@
 	NULL,					/* whiteboard_prpl_ops */
 	NULL,					/* send_raw */
 	NULL,					/* roomlist_room_serialize */
+	NULL,					/* unregister_user */
+	NULL,					/* send_attention */
+	NULL,					/* get_attention_types */
 
 	/* padding */
-	NULL,
-	NULL,
-	NULL,
 	NULL
 };
 
--- a/libpurple/protocols/oscar/libicq.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/oscar/libicq.c	Thu Jan 17 08:12:37 2008 +0000
@@ -92,11 +92,11 @@
 	NULL,					/* whiteboard_prpl_ops */
 	NULL,					/* send_raw */
 	NULL,					/* roomlist_room_serialize */
+	NULL,					/* unregister_user */
+	NULL,					/* send_attention */
+	NULL,					/* get_attention_types */
 
 	/* padding */
-	NULL,
-	NULL,
-	NULL,
 	NULL
 };
 
--- a/libpurple/protocols/oscar/oscar.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Thu Jan 17 08:12:37 2008 +0000
@@ -1517,6 +1517,7 @@
 {
 	struct pieceofcrap *pos = data;
 	gchar *buf;
+	ssize_t result;
 
 	if (!PURPLE_CONNECTION_IS_VALID(pos->gc))
 	{
@@ -1528,8 +1529,8 @@
 	pos->fd = source;
 
 	if (source < 0) {
-		buf = g_strdup_printf(_("You may be disconnected shortly.  You may want to use TOC until "
-			"this is fixed.  Check %s for updates."), PURPLE_WEBSITE);
+		buf = g_strdup_printf(_("You may be disconnected shortly.  "
+				"Check %s for updates."), PURPLE_WEBSITE);
 		purple_notify_warning(pos->gc, NULL,
 							_("Unable to get a valid AIM login hash."),
 							buf);
@@ -1541,7 +1542,18 @@
 
 	buf = g_strdup_printf("GET " AIMHASHDATA "?offset=%ld&len=%ld&modname=%s HTTP/1.0\n\n",
 			pos->offset, pos->len, pos->modname ? pos->modname : "");
-	write(pos->fd, buf, strlen(buf));
+	result = send(pos->fd, buf, strlen(buf), 0);
+	if (result != strlen(buf)) {
+		if (result < 0)
+			purple_debug_error("oscar", "Error writing %" G_GSIZE_FORMAT
+					" bytes to fetch AIM hash data: %s\n",
+					strlen(buf), g_strerror(errno));
+		else
+			purple_debug_error("oscar", "Tried to write %"
+					G_GSIZE_FORMAT " bytes to fetch AIM hash data but "
+					"instead wrote %" G_GSIZE_FORMAT " bytes\n",
+					strlen(buf), result);
+	}
 	g_free(buf);
 	g_free(pos->modname);
 	pos->inpa = purple_input_add(pos->fd, PURPLE_INPUT_READ, damn_you, pos);
@@ -1723,7 +1735,6 @@
 	int type = 0;
 	gboolean buddy_is_away = FALSE;
 	const char *status_id;
-	char *itmsurl = NULL;
 	va_list ap;
 	aim_userinfo_t *info;
 
@@ -1771,11 +1782,6 @@
 			status_id = OSCAR_STATUS_ID_AVAILABLE;
 	}
 
-	if (info->itmsurl_encoding && info->itmsurl && info->itmsurl_len)
-		/* Grab the iTunes Music Store URL */
-		itmsurl = oscar_encoding_to_utf8(account, info->itmsurl_encoding,
-				info->itmsurl, info->itmsurl_len);
-
 	if (info->flags & AIM_FLAG_WIRELESS)
 	{
 		purple_prpl_got_user_status(account, info->sn, OSCAR_STATUS_ID_MOBILE, NULL);
@@ -1783,27 +1789,31 @@
 		purple_prpl_got_user_status_deactive(account, info->sn, OSCAR_STATUS_ID_MOBILE);
 	}
 
-	if (status_id == OSCAR_STATUS_ID_AVAILABLE)
+	if (strcmp(status_id, OSCAR_STATUS_ID_AVAILABLE) == 0)
 	{
 		char *message = NULL;
+		char *itmsurl = NULL;
 
 		if (info->status != NULL && info->status[0] != '\0')
 			/* Grab the available message */
 			message = oscar_encoding_to_utf8(account, info->status_encoding,
 					info->status, info->status_len);
 
+		if (info->itmsurl_encoding && info->itmsurl && info->itmsurl_len)
+			/* Grab the iTunes Music Store URL */
+			itmsurl = oscar_encoding_to_utf8(account, info->itmsurl_encoding,
+					info->itmsurl, info->itmsurl_len);
+
 		purple_prpl_got_user_status(account, info->sn, status_id,
 				"message", message, "itmsurl", itmsurl, NULL);
 
 		g_free(message);
+		g_free(itmsurl);
 	}
 	else
 	{
-		purple_prpl_got_user_status(account, info->sn, status_id,
-				"itmsurl", itmsurl, NULL);
-	}
-
-	g_free(itmsurl);
+		purple_prpl_got_user_status(account, info->sn, status_id, NULL);
+	}
 
 	/* Login time stuff */
 	if (info->present & AIM_USERINFO_PRESENT_ONLINESINCE)
@@ -4444,7 +4454,6 @@
 	PurplePresence *presence;
 	PurpleStatusType *status_type;
 	PurpleStatusPrimitive primitive;
-	gboolean invisible;
 
 	char *htmlinfo;
 	char *info_encoding = NULL;
@@ -4459,7 +4468,6 @@
 	status_type = purple_status_get_type(status);
 	primitive = purple_status_type_get_primitive(status_type);
 	presence = purple_account_get_presence(account);
-	invisible = purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_INVISIBLE);
 
 	if (!setinfo)
 	{
@@ -5219,7 +5227,7 @@
 	data->nick = (buddy ? g_strdup(purple_buddy_get_alias_only(buddy)) : NULL);
 
 	purple_request_yes_no(gc, NULL, _("Authorization Given"), dialog_msg,
-						1, /* Default action is "no" */
+						PURPLE_DEFAULT_ACTION_NONE,
 						purple_connection_get_account(gc), sn, NULL,
 						data,
 						G_CALLBACK(purple_icq_buddyadd),
@@ -5975,7 +5983,7 @@
 			_("Because this reveals your IP address, it "
 			  "may be considered a security risk.  Do you "
 			  "wish to continue?"),
-			0,
+			0, /* Default action is "connect" */
 			purple_connection_get_account(gc), data->who, NULL,
 			data, 2,
 			_("C_onnect"), G_CALLBACK(oscar_ask_directim_yes_cb),
--- a/libpurple/protocols/oscar/oscar.h	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/oscar/oscar.h	Thu Jan 17 08:12:37 2008 +0000
@@ -1074,7 +1074,7 @@
 /* 0x000f */ int aim_locate_setinterests(OscarData *od, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, guint16 privacy);
 /* 0x0015 */ int aim_locate_getinfoshort(OscarData *od, const char *sn, guint32 flags);
 
-void aim_locate_requestuserinfo(OscarData *od, const char *sn);
+void aim_locate_autofetch_away_message(OscarData *od, const char *sn);
 guint32 aim_locate_getcaps(OscarData *od, ByteStream *bs, int len);
 guint32 aim_locate_getcaps_short(OscarData *od, ByteStream *bs, int len);
 void aim_info_free(aim_userinfo_t *);
--- a/libpurple/protocols/oscar/peer.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/oscar/peer.c	Thu Jan 17 08:12:37 2008 +0000
@@ -1041,7 +1041,7 @@
 						  "Images.  Because your IP address will be "
 						  "revealed, this may be considered a privacy "
 						  "risk."),
-						PURPLE_DEFAULT_ACTION_NONE,
+						0, /* Default action is "connect" */
 						account, sn, NULL,
 						conn, 2,
 						_("C_onnect"), G_CALLBACK(peer_connection_got_proposition_yes_cb),
--- a/libpurple/protocols/qq/file_trans.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/qq/file_trans.c	Thu Jan 17 08:12:37 2008 +0000
@@ -97,6 +97,7 @@
 	guint8 *buffer;
 	PurpleCipher *cipher;
 	PurpleCipherContext *context;
+	size_t wc;
 
 	const gint QQ_MAX_FILE_MD5_LENGTH = 10002432;
 
@@ -109,15 +110,20 @@
 
 	buffer = g_newa(guint8, filelen);
 	g_return_if_fail(buffer != NULL);
-	fread(buffer, filelen, 1, fp);
+	wc = fread(buffer, filelen, 1, fp);
+	fclose(fp);
+	if (wc != 1) {
+		purple_debug_error("qq", "Unable to read file: %s\n", filename);
+
+		/* TODO: XXX: Really, the caller should be modified to deal with this properly. */
+		return;
+	}
 
 	cipher = purple_ciphers_find_cipher("md5");
 	context = purple_cipher_context_new(cipher, NULL);
 	purple_cipher_context_append(context, buffer, filelen);
 	purple_cipher_context_digest(context, 16, md5, NULL);
 	purple_cipher_context_destroy(context);
-
-	fclose(fp);
 }
 
 static void _qq_get_file_header(guint8 *buf, guint8 **cursor, gint buflen, qq_file_header *fh)
--- a/libpurple/protocols/qq/group_im.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/qq/group_im.c	Thu Jan 17 08:12:37 2008 +0000
@@ -135,7 +135,7 @@
 
 	purple_request_action(gc, _("QQ Qun Operation"),
 			    msg, reason,
-			    2,
+			    PURPLE_DEFAULT_ACTION_NONE,
 				purple_connection_get_account(gc), nombre, NULL,
 				g, 3,
 			    _("Approve"),
--- a/libpurple/protocols/qq/group_opt.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/qq/group_opt.c	Thu Jan 17 08:12:37 2008 +0000
@@ -96,7 +96,8 @@
 	g_return_if_fail(g != NULL && g->gc != NULL && g->member > 0);
 
 	qq_send_packet_get_info(g->gc, g->member, TRUE);	/* we want to see window */
-	purple_request_action(g->gc, NULL, _("Do you want to approve the request?"), "", 2,
+	purple_request_action(g->gc, NULL, _("Do you want to approve the request?"), "",
+					PURPLE_DEFAULT_ACTION_NONE,
 					purple_connection_get_account(g->gc), NULL, NULL,
 					g, 2,
 					_("Reject"), G_CALLBACK(qq_group_reject_application_with_struct),
--- a/libpurple/protocols/qq/sys_msg.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/qq/sys_msg.c	Thu Jan 17 08:12:37 2008 +0000
@@ -84,7 +84,8 @@
 
 	nombre = uid_to_purple_name(uid);
 	purple_request_action
-	    (gc, NULL, _("Do you want to approve the request?"), "", 2,
+	    (gc, NULL, _("Do you want to approve the request?"), "",
+		PURPLE_DEFAULT_ACTION_NONE,
 		 purple_connection_get_account(gc), nombre, NULL,
 		 g, 2,
 	     _("Reject"), G_CALLBACK(qq_reject_add_request_with_gc_and_uid),
@@ -107,7 +108,8 @@
 	qq_send_packet_get_info(gc, uid, TRUE);	/* we want to see window */
 	nombre = uid_to_purple_name(uid);
 	purple_request_action
-	    (gc, NULL, _("Do you want to add this buddy?"), "", 2,
+	    (gc, NULL, _("Do you want to add this buddy?"), "",
+		PURPLE_DEFAULT_ACTION_NONE,
 		 purple_connection_get_account(gc), nombre, NULL,
 		 g, 2,
 	     _("Cancel"), NULL,
@@ -166,7 +168,8 @@
 		message = g_strdup_printf(_("You have been added by %s"), from);
 		_qq_sys_msg_log_write(gc, message, from);
 		purple_request_action(gc, NULL, message,
-				    _("Would you like to add him?"), 2,
+				    _("Would you like to add him?"),
+					PURPLE_DEFAULT_ACTION_NONE,
 					purple_connection_get_account(gc), name, NULL,
 					g, 3,
 				    _("Cancel"), NULL,
@@ -240,7 +243,7 @@
 	_qq_sys_msg_log_write(gc, message, from);
 
 	purple_request_action
-	    (gc, NULL, message, reason, 2,
+	    (gc, NULL, message, reason, PURPLE_DEFAULT_ACTION_NONE,
 		purple_connection_get_account(gc), name, NULL,
 		 g, 3,
 	     _("Reject"),
@@ -260,7 +263,7 @@
 		g2->uid = strtol(from, NULL, 10);
 		message = g_strdup_printf(_("%s is not in your buddy list"), from);
 		purple_request_action(gc, NULL, message,
-				    _("Would you like to add him?"), 2,
+				    _("Would you like to add him?"), PURPLE_DEFAULT_ACTION_NONE,
 					purple_connection_get_account(gc), name, NULL,
 					g2, 3,
 					_("Cancel"), NULL,
--- a/libpurple/protocols/sametime/sametime.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/sametime/sametime.c	Thu Jan 17 08:12:37 2008 +0000
@@ -2286,6 +2286,7 @@
 
   PurpleXfer *xfer;
   FILE *fp;
+  size_t wc;
 
   xfer = mwFileTransfer_getClientData(ft);
   g_return_if_fail(xfer != NULL);
@@ -2294,7 +2295,12 @@
   g_return_if_fail(fp != NULL);
 
   /* we must collect and save our precious data */
-  fwrite(data->data, 1, data->len, fp);
+  wc = fwrite(data->data, 1, data->len, fp);
+  if (wc != data->len) {
+    DEBUG_ERROR("failed to write data\n");
+    purple_xfer_cancel_local(xfer);
+    return;
+  }
 
   /* update the progress */
   xfer->bytes_sent += data->len;
--- a/libpurple/protocols/yahoo/util.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/yahoo/util.c	Thu Jan 17 08:12:37 2008 +0000
@@ -164,6 +164,25 @@
 		return g_strdup("");
 }
 
+char *yahoo_convert_to_numeric(const char *str)
+{
+	GString *gstr = NULL;
+	char *retstr;
+	const char *p;
+
+	gstr = g_string_sized_new(strlen(str) * 6 + 1);
+
+	for (p = str; *p; p++) {
+		g_string_append_printf(gstr, "&#%u;", *p);
+	}
+
+	retstr = gstr->str;
+
+	g_string_free(gstr, FALSE);
+
+	return retstr;
+}
+
 /*
  * I found these on some website but i don't know that they actually
  * work (or are supposed to work). I didn't implement them yet.
--- a/libpurple/protocols/yahoo/yahoo.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo.c	Thu Jan 17 08:12:37 2008 +0000
@@ -4165,17 +4165,13 @@
 
 GList *yahoo_attention_types(PurpleAccount *account)
 {
-	PurpleAttentionType *attn;
 	static GList *list = NULL;
 
 	if (!list) {
 		/* Yahoo only supports one attention command: the 'buzz'. */
 		/* This is index number YAHOO_BUZZ. */
-		attn = g_new0(PurpleAttentionType, 1);
-		attn->name = _("Buzz");
-		attn->incoming_description = _("%s has buzzed you!");
-		attn->outgoing_description = _("Buzzing %s...");
-		list = g_list_append(list, attn);
+		list = g_list_append(list, purple_attention_type_new("Buzz", _("Buzz"),
+				_("%s has buzzed you!"), _("Buzzing %s...")));
 	}
 
 	return list;
--- a/libpurple/protocols/yahoo/yahoo.h	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo.h	Thu Jan 17 08:12:37 2008 +0000
@@ -218,6 +218,8 @@
  */
 char *yahoo_string_decode(PurpleConnection *gc, const char *str, gboolean utf8);
 
+char *yahoo_convert_to_numeric(const char *str);
+
 /* previously-static functions, now needed for yahoo_profile.c */
 void yahoo_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full);
 
--- a/libpurple/protocols/yahoo/yahoo_aliases.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_aliases.c	Thu Jan 17 08:12:37 2008 +0000
@@ -37,6 +37,8 @@
 /* I hate hardcoding this stuff, but Yahoo never sends us anything to use.  Someone in the know may be able to tweak this URL */
 #define YAHOO_ALIAS_FETCH_URL "http://address.yahoo.com/yab/us?v=XM&prog=ymsgr&.intl=us&diffs=1&t=0&tags=short&rt=0&prog-ver=8.1.0.249&useutf8=1&legenc=codepage-1252"
 #define YAHOO_ALIAS_UPDATE_URL "http://address.yahoo.com/yab/us?v=XM&prog=ymsgr&.intl=us&sync=1&tags=short&noclear=1&useutf8=1&legenc=codepage-1252"
+#define YAHOOJP_ALIAS_FETCH_URL "http://address.yahoo.co.jp/yab/jp?v=XM&prog=ymsgr&.intl=jp&diffs=1&t=0&tags=short&rt=0&prog-ver=7.0.0.7"
+#define YAHOOJP_ALIAS_UPDATE_URL "http://address.yahoo.co.jp/yab/jp?v=XM&prog=ymsgr&.intl=jp&sync=1&tags=short&noclear=1"
 
 void yahoo_update_alias(PurpleConnection *gc, const char *who, const char *alias);
 
@@ -90,7 +92,10 @@
 				id = xmlnode_get_attrib(item,"id");
 
 		                /* Yahoo stores first and last names separately, lets put them together into a full name */
-				full_name = g_strstrip(g_strdup_printf("%s %s", (fn != NULL ? fn : "") , (ln != NULL ? ln : "")));
+				if (yd->jp)
+					full_name = g_strstrip(g_strdup_printf("%s %s", (ln != NULL ? ln : "") , (fn != NULL ? fn : "")));
+				else
+					full_name = g_strstrip(g_strdup_printf("%s %s", (fn != NULL ? fn : "") , (ln != NULL ? ln : "")));
 				nick_name = (nn != NULL ? g_strstrip(g_strdup_printf("%s", nn)) : NULL);
 
 				if (nick_name != NULL)
@@ -139,7 +144,7 @@
 {
 	struct yahoo_data *yd = gc->proto_data;
 	struct callback_data *cb;
-	const char *url = YAHOO_ALIAS_FETCH_URL;
+	const char *url;
 	char *request, *webpage, *webaddress;
 	PurpleUtilFetchUrlData *url_data;
 
@@ -148,6 +153,7 @@
 	cb->gc = gc;
 
 	/*  Build all the info to make the web request */
+	url = yd->jp ? YAHOOJP_ALIAS_FETCH_URL : YAHOO_ALIAS_FETCH_URL;
 	purple_url_parse(url, &webaddress, NULL, &webpage, NULL, NULL);
 	request = g_strdup_printf("GET /%s HTTP/1.1\r\n"
 				 "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\n"
@@ -221,14 +227,15 @@
 	struct yahoo_data *yd;
 	struct YahooUser *yu;
 	char *content, *url, *request, *webpage, *webaddress, *strtmp;
+	char *escaped_alias, *alias_jp, *converted_alias_jp;
 	int inttmp;
 	struct callback_data *cb;
 	PurpleBuddy *buddy;
 	PurpleUtilFetchUrlData *url_data;
 
-	g_return_if_fail(alias!= NULL);
-	g_return_if_fail(who!=NULL);
-	g_return_if_fail(gc!=NULL);
+	g_return_if_fail(alias != NULL);
+	g_return_if_fail(who != NULL);
+	g_return_if_fail(gc != NULL);
 
 	purple_debug_info("yahoo", "Sending '%s' as new alias for user '%s'.\n",alias, who);
 
@@ -247,12 +254,25 @@
 	cb->gc = gc;
 
 	/*  Build all the info to make the web request */
-	url = g_strdup(YAHOO_ALIAS_UPDATE_URL);
+	url = yd->jp? YAHOOJP_ALIAS_UPDATE_URL: YAHOO_ALIAS_UPDATE_URL;
 	purple_url_parse(url, &webaddress, &inttmp, &webpage, &strtmp, &strtmp);
 
-	content = g_strdup_printf("<?xml version=\"1.0\" encoding=\"utf-8\"?><ab k=\"%s\" cc=\"1\">\n"
-				  "<ct e=\"1\"  yi='%s' id='%s' nn='%s' pr='0' />\n</ab>\r\n",
-				  gc->account->username, who, yu->id, g_markup_escape_text(alias, strlen(alias)));
+	if (yd->jp) {
+		alias_jp = g_convert(alias, strlen(alias), "EUC-JP", "UTF-8", NULL, NULL, NULL);
+		converted_alias_jp = yahoo_convert_to_numeric(alias_jp);
+		content = g_strdup_printf("<ab k=\"%s\" cc=\"1\">\n"
+		                          "<ct e=\"1\"  yi='%s' id='%s' nn='%s' pr='0' />\n</ab>\r\n",
+		                          gc->account->username, who, yu->id, converted_alias_jp);
+		free(converted_alias_jp);
+		g_free(alias_jp);
+	}
+	else {
+		escaped_alias = g_markup_escape_text(alias, strlen(alias));
+		content = g_strdup_printf("<?xml version=\"1.0\" encoding=\"utf-8\"?><ab k=\"%s\" cc=\"1\">\n"
+		                          "<ct e=\"1\"  yi='%s' id='%s' nn='%s' pr='0' />\n</ab>\r\n",
+		                          gc->account->username, who, yu->id, escaped_alias);
+		g_free(escaped_alias);
+	}
 
 	request = g_strdup_printf("POST /%s HTTP/1.1\r\n"
 				  "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\n"
@@ -271,7 +291,6 @@
 	}
 
 	g_free(content);
-	g_free(url);
 	g_free(request);
 }
 
--- a/libpurple/protocols/zephyr/ZSendList.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/zephyr/ZSendList.c	Thu Jan 17 08:12:37 2008 +0000
@@ -24,7 +24,7 @@
     char *list[];
     int nitems;
     Z_AuthProc cert_routine;
-    Code_t (*send_routine)(void);
+    Code_t (*send_routine)();
 {
     Code_t retval;
     ZNotice_t newnotice;
--- a/libpurple/protocols/zephyr/ZSendNot.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/zephyr/ZSendNot.c	Thu Jan 17 08:12:37 2008 +0000
@@ -20,7 +20,7 @@
 Code_t ZSrvSendNotice(notice, cert_routine, send_routine)
     ZNotice_t *notice;
     Z_AuthProc cert_routine;
-    Code_t (*send_routine)(void);
+    Code_t (*send_routine)();
 {    
     Code_t retval;
     ZNotice_t newnotice;
--- a/libpurple/protocols/zephyr/zephyr.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/zephyr/zephyr.c	Thu Jan 17 08:12:37 2008 +0000
@@ -156,13 +156,20 @@
 #endif
 
 static Code_t zephyr_subscribe_to(zephyr_account* zephyr, char* class, char *instance, char *recipient, char* galaxy) {
+	size_t result;
+	Code_t ret_val = -1;
 
 	if (use_tzc(zephyr)) {
 		/* ((tzcfodder . subscribe) ("class" "instance" "recipient")) */
 		gchar *zsubstr = g_strdup_printf("((tzcfodder . subscribe) (\"%s\" \"%s\" \"%s\"))\n",class,instance,recipient);
-		write(zephyr->totzc[ZEPHYR_FD_WRITE],zsubstr,strlen(zsubstr));
+		size_t len = strlen(zsubstr);
+		result = write(zephyr->totzc[ZEPHYR_FD_WRITE],zsubstr,len);
+		if (result != len) {
+			purple_debug_error("zephyr", "Unable to write a message: %s\n", g_strerror(errno));
+		} else {
+			ret_val = ZERR_NONE;
+		}
 		g_free(zsubstr);
-		return ZERR_NONE;
 	}
 	else {
 		if (use_zeph02(zephyr)) {
@@ -170,13 +177,10 @@
 			sub.zsub_class = class;
 			sub.zsub_classinst = instance;
 			sub.zsub_recipient = recipient; 
-			return ZSubscribeTo(&sub,1,0);
-		} else {
-			/* This should not happen */
-			return -1;
+			ret_val = ZSubscribeTo(&sub,1,0);
 		}
 	}
-	return -1;
+	return ret_val;
 }
 
 char *local_zephyr_normalize(zephyr_account* zephyr,const char *);
@@ -1373,7 +1377,11 @@
 					} else 
 						if (use_tzc(zephyr)) {
 							gchar *zlocstr = g_strdup_printf("((tzcfodder . zlocate) \"%s\")\n",chk);
-							write(zephyr->totzc[ZEPHYR_FD_WRITE],zlocstr,strlen(zlocstr));
+							size_t len = strlen(zlocstr);
+							size_t result = write(zephyr->totzc[ZEPHYR_FD_WRITE],zlocstr,len);
+							if (result != len) {
+								purple_debug_error("zephyr", "Unable to write a message: %s\n", g_strerror(errno));
+							}
 							g_free(zlocstr);
 						}
 				}
@@ -2193,6 +2201,8 @@
 	html_buf2 = purple_unescape_html(html_buf);
 
 	if(use_tzc(zephyr)) {
+		size_t len;
+		size_t result;
 		char* zsendstr;
 		/* CMU cclub tzc doesn't grok opcodes for now  */
 		char* tzc_sig = zephyr_tzc_escape_msg(sig);
@@ -2200,7 +2210,14 @@
 		zsendstr = g_strdup_printf("((tzcfodder . send) (class . \"%s\") (auth . t) (recipients (\"%s\" . \"%s\")) (message . (\"%s\" \"%s\"))	) \n",
 					   zclass, instance, recipient, tzc_sig, tzc_body);
 		/*		fprintf(stderr,"zsendstr = %s\n",zsendstr); */
-		write(zephyr->totzc[ZEPHYR_FD_WRITE],zsendstr,strlen(zsendstr));
+		len = strlen(zsendstr);
+		result = write(zephyr->totzc[ZEPHYR_FD_WRITE], zsendstr, len);
+		if (result != len) {
+			g_free(zsendstr);
+			g_free(html_buf2);
+			g_free(html_buf);
+			return errno;
+		}
 		g_free(zsendstr);
 	} else if (use_zeph02(zephyr)) {
 		ZNotice_t notice;
@@ -2221,6 +2238,9 @@
 		purple_debug_info("zephyr","About to send notice\n");
 		if (! ZSendNotice(&notice, ZAUTH) == ZERR_NONE) {
 			/* XXX handle errors here */
+			g_free(buf);
+			g_free(html_buf2);
+			g_free(html_buf);
 			return 0;
 		}
 		purple_debug_info("zephyr","notice sent\n");
@@ -2257,7 +2277,7 @@
 	ZAsyncLocateData_t ald;
 	zephyr_account *zephyr = gc->proto_data;
 	gchar* normalized_who = local_zephyr_normalize(zephyr,who);
-	
+
 	if (use_zeph02(zephyr)) {
 		if (ZRequestLocations(normalized_who, &ald, UNACKED, ZAUTH) == ZERR_NONE) {
 			zephyr->pending_zloc_names = g_list_append(zephyr->pending_zloc_names,
@@ -2266,14 +2286,22 @@
 			/* XXX deal with errors somehow */
 		}
 	} else if (use_tzc(zephyr)) {
+		size_t len;
+		size_t result;
 		char* zlocstr = g_strdup_printf("((tzcfodder . zlocate) \"%s\")\n",normalized_who);
 		zephyr->pending_zloc_names = g_list_append(zephyr->pending_zloc_names, g_strdup(normalized_who));
-		write(zephyr->totzc[ZEPHYR_FD_WRITE],zlocstr,strlen(zlocstr));
+		len = strlen(zlocstr);
+		result = write(zephyr->totzc[ZEPHYR_FD_WRITE],zlocstr,len);
+		if (result != len) {
+			purple_debug_error("zephyr", "Unable to write a message: %s\n", g_strerror(errno));
+		}
 		g_free(zlocstr);
 	}
 }
 
 static void zephyr_set_status(PurpleAccount *account, PurpleStatus *status) {
+	size_t len;
+	size_t result;
 	zephyr_account *zephyr = purple_account_get_connection(account)->proto_data;
 	PurpleStatusPrimitive primitive = purple_status_type_get_primitive(purple_status_get_type(status));
 
@@ -2291,7 +2319,11 @@
 		}
 		else {
 			char *zexpstr = g_strdup_printf("((tzcfodder . set-location) (hostname . \"%s\") (exposure . \"%s\"))\n",zephyr->ourhost,zephyr->exposure);
-			write(zephyr->totzc[ZEPHYR_FD_WRITE],zexpstr,strlen(zexpstr));
+			len = strlen(zexpstr);
+			result = write(zephyr->totzc[ZEPHYR_FD_WRITE],zexpstr,len);
+			if (result != len) {
+				purple_debug_error("zephyr", "Unable to write message: %s\n", g_strerror(errno));
+			}
 			g_free(zexpstr);
 		}
 	} 
@@ -2301,7 +2333,11 @@
 			ZSetLocation(EXPOSE_OPSTAFF);
 		} else {
 			char *zexpstr = g_strdup_printf("((tzcfodder . set-location) (hostname . \"%s\") (exposure . \"%s\"))\n",zephyr->ourhost,EXPOSE_OPSTAFF);
-			write(zephyr->totzc[ZEPHYR_FD_WRITE],zexpstr,strlen(zexpstr));
+			len = strlen(zexpstr);
+			result = write(zephyr->totzc[ZEPHYR_FD_WRITE],zexpstr,len);
+			if (result != len) {
+				purple_debug_error("zephyr", "Unable to write message: %s\n", g_strerror(errno));
+			}
 			g_free(zexpstr);
 		}
 	}
--- a/libpurple/protocols/zephyr/zephyr.h	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/protocols/zephyr/zephyr.h	Thu Jan 17 08:12:37 2008 +0000
@@ -163,9 +163,9 @@
 Code_t ZReadAscii16 ZP((char *, int, unsigned short *));
 Code_t ZSendPacket ZP((char*, int, int));
 Code_t ZSendList ZP((ZNotice_t*, char *[], int, Z_AuthProc));
-Code_t ZSrvSendList ZP((ZNotice_t*, char*[], int, Z_AuthProc, Code_t (*)(void)));
+Code_t ZSrvSendList ZP((ZNotice_t*, char*[], int, Z_AuthProc, Code_t (*)()));
 Code_t ZSendNotice ZP((ZNotice_t *, Z_AuthProc));
-Code_t ZSrvSendNotice ZP((ZNotice_t*, Z_AuthProc, Code_t (*)(void)));
+Code_t ZSrvSendNotice ZP((ZNotice_t*, Z_AuthProc, Code_t (*)()));
 Code_t ZFormatNotice ZP((ZNotice_t*, char**, int*, Z_AuthProc));
 Code_t ZFormatSmallNotice ZP((ZNotice_t*, ZPacket_t, int*, Z_AuthProc));
 Code_t ZFormatRawNoticeList ZP((ZNotice_t *notice, char *list[], int nitems,
--- a/libpurple/prpl.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/prpl.c	Thu Jan 17 08:12:37 2008 +0000
@@ -29,6 +29,107 @@
 #include "util.h"
 
 /**************************************************************************/
+/** @name Attention Type API                                              */
+/**************************************************************************/
+PurpleAttentionType *
+purple_attention_type_new(const char *ulname, const char *name,
+						const char *inc_desc, const char *out_desc)
+{
+	PurpleAttentionType *attn = g_new0(PurpleAttentionType, 1);
+
+	purple_attention_type_set_name(attn, name);
+	purple_attention_type_set_incoming_desc(attn, inc_desc);
+	purple_attention_type_set_outgoing_desc(attn, out_desc);
+	purple_attention_type_set_unlocalized_name(attn, ulname);
+
+	return attn;
+}
+
+
+void
+purple_attention_type_set_name(PurpleAttentionType *type, const char *name)
+{
+	g_return_if_fail(type != NULL);
+
+	type->name = name;
+}
+
+void
+purple_attention_type_set_incoming_desc(PurpleAttentionType *type, const char *desc)
+{
+	g_return_if_fail(type != NULL);
+
+	type->incoming_description = desc;
+}
+
+void
+purple_attention_type_set_outgoing_desc(PurpleAttentionType *type, const char *desc)
+{
+	g_return_if_fail(type != NULL);
+
+	type->outgoing_description = desc;
+}
+
+void
+purple_attention_type_set_icon_name(PurpleAttentionType *type, const char *name)
+{
+	g_return_if_fail(type != NULL);
+	
+	type->icon_name = name;
+}
+
+void
+purple_attention_type_set_unlocalized_name(PurpleAttentionType *type, const char *ulname)
+{
+	g_return_if_fail(type != NULL);
+
+	type->unlocalized_name = ulname;
+}
+
+const char *
+purple_attention_type_get_name(const PurpleAttentionType *type)
+{
+	g_return_val_if_fail(type != NULL, NULL);
+
+	return type->name;
+}
+
+const char *
+purple_attention_type_get_incoming_desc(const PurpleAttentionType *type)
+{
+	g_return_val_if_fail(type != NULL, NULL);
+
+	return type->incoming_description;
+}
+
+const char *
+purple_attention_type_get_outgoing_desc(const PurpleAttentionType *type)
+{
+	g_return_val_if_fail(type != NULL, NULL);
+
+	return type->outgoing_description;
+}
+
+const char *
+purple_attention_type_get_icon_name(const PurpleAttentionType *type)
+{
+	g_return_val_if_fail(type != NULL, NULL);
+
+	if(type->icon_name == NULL || *(type->icon_name) == '\0')
+		return NULL;
+
+	return type->icon_name;
+}
+
+const char *
+purple_attention_type_get_unlocalized_name(const PurpleAttentionType *type)
+{
+	g_return_val_if_fail(type != NULL, NULL);
+
+	return type->unlocalized_name;
+}
+
+/**************************************************************************/
 /** @name Protocol Plugin API  */
 /**************************************************************************/
 void
--- a/libpurple/prpl.h	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/prpl.h	Thu Jan 17 08:12:37 2008 +0000
@@ -99,9 +99,9 @@
 	const char *incoming_description;  /**< Shown when sent */
 	const char *outgoing_description;  /**< Shown when receied */
 	const char *icon_name;             /**< Icon to display (optional) */
+	const char *unlocalized_name;      /**< Unlocalized name for UIs needing it */
 
 	/* Reserved fields for future purposes */
-	gpointer _reserved1;
 	gpointer _reserved2;
 	gpointer _reserved3;
 	gpointer _reserved4;
@@ -412,6 +412,127 @@
 #endif
 
 /**************************************************************************/
+/** @name Attention Type API                                              */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Creates a new #PurpleAttentionType object and sets its mandatory parameters.
+ *
+ * @param ulname A non-localized string that can be used by UIs in need of such
+ *               non-localized strings.  This should be the same as @a name,
+ *               without localization.
+ * @param name A localized string that the UI may display for the event. This
+ *             should be the same string as @a ulname, with localization.
+ * @param inc_desc A localized description shown when the event is received.
+ * @param out_desc A localized description shown when the event is sent.
+ * @return A pointer to the new object.
+ * @since 2.4.0
+ */
+PurpleAttentionType *purple_attention_type_new(const char *ulname, const char *name,
+								const char *inc_desc, const char *out_desc);
+
+/**
+ * Sets the displayed name of the attention-demanding event.
+ *
+ * @param type The attention type.
+ * @param name The localized name that will be displayed by UIs. This should be
+ *             the same string given as the unlocalized name, but with
+ *             localization.
+ * @since 2.4.0
+ */
+void purple_attention_type_set_name(PurpleAttentionType *type, const char *name);
+
+/**
+ * Sets the description of the attention-demanding event shown in  conversations
+ * when the event is received.
+ *
+ * @param type The attention type.
+ * @param desc The localized description for incoming events.
+ * @since 2.4.0
+ */
+void purple_attention_type_set_incoming_desc(PurpleAttentionType *type, const char *desc);
+
+/**
+ * Sets the description of the attention-demanding event shown in conversations
+ * when the event is sent.
+ *
+ * @param type The attention type.
+ * @param desc The localized description for outgoing events.
+ * @since 2.4.0
+ */
+void purple_attention_type_set_outgoing_desc(PurpleAttentionType *type, const char *desc);
+
+/**
+ * Sets the name of the icon to display for the attention event; this is optional.
+ *
+ * @param type The attention type.
+ * @param name The icon's name.
+ * @note Icons are optional for attention events.
+ * @since 2.4.0
+ */
+void purple_attention_type_set_icon_name(PurpleAttentionType *type, const char *name);
+
+/**
+ * Sets the unlocalized name of the attention event; some UIs may need this,
+ * thus it is required.
+ *
+ * @param type The attention type.
+ * @param ulname The unlocalized name.  This should be the same string given as
+ *               the localized name, but without localization.
+ * @since 2.4.0
+ */
+void purple_attention_type_set_unlocalized_name(PurpleAttentionType *type, const char *ulname);
+
+/**
+ * Get the attention type's name as displayed by the UI.
+ *
+ * @param type The attention type.
+ * @return The name.
+ * @since 2.4.0
+ */
+const char *purple_attention_type_get_name(const PurpleAttentionType *type);
+
+/**
+ * Get the attention type's description shown when the event is received.
+ *
+ * @param type The attention type.
+ * @return The description.
+ * @since 2.4.0
+ */
+const char *purple_attention_type_get_incoming_desc(const PurpleAttentionType *type);
+
+/**
+ * Get the attention type's description shown when the event is sent.
+ *
+ * @param type The attention type.
+ * @return The description.
+ * @since 2.4.0
+ */
+const char *purple_attention_type_get_outgoing_desc(const PurpleAttentionType *type);
+
+/**
+ * Get the attention type's icon name.
+ *
+ * @param type The attention type.
+ * @return The icon name or @c NULL if unset/empty.
+ * @note Icons are optional for attention events.
+ * @since 2.4.0
+ */
+const char *purple_attention_type_get_icon_name(const PurpleAttentionType *type);
+
+/**
+ * Get the attention type's unlocalized name; this is useful for some UIs.
+ *
+ * @param type The attention type
+ * @return The unlocalized name.
+ * @since 2.4.0
+ */
+const char *purple_attention_type_get_unlocalized_name(const PurpleAttentionType *type);
+
+/*@}*/
+
+/**************************************************************************/
 /** @name Protocol Plugin API                                             */
 /**************************************************************************/
 /*@{*/
--- a/libpurple/request.h	Thu Jan 17 08:01:02 2008 +0000
+++ b/libpurple/request.h	Thu Jan 17 08:12:37 2008 +0000
@@ -1318,6 +1318,8 @@
  * @param secondary      Secondary information, or @c NULL if there is none.
  * @param default_action The default action, zero-indexed; if the third action
  *                       supplied should be the default, supply <tt>2</tt>.
+ *                       The should be the action that users are most likely
+ *                       to select.
  * @param account        The #PurpleAccount associated with this request, or @c
  *                       NULL if none is.
  * @param who            The username of the buddy associated with this request,
@@ -1356,6 +1358,8 @@
  * @param secondary      Secondary information, or @c NULL if there is none.
  * @param default_action The default action, zero-indexed; if the third action
  *                       supplied should be the default, supply <tt>2</tt>.
+ *                       The should be the action that users are most likely
+ *                       to select.
  * @param account        The #PurpleAccount associated with this request, or @c
  *                       NULL if none is.
  * @param who            The username of the buddy associated with this request,
--- a/pidgin/gtkblist.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/pidgin/gtkblist.c	Thu Jan 17 08:12:37 2008 +0000
@@ -4143,12 +4143,11 @@
 static void pidgin_blist_new_list(PurpleBuddyList *blist)
 {
 	PidginBuddyList *gtkblist;
-	PidginBuddyListPrivate *priv;
 
 	gtkblist = g_new0(PidginBuddyList, 1);
 	gtkblist->connection_errors = g_hash_table_new_full(g_direct_hash,
 												g_direct_equal, NULL, g_free);
-	gtkblist->priv = priv = g_new0(PidginBuddyListPrivate, 1);
+	gtkblist->priv = g_new0(PidginBuddyListPrivate, 1);
 
 	blist->ui_data = gtkblist;
 }
--- a/pidgin/gtkconv.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/pidgin/gtkconv.c	Thu Jan 17 08:12:37 2008 +0000
@@ -441,6 +441,13 @@
 
 		cmdline = cmd + strlen(prefix);
 
+		if (strcmp(cmdline, "xyzzy") == 0) {
+			purple_conversation_write(conv, "", "Nothing happens",
+					PURPLE_MESSAGE_NO_LOG, time(NULL));
+			g_free(cmd);
+			return TRUE;
+		}
+
 		gtk_text_iter_forward_chars(&start, g_utf8_strlen(prefix, -1));
 		gtk_text_buffer_get_end_iter(GTK_IMHTML(gtkconv->entry)->text_buffer, &end);
 		markup = gtk_imhtml_get_markup_range(GTK_IMHTML(gtkconv->entry), &start, &end);
--- a/pidgin/gtklog.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/pidgin/gtklog.c	Thu Jan 17 08:12:37 2008 +0000
@@ -139,7 +139,7 @@
 	{
 		/* Searching for the same term acts as "Find Next" */
 		gtk_imhtml_search_find(GTK_IMHTML(lv->imhtml), lv->search);
-		return;	
+		return;
 	}
 
 	pidgin_set_cursor(lv->window, GDK_WATCH);
@@ -321,7 +321,7 @@
 	data2[0] = lv->treestore;
 	data2[1] = data[3]; /* iter */
 	data2[2] = log;
-	purple_request_action(lv, NULL, "Delete Log?", tmp, 0, 
+	purple_request_action(lv, NULL, "Delete Log?", tmp, 0,
 						NULL, NULL, NULL,
 						data2, 2,
 						_("Delete"), delete_log_cb,
@@ -556,8 +556,13 @@
 				if (!purple_prefs_get_bool("/purple/logging/log_chats"))
 					log_preferences = _("Chats will only be logged if the \"Log all chats\" preference is enabled.");
 			}
+			g_free(ht->screenname);
+			g_free(ht);
 		}
 
+		if(icon != NULL)
+			gtk_widget_destroy(icon);
+
 		purple_notify_info(NULL, title, _("No logs were found"), log_preferences);
 		return NULL;
 	}
@@ -731,18 +736,19 @@
 }
 
 void pidgin_log_show_contact(PurpleContact *contact) {
-	struct log_viewer_hash_t *ht = g_new0(struct log_viewer_hash_t, 1);
+	struct log_viewer_hash_t *ht;
 	PurpleBlistNode *child;
 	PidginLogViewer *lv = NULL;
 	GList *logs = NULL;
 	GdkPixbuf *pixbuf;
-	GtkWidget *image = gtk_image_new();
+	GtkWidget *image;
 	const char *name = NULL;
 	char *title;
 	int total_log_size = 0;
 
 	g_return_if_fail(contact != NULL);
 
+	ht = g_new0(struct log_viewer_hash_t, 1);
 	ht->type = PURPLE_LOG_IM;
 	ht->contact = contact;
 
@@ -764,9 +770,16 @@
 	}
 	logs = g_list_sort(logs, purple_log_compare);
 
+	image = gtk_image_new();
 	pixbuf = gtk_widget_render_icon(image, PIDGIN_STOCK_STATUS_PERSON,
 					gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_SMALL), "GtkWindow");
-	gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
+	if (pixbuf) {
+		gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
+		g_object_unref(pixbuf);
+	} else {
+		gtk_widget_destroy(image);
+		image = NULL;
+	}
 
 	if (contact->alias != NULL)
 		name = contact->alias;
--- a/pidgin/gtkprefs.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/pidgin/gtkprefs.c	Thu Jan 17 08:12:37 2008 +0000
@@ -478,12 +478,20 @@
 {
 	FILE *f;
 	gchar *path;
+	size_t wc;
 
 	if ((error_message != NULL) || (len == 0))
 		return;
 
 	f = purple_mkstemp(&path, TRUE);
-	fwrite(themedata, len, 1, f);
+	wc = fwrite(themedata, len, 1, f);
+	if (wc != 1) {
+		purple_debug_warning("theme_got_url", "Unable to write theme data.\n");
+		fclose(f);
+		g_unlink(path);
+		g_free(path);
+		return;
+	}
 	fclose(f);
 
 	theme_install_theme(path, user_data);
@@ -1718,9 +1726,6 @@
 	int j;
 	const char *file;
 	char *pref;
-#if !defined _WIN32 || defined USE_GSTREAMER
-	GtkWidget *label;
-#endif
 #ifndef _WIN32
 	GtkWidget *dd;
 	GtkWidget *entry;
--- a/pidgin/gtkrequest.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/pidgin/gtkrequest.c	Thu Jan 17 08:12:37 2008 +0000
@@ -663,7 +663,11 @@
 		gtk_widget_grab_focus(img);
 		gtk_widget_grab_default(img);
 	} else
-		gtk_dialog_set_default_response(GTK_DIALOG(dialog), default_action);
+		/*
+		 * Need to invert the default_action number because the
+		 * buttons are added to the dialog in reverse order.
+		 */
+		gtk_dialog_set_default_response(GTK_DIALOG(dialog), action_count - 1 - default_action);
 
 	/* Show everything. */
 	pidgin_auto_parent_window(dialog);
--- a/pidgin/gtkstatusbox.c	Thu Jan 17 08:01:02 2008 +0000
+++ b/pidgin/gtkstatusbox.c	Thu Jan 17 08:12:37 2008 +0000
@@ -320,12 +320,20 @@
 {
 	FILE *f;
 	gchar *path;
+	size_t wc;
 
 	if ((error_message != NULL) || (len == 0))
 		return;
 
 	f = purple_mkstemp(&path, TRUE);
-	fwrite(themedata, len, 1, f);
+	wc = fwrite(themedata, len, 1, f);
+	if (wc != 1) {
+		purple_debug_warning("theme_got_url", "Unable to write theme data.\n");
+		fclose(f);
+		g_unlink(path);
+		g_free(path);
+		return;
+	}
 	fclose(f);
 
 	icon_choose_cb(path, user_data);
--- a/pidgin/win32/nsis/pidgin-installer.nsi	Thu Jan 17 08:01:02 2008 +0000
+++ b/pidgin/win32/nsis/pidgin-installer.nsi	Thu Jan 17 08:12:37 2008 +0000
@@ -1167,6 +1167,10 @@
     MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION $(PIDGIN_IS_RUNNING) /SD IDCANCEL IDRETRY retry_runcheck
     Abort
 
+  ; Close the Handle (If we don't do this, the uninstaller called from within will fail)
+  ; This is not optimal because there is a (small) window of time when a new process could start
+  System::Call 'kernel32::CloseHandle(i $R1) i .R1'
+
   Pop $R1
   Pop $R0
 FunctionEnd