changeset 25218:bdd00a7113d7

propagate from branch 'im.pidgin.pidgin' (head f3891f3348abfe90fbe60a054833c12075aa8df4) to branch 'im.pidgin.cpw.malu.xmpp.attention' (head d235bb23dbe13535f85e071d6c4f42e07ac6e0ce)
author Marcus Lundblad <ml@update.uu.se>
date Sun, 16 Nov 2008 15:39:46 +0000
parents 2f01775c81d5 (current diff) fae699fece1f (diff)
children 0a5540936908
files libpurple/protocols/jabber/message.c
diffstat 32 files changed, 216 insertions(+), 234 deletions(-) [+]
line wrap: on
line diff
--- a/finch/libgnt/gntentry.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/finch/libgnt/gntentry.c	Sun Nov 16 15:39:46 2008 +0000
@@ -903,6 +903,7 @@
 				GNT_KEY_CTRL_K, NULL);
 	gnt_bindable_class_register_action(bindable, "delete-prev-word", del_prev_word,
 				GNT_KEY_CTRL_W, NULL);
+	gnt_bindable_register_binding(bindable, "delete-prev-word", "\033", s, NULL);
 	gnt_bindable_class_register_action(bindable, "cursor-prev-word", move_back_word,
 				"\033" "b", NULL);
 	gnt_bindable_class_register_action(bindable, "cursor-prev", move_back,
--- a/libpurple/blist.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/blist.c	Sun Nov 16 15:39:46 2008 +0000
@@ -2214,6 +2214,7 @@
 	struct proto_chat_entry *pce;
 	PurpleBlistNode *node, *group;
 	GList *parts;
+	char *normname;
 
 	g_return_val_if_fail(purplebuddylist != NULL, NULL);
 	g_return_val_if_fail((name != NULL) && (*name != '\0'), NULL);
@@ -2227,6 +2228,7 @@
 	if (prpl_info->find_blist_chat != NULL)
 		return prpl_info->find_blist_chat(account, name);
 
+	normname = g_strdup(purple_normalize(account, name));
 	for (group = purplebuddylist->root; group != NULL; group = group->next) {
 		for (node = group->child; node != NULL; node = node->next) {
 			if (PURPLE_BLIST_NODE_IS_CHAT(node)) {
@@ -2246,14 +2248,15 @@
 				g_list_free(parts);
 
 				if (chat->account == account && chat_name != NULL &&
-					name != NULL && !strcmp(chat_name, name)) {
-
+					normname != NULL && !strcmp(purple_normalize(account, chat_name), normname)) {
+					g_free(normname);
 					return chat;
 				}
 			}
 		}
 	}
 
+	g_free(normname);
 	return NULL;
 }
 
--- a/libpurple/dbus-analyze-functions.py	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/dbus-analyze-functions.py	Sun Nov 16 15:39:46 2008 +0000
@@ -372,13 +372,13 @@
 
     def inputsimple(self, type, name, us):
         if us:
+            self.cdecls.append("\tdbus_uint32_t %s;" % name)
+            self.cparams.append(("UINT32", name))
+            self.addintype("u", name)
+        else:
             self.cdecls.append("\tdbus_int32_t %s;" % name)
             self.cparams.append(("INT32", name))
             self.addintype("i", name)
-        else:
-            self.cdecls.append("\tdbus_uint32_t %s;" % name)
-            self.cparams.append(("UINT32", name))
-            self.addintype("u", name)
 
     def inputstring(self, type, name, us):
         if us:
--- a/libpurple/plugins/log_reader.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/plugins/log_reader.c	Sun Nov 16 15:39:46 2008 +0000
@@ -1971,7 +1971,7 @@
 	c = contents;
 	line = contents;
 
-	while (*c) {
+	while (c && *c) {
 		gboolean is_in_message = FALSE;
 
 		if (purple_str_has_prefix(line, QIP_LOG_IN_MESSAGE_ESC) ||
--- a/libpurple/protocols/jabber/message.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/jabber/message.c	Sun Nov 16 15:39:46 2008 +0000
@@ -612,7 +612,7 @@
 
 						if (jid) {
 							chat = jabber_chat_find(js, jid->node, jid->domain);
-							conv = chat->conv;
+							if (chat) conv = chat->conv;
 						}
 
 						jabber_id_free(jid);
@@ -644,7 +644,7 @@
 				/* note: if there were no smileys in the incoming message, or
 				  	if receiving custom smileys is turned off, smiley_refs will
 					be NULL */
-				for (; smiley_refs ; smiley_refs = g_list_delete_link(smiley_refs, smiley_refs)) {
+				for (; conv && smiley_refs ; smiley_refs = g_list_delete_link(smiley_refs, smiley_refs)) {
 					JabberSmileyRef *ref = (JabberSmileyRef *) smiley_refs->data;
 					const gchar *cid = ref->cid;
 					const gchar *alt = ref->alt;
--- a/libpurple/protocols/msn/httpconn.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/msn/httpconn.c	Sun Nov 16 15:39:46 2008 +0000
@@ -119,7 +119,7 @@
 		/* Need to wait for the full HTTP header to arrive */
 		return FALSE;
 
-	s += 4; /* Skip \r\n */
+	s += 4; /* Skip \r\n\r\n */
 	header = g_strndup(buf, s - buf);
 	body_start = s;
 	body_len = size - (body_start - buf);
@@ -162,7 +162,7 @@
 	body[body_len] = '\0';
 
 #ifdef MSN_DEBUG_HTTP
-	purple_debug_misc("msn", "Incoming HTTP buffer (header): {%s\r\n}\n",
+	purple_debug_misc("msn", "Incoming HTTP buffer (header): {%s}\n",
 					header);
 #endif
 
@@ -184,6 +184,7 @@
 			purple_debug_error("msn", "Malformed X-MSN-Messenger field.\n{%s}\n",
 							 buf);
 
+			g_free(header);
 			g_free(body);
 			return FALSE;
 		}
@@ -268,27 +269,26 @@
 {
 	MsnHttpConn *httpconn;
 	MsnServConn *servconn;
-	MsnSession *session;
 	char buf[MSN_BUF_LEN];
-	char *cur, *end, *old_rx_buf;
 	gssize len;
-	int cur_len;
 	char *result_msg = NULL;
 	size_t result_len = 0;
 	gboolean error = FALSE;
 
 	httpconn = data;
-	servconn = NULL;
-	session = httpconn->session;
+	servconn = httpconn->servconn;
+
+	if (servconn->type == MSN_SERVCONN_NS)
+		servconn->session->account->gc->last_received = time(NULL);
 
 	len = read(httpconn->fd, buf, sizeof(buf) - 1);
-
 	if (len < 0 && errno == EAGAIN)
 		return;
-	else if (len <= 0)
-	{
-		purple_debug_error("msn", "HTTP: Read error\n");
-		msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_READ);
+	if (len <= 0) {
+		purple_debug_error("msn", "HTTP: servconn %03d read error, "
+			"len: %" G_GSSIZE_FORMAT ", errno: %d, error: %s\n",
+			servconn->num, len, error, g_strerror(errno));
+		msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_READ);
 
 		return;
 	}
@@ -304,19 +304,15 @@
 	{
 		/* Either we must wait for more input, or something went wrong */
 		if (error)
-			msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_READ);
+			msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_READ);
 
 		return;
 	}
 
-	httpconn->servconn->processing = FALSE;
-
-	servconn = httpconn->servconn;
-
 	if (error)
 	{
 		purple_debug_error("msn", "HTTP: Special error\n");
-		msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_READ);
+		msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_READ);
 
 		return;
 	}
@@ -339,64 +335,7 @@
 	servconn->rx_buf = result_msg;
 	servconn->rx_len = result_len;
 
-	end = old_rx_buf = servconn->rx_buf;
-
-	servconn->processing = TRUE;
-
-	do
-	{
-		cur = end;
-
-		if (servconn->payload_len)
-		{
-			if (servconn->payload_len > servconn->rx_len)
-				/* The payload is still not complete. */
-				break;
-
-			cur_len = servconn->payload_len;
-			end += cur_len;
-		}
-		else
-		{
-			end = strstr(cur, "\r\n");
-
-			if (end == NULL)
-				/* The command is still not complete. */
-				break;
-
-			*end = '\0';
-			end += 2;
-			cur_len = end - cur;
-		}
-
-		servconn->rx_len -= cur_len;
-
-		if (servconn->payload_len)
-		{
-			msn_cmdproc_process_payload(servconn->cmdproc, cur, cur_len);
-			servconn->payload_len = 0;
-		}
-		else
-		{
-			msn_cmdproc_process_cmd_text(servconn->cmdproc, cur);
-			servconn->payload_len = servconn->cmdproc->last_cmd->payload_len;
-		}
-	} while (servconn->connected && servconn->rx_len > 0);
-
-	if (servconn->connected)
-	{
-		if (servconn->rx_len > 0)
-			servconn->rx_buf = g_memdup(cur, servconn->rx_len);
-		else
-			servconn->rx_buf = NULL;
-	}
-
-	servconn->processing = FALSE;
-
-	if (servconn->wasted)
-		msn_servconn_destroy(servconn);
-
-	g_free(old_rx_buf);
+	msn_servconn_process_data(servconn);
 }
 
 static void
--- a/libpurple/protocols/msn/msn.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/msn/msn.c	Sun Nov 16 15:39:46 2008 +0000
@@ -121,9 +121,6 @@
 	session = gc->proto_data;
 	swboard = msn_session_get_swboard(session, username, MSN_SB_FLAG_IM);
 
-	if (swboard == NULL)
-		return FALSE;
-
 	msn_switchboard_send_msg(swboard, msg, TRUE);
 	msn_message_destroy(msg);
 
@@ -550,21 +547,17 @@
 msn_new_xfer(PurpleConnection *gc, const char *who)
 {
 	MsnSession *session;
-	MsnSlpLink *slplink;
 	PurpleXfer *xfer;
 
 	session = gc->proto_data;
 
 	xfer = purple_xfer_new(gc->account, PURPLE_XFER_SEND, who);
 
-	if (xfer)
-	{
-		slplink = msn_session_get_slplink(session, who);
-
-		xfer->data = slplink;
-
-		purple_xfer_set_init_fnc(xfer, t_msn_xfer_init);
-	}
+	g_return_val_if_fail(xfer != NULL, NULL);
+
+	xfer->data = msn_session_get_slplink(session, who);
+
+	purple_xfer_set_init_fnc(xfer, t_msn_xfer_init);
 
 	return xfer;
 }
@@ -2556,22 +2549,19 @@
 	PURPLE_PLUGIN_MAGIC,
 	PURPLE_MAJOR_VERSION,
 	PURPLE_MINOR_VERSION,
-	PURPLE_PLUGIN_PROTOCOL,                             /**< type           */
+	PURPLE_PLUGIN_PROTOCOL,                           /**< type           */
 	NULL,                                             /**< ui_requirement */
 	0,                                                /**< flags          */
 	NULL,                                             /**< dependencies   */
-	PURPLE_PRIORITY_DEFAULT,                            /**< priority       */
+	PURPLE_PRIORITY_DEFAULT,                          /**< priority       */
 
 	"prpl-msn",                                       /**< id             */
 	"MSN",                                            /**< name           */
 	DISPLAY_VERSION,                                  /**< version        */
-	                                                  /**  summary        */
-	N_("Windows Live Messenger Protocol Plugin"),
-	                                                  /**  description    */
-	N_("Windows Live Messenger Protocol Plugin"),
-	"Christian Hammond <chipx86@gnupdate.org>, "
-	"MaYuan <mayuan2006@gmail.com>",				  /**< author         */
-	PURPLE_WEBSITE,                                     /**< homepage       */
+	N_("Windows Live Messenger Protocol Plugin"),     /**< summary        */
+	N_("Windows Live Messenger Protocol Plugin"),     /**< description    */
+	NULL,                                             /**< author         */
+	PURPLE_WEBSITE,                                   /**< homepage       */
 
 	msn_load,                                         /**< load           */
 	msn_unload,                                       /**< unload         */
--- a/libpurple/protocols/msn/servconn.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/msn/servconn.c	Sun Nov 16 15:39:46 2008 +0000
@@ -174,15 +174,6 @@
 
 	servconn = data;
 	servconn->connect_data = NULL;
-	servconn->processing = FALSE;
-
-	if (servconn->wasted)
-	{
-		if (source >= 0)
-			close(source);
-		msn_servconn_destroy(servconn);
-		return;
-	}
 
 	servconn->fd = source;
 
@@ -375,24 +366,19 @@
 read_cb(gpointer data, gint source, PurpleInputCondition cond)
 {
 	MsnServConn *servconn;
-	MsnSession *session;
 	char buf[MSN_BUF_LEN];
-	char *cur, *end, *old_rx_buf;
 	gssize len;
-	int cur_len;
 
 	servconn = data;
-	session = servconn->session;
 
-	len = read(servconn->fd, buf, sizeof(buf) - 1);
 	if (servconn->type == MSN_SERVCONN_NS)
 		servconn->session->account->gc->last_received = time(NULL);
 
-	if (len < 0 && errno == EAGAIN) {
+	len = read(servconn->fd, buf, sizeof(buf) - 1);
+	if (len < 0 && errno == EAGAIN)
 		return;
-
-	} else if (len <= 0) {
-		purple_debug_error("msn", "servconn %03d read error,"
+	if (len <= 0) {
+		purple_debug_error("msn", "servconn %03d read error, "
 			"len: %" G_GSSIZE_FORMAT ", errno: %d, error: %s\n",
 			servconn->num, len, errno, g_strerror(errno));
 		msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_READ);
@@ -406,6 +392,14 @@
 	memcpy(servconn->rx_buf + servconn->rx_len, buf, len + 1);
 	servconn->rx_len += len;
 
+	msn_servconn_process_data(servconn);
+}
+
+void msn_servconn_process_data(MsnServConn *servconn)
+{
+	char *cur, *end, *old_rx_buf;
+	int cur_len;
+
 	end = old_rx_buf = servconn->rx_buf;
 
 	servconn->processing = TRUE;
--- a/libpurple/protocols/msn/servconn.h	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/msn/servconn.h	Sun Nov 16 15:39:46 2008 +0000
@@ -170,4 +170,12 @@
  */
 void msn_servconn_got_error(MsnServConn *servconn, MsnServConnError error);
 
+/**
+ * Process the data in servconn->rx_buf.  This is called after reading
+ * data from the socket.
+ *
+ * @param servconn The servconn.
+ */
+void msn_servconn_process_data(MsnServConn *servconn);
+
 #endif /* _MSN_SERVCONN_H_ */
--- a/libpurple/protocols/msn/slp.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/msn/slp.c	Sun Nov 16 15:39:46 2008 +0000
@@ -758,17 +758,20 @@
 
 	if (slplink->swboard == NULL)
 	{
-		/* We will need this in order to change its flags. */
-		slplink->swboard = (MsnSwitchBoard *)cmdproc->data;
-		/* If swboard is NULL, something has probably gone wrong earlier on
-		 * I didn't want to do this, but MSN 7 is somehow causing us to crash
-		 * here, I couldn't reproduce it to debug more, and people are
-		 * reporting bugs. Hopefully this doesn't cause more crashes. Stu.
+		/*
+		 * We will need swboard in order to change its flags.  If its
+		 * NULL, something has probably gone wrong earlier on.  I
+		 * didn't want to do this, but MSN 7 is somehow causing us
+		 * to crash here, I couldn't reproduce it to debug more,
+		 * and people are reporting bugs. Hopefully this doesn't
+		 * cause more crashes. Stu.
 		 */
-		if (slplink->swboard != NULL)
+		if (cmdproc->data == NULL)
+			g_warning("msn_p2p_msg cmdproc->data was NULL\n");
+		else {
+			slplink->swboard = (MsnSwitchBoard *)cmdproc->data;
 			slplink->swboard->slplinks = g_list_prepend(slplink->swboard->slplinks, slplink);
-		else
-			purple_debug_error("msn", "msn_p2p_msg, swboard is NULL, ouch!\n");
+		}
 	}
 
 	msn_slplink_process_msg(slplink, msg);
@@ -844,7 +847,18 @@
 		sha1 = msn_object_get_sha1(obj);
 
 		slplink = msn_session_get_slplink(session, who);
-		slplink->swboard = swboard;
+		if (slplink->swboard != swboard) {
+			if (slplink->swboard != NULL)
+				/*
+				 * Apparently we're using a different switchboard now or
+				 * something?  I don't know if this is normal, but it
+				 * definitely happens.  So make sure the old switchboard
+				 * doesn't still have a reference to us.
+				 */
+				slplink->swboard->slplinks = g_list_remove(slplink->swboard->slplinks, slplink);
+			slplink->swboard = swboard;
+			slplink->swboard->slplinks = g_list_prepend(slplink->swboard->slplinks, slplink);
+		}
 
 		/* If the conversation doesn't exist then this is a custom smiley
 		 * used in the first message in a MSN conversation: we need to create
--- a/libpurple/protocols/msn/switchboard.h	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/msn/switchboard.h	Sun Nov 16 15:39:46 2008 +0000
@@ -68,9 +68,9 @@
  */
 struct _MsnSwitchBoard
 {
-	MsnSession *session;
-	MsnServConn *servconn;
-	MsnCmdProc *cmdproc;
+	MsnSession *session;   /**< Our parent session. */
+	MsnServConn *servconn; /**< The physical connection for this switchboard. */
+	MsnCmdProc *cmdproc;   /**< Convenience variable for servconn->cmdproc. */
 	char *im_user;
 
 	MsnSBFlag flag;
--- a/libpurple/protocols/myspace/myspace.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/myspace/myspace.c	Sun Nov 16 15:39:46 2008 +0000
@@ -680,20 +680,34 @@
 msim_incoming_im(MsimSession *session, MsimMessage *msg)
 {
 	gchar *username, *msg_msim_markup, *msg_purple_markup;
+	gchar *userid;
 	time_t time_received;
+	PurpleConversation *conv;
 
 	g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
 	g_return_val_if_fail(msg != NULL, FALSE);
 
 	username = msim_msg_get_string(msg, "_username");
+	/* I know this isn't really a string... but we need it to be one for
+	 * purple_find_conversation_with_account(). */
+	userid = msim_msg_get_string(msg, "f");
 	g_return_val_if_fail(username != NULL, FALSE);
 
+	purple_debug_info("msim_incoming_im", "UserID is %s", userid);
+
 	if (msim_is_userid(username)) {
 		purple_debug_info("msim", "Ignoring message from spambot (%s) on account %s\n",
 				username, purple_account_get_username(session->account));
 		g_free(username);
 		return FALSE;
 	}
+	
+	/* See if a conversation with their UID already exists...*/
+	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, userid, session->account);
+	if (conv) {
+		/* Since the conversation exists... We need to normalize it */
+		purple_conversation_set_name(conv, username);
+	}
 
 	msg_msim_markup = msim_msg_get_string(msg, "msg");
 	g_return_val_if_fail(msg_msim_markup != NULL, FALSE);
@@ -703,6 +717,7 @@
 
 	time_received = msim_msg_get_integer(msg, "date");
 	if (!time_received) {
+		purple_debug_info("msim_incoming_im", "date in message not set.\n");
 		time_received = time(NULL);
 	}
 
--- a/libpurple/protocols/myspace/myspace.h	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/myspace/myspace.h	Sun Nov 16 15:39:46 2008 +0000
@@ -48,6 +48,7 @@
 #include "request.h"    /* For dialogs used in setting the username */
 #include "xmlnode.h"
 #include "core.h"
+#include "conversation.h" /* For late normalization */
 
 /* MySpaceIM includes */
 #include "persist.h"
--- a/libpurple/protocols/oscar/family_auth.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/oscar/family_auth.c	Sun Nov 16 15:39:46 2008 +0000
@@ -32,7 +32,7 @@
 
 #include <ctype.h>
 
-#define USE_XOR_FOR_ICQ
+/* #define USE_XOR_FOR_ICQ */
 
 #ifdef USE_XOR_FOR_ICQ
 /**
--- a/libpurple/protocols/oscar/flap_connection.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/oscar/flap_connection.c	Sun Nov 16 15:39:46 2008 +0000
@@ -228,7 +228,13 @@
 			rateclass->last.tv_usec = now.tv_usec;
 		}
 	} else {
-		purple_debug_warning("oscar", "No rate class found for family %hu subtype %hu\n", family, subtype);
+		/*
+		 * It's normal for SNACs 0x0001/0x0006 and 0x0001/0x0017 to be
+		 * sent before we receive rate info from the server, so don't
+		 * bother warning about them.
+		 */
+		if (family != 0x0001 || (subtype != 0x0006 && subtype != 0x0017))
+			purple_debug_warning("oscar", "No rate class found for family 0x%04hx subtype 0x%04hx\n", family, subtype);
 	}
 
 	if (enqueue)
--- a/libpurple/protocols/oscar/oscar.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Sun Nov 16 15:39:46 2008 +0000
@@ -1142,15 +1142,7 @@
 	conn->watcher_incoming = purple_input_add(conn->fd,
 			PURPLE_INPUT_READ, flap_connection_recv_cb, conn);
 	if (conn->cookie == NULL)
-	{
-		if (!aim_snvalid_icq(purple_account_get_username(account)))
-			/*
-			 * We don't send this when authenticating an ICQ account
-			 * because for some reason ICQ is still using the
-			 * assy/insecure authentication procedure.
-			 */
-			flap_connection_send_version(od, conn);
-	}
+		flap_connection_send_version(od, conn);
 	else
 	{
 		flap_connection_send_version_with_cookie(od, conn,
@@ -4807,7 +4799,7 @@
 		gchar *buf;
 		buf = g_strdup_printf(_("Could not add the buddy %s because the username is invalid.  Usernames must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), buddy->name);
 		if (!purple_conv_present_error(buddy->name, account, buf))
-			purple_notify_error(gc, NULL, _("Unable To Add"), buf);
+			purple_notify_error(gc, NULL, _("Unable to Add"), buf);
 		g_free(buf);
 
 		/* Remove from local list */
@@ -4926,7 +4918,7 @@
 	purple_debug_error("oscar", "ssi: SNAC error %hu\n", reason);
 
 	if (reason == 0x0005) {
-		purple_notify_error(gc, NULL, _("Unable To Retrieve Buddy List"),
+		purple_notify_error(gc, NULL, _("Unable to Retrieve Buddy List"),
 						  _("The AIM servers were temporarily unable to send your buddy list.  Your buddy list is not lost, and will probably become available in a few minutes."));
 		if (od->getblisttimer > 0)
 			purple_timeout_remove(od->getblisttimer);
@@ -5277,7 +5269,7 @@
 				gchar *buf;
 				buf = g_strdup_printf(_("Could not add the buddy %s because you have too many buddies in your buddy list.  Please remove one and try again."), (retval->name ? retval->name : _("(no name)")));
 				if ((retval->name != NULL) && !purple_conv_present_error(retval->name, purple_connection_get_account(gc), buf))
-					purple_notify_error(gc, NULL, _("Unable To Add"), buf);
+					purple_notify_error(gc, NULL, _("Unable to Add"), buf);
 				g_free(buf);
 			}
 
@@ -5292,7 +5284,7 @@
 				buf = g_strdup_printf(_("Could not add the buddy %s for an unknown reason."),
 						(retval->name ? retval->name : _("(no name)")));
 				if ((retval->name != NULL) && !purple_conv_present_error(retval->name, purple_connection_get_account(gc), buf))
-					purple_notify_error(gc, NULL, _("Unable To Add"), buf);
+					purple_notify_error(gc, NULL, _("Unable to Add"), buf);
 				g_free(buf);
 			} break;
 		}
--- a/libpurple/protocols/qq/buddy_info.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/qq/buddy_info.c	Sun Nov 16 15:39:46 2008 +0000
@@ -418,8 +418,8 @@
 			utf8_title = g_strdup(_("Modify Address"));
 			utf8_prim = g_strdup_printf("%s for %s", _("Modify Address"), segments[0]);
 		case QQ_FIELD_EXT:
-			utf8_title = g_strdup(_("Modify Extend Information"));
-			utf8_prim = g_strdup_printf("%s for %s", _("Modify Extend Information"), segments[0]);
+			utf8_title = g_strdup(_("Modify Extended Information"));
+			utf8_prim = g_strdup_printf("%s for %s", _("Modify Extended Information"), segments[0]);
 			break;
 		case QQ_FIELD_BASE:
 		default:
@@ -457,7 +457,7 @@
 	data[data_len] = '\0';
 	if (qd->uid != atoi((gchar *) data)) {	/* return should be my uid */
 		purple_debug_info("QQ", "Failed Updating info\n");
-		qq_got_attention(gc, _("Failed changing buddy information."));
+		qq_got_attention(gc, _("Could not change buddy information."));
 	}
 }
 
@@ -483,51 +483,27 @@
 
 void qq_change_icon_cb(PurpleConnection *gc, const char *filepath)
 {
-	gchar **segments;
-	const gchar *filename;
-	gint index;
+	gchar *basename;
+	size_t index;
 	gint face;
-	gchar *error;
 
 	g_return_if_fail(filepath != NULL);
 
 	purple_debug_info("QQ", "Change my icon to %s\n", filepath);
-	segments = g_strsplit_set(filepath, G_DIR_SEPARATOR_S, 0);
 
-#if 0
-	for (index = 0; segments[index] != NULL; index++) {
-		purple_debug_info("QQ", "Split to %s\n", segments[index]);
-	}
-#endif
-
-	index = g_strv_length(segments) - 1;
-	if (index < 0) {
-		g_strfreev(segments);
-		return;
-	}
-
-	filename = segments[index];
-	index = strcspn (filename, "0123456789");
-	if (index < 0 || index >= strlen(filename)) {
-		error = g_strdup_printf(_("Can not get face number in file name (%s)"), filename);
-		purple_notify_error(gc, _("QQ Buddy"), _("Failed change icon"), error);
-		g_free(error);
-		return;
-	}
-	face = strtol(filename+index, NULL, 10);
+	basename = g_path_get_basename(filepath);
+	index = strcspn(basename, "0123456789");
+	face = strtol(basename + index, NULL, 10);
+	g_free(basename);
 	purple_debug_info("QQ", "Set face to %d\n", face);
 
 	request_set_buddy_icon(gc, face);
-
-	g_strfreev(segments);
 }
 
 void qq_set_custom_icon(PurpleConnection *gc, PurpleStoredImage *img)
 {
 	PurpleAccount *account = purple_connection_get_account(gc);
 	const gchar *icon_path = purple_account_get_buddy_icon_path(account);
-	gchar **segments;
-	gint index;
 
 	g_return_if_fail(icon_path != NULL);
 
@@ -536,12 +512,6 @@
 	 *  purple_imgstore_get_filename is always new file
 	 *  QQ buddy may set custom icon if level is over 16 */
 	purple_debug_info("QQ", "Change my icon to %s\n", icon_path);
-	segments = g_strsplit_set(icon_path, G_DIR_SEPARATOR_S, 0);
-	for (index = 0; segments[index] != NULL; index++) {
-		purple_debug_info("QQ", "Split to %s\n", segments[index]);
-	}
-
-	g_strfreev(segments);
 }
 
 gchar *qq_get_icon_name(gint face)
--- a/libpurple/protocols/qq/group_join.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/qq/group_join.c	Sun Nov 16 15:39:46 2008 +0000
@@ -219,11 +219,11 @@
 
 	rmd = qq_room_data_find(gc, id);
 	if (rmd != NULL) {
-		msg = g_strdup_printf(_("Successed join to Qun %s (%d)"), rmd->title_utf8, rmd->ext_id);
+		msg = g_strdup_printf(_("Successfully joined Qun %s (%d)"), rmd->title_utf8, rmd->ext_id);
 		qq_got_attention(gc, msg);
 		g_free(msg);
 	} else {
-		qq_got_attention(gc, _("Successed join to Qun"));
+		qq_got_attention(gc, _("Successfully joined Qun"));
 	}
 }
 
--- a/libpurple/protocols/qq/group_opt.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/qq/group_opt.c	Sun Nov 16 15:39:46 2008 +0000
@@ -204,7 +204,7 @@
 
 	purple_debug_info("QQ", "Succeed in modify members for room %d\n", rmd->ext_id);
 
-	qq_room_got_chat_in(gc, id, 0, _("Successed changing Qun member"), now);
+	qq_room_got_chat_in(gc, id, 0, _("Successfully changed Qun member"), now);
 }
 
 void qq_room_change_info(PurpleConnection *gc, qq_room_data *rmd)
@@ -248,7 +248,7 @@
 
 	purple_debug_info("QQ", "Succeed modify room info of %d\n", id);
 
-	qq_room_got_chat_in(gc, id, 0, _("Successed changing Qun information"), now);
+	qq_room_got_chat_in(gc, id, 0, _("Successfully changed Qun information"), now);
 }
 
 /* we create a very simple room first, and then let the user to modify */
@@ -347,7 +347,7 @@
 
 	purple_request_action(gc, _("QQ Qun Operation"),
 			    _("You have successfully created a Qun"),
-			    _("Would you like to set up the detail information now?"),
+			    _("Would you like to set detailed information now?"),
 			    1,
 				purple_connection_get_account(gc), NULL, NULL,
 				add_req, 2,
@@ -520,7 +520,7 @@
 		rmd->my_role = QQ_ROOM_ROLE_YES;
 	}
 
-	msg = g_strdup_printf(_("<b>Joinning Qun %d is approved by Admin %d for %s</b>"),
+	msg = g_strdup_printf(_("<b>Joining Qun %d is approved by admin %d for %s</b>"),
 			ext_id, admin_uid, reason);
 	now = time(NULL);
 	qq_room_got_chat_in(gc, id, 0, msg, now);
--- a/libpurple/protocols/qq/qq.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/qq/qq.c	Sun Nov 16 15:39:46 2008 +0000
@@ -56,9 +56,6 @@
 #include "utils.h"
 #include "version.h"
 
-#define OPENQ_AUTHOR            "Puzzlebird"
-#define OPENQ_WEBSITE           "http://openq.sourceforge.net"
-
 #ifndef OPENQ_VERSION
 #define OPENQ_VERSION           DISPLAY_VERSION
 #endif
@@ -770,7 +767,7 @@
 	g_string_append(info, "</body></html>");
 
 	title = g_strdup_printf(_("About OpenQ r%s"), OPENQ_VERSION);
-	purple_notify_formatted(gc, NULL, title, NULL, info->str, NULL, NULL);
+	purple_notify_formatted(gc, title, title, NULL, info->str, NULL, NULL);
 
 	g_free(title);
 	g_string_free(info, TRUE);
@@ -866,7 +863,7 @@
 	act = purple_plugin_action_new(_("Modify Information"), action_modify_info_base);
 	m = g_list_append(m, act);
 
-	act = purple_plugin_action_new(_("Modify Extend Information"), action_modify_info_ext);
+	act = purple_plugin_action_new(_("Modify Extended Information"), action_modify_info_ext);
 	m = g_list_append(m, act);
 
 	act = purple_plugin_action_new(_("Modify Address"), action_modify_info_addr);
@@ -1113,11 +1110,11 @@
 	"QQ",				/**< name		*/
 	DISPLAY_VERSION,		/**< version		*/
 					/**  summary		*/
-	N_("QQ Protocol	Plugin"),
+	N_("QQ Protocol Plugin"),
 					/**  description	*/
-	N_("QQ Protocol	Plugin"),
-	OPENQ_AUTHOR,			/**< author		*/
-	OPENQ_WEBSITE,			/**< homepage		*/
+	N_("QQ Protocol Plugin"),
+	NULL,				/**< author		*/
+	PURPLE_WEBSITE,		/**< homepage	*/
 
 	NULL,				/**< load		*/
 	NULL,				/**< unload		*/
@@ -1149,8 +1146,7 @@
 
 	server_list = server_list_build('A');
 
-	purple_prefs_add_string_list("/plugins/prpl/qq/serverlist", server_list);
-	server_list = purple_prefs_get_string_list("/plugins/prpl/qq/serverlist");
+	purple_prefs_remove("/plugins/prpl/qq/serverlist");
 
 	server_kv_list = NULL;
 	kvp = g_new0(PurpleKeyValuePair, 1);
@@ -1203,10 +1199,10 @@
 	option = purple_account_option_bool_new(_("Show server news"), "show_news", TRUE);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
 
-	option = purple_account_option_int_new(_("Keep alive interval(s)"), "keep_alive_interval", 60);
+	option = purple_account_option_int_new(_("Keep alive interval (seconds)"), "keep_alive_interval", 60);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
 
-	option = purple_account_option_int_new(_("Update interval(s)"), "update_interval", 300);
+	option = purple_account_option_int_new(_("Update interval (seconds)"), "update_interval", 300);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
 
 	purple_prefs_add_none("/plugins/prpl/qq");
--- a/libpurple/protocols/qq/qq_base.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/qq/qq_base.c	Sun Nov 16 15:39:46 2008 +0000
@@ -71,7 +71,7 @@
 	if (len < 139) {
 		purple_connection_error_reason(gc,
 				PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
-				_("Can not decrypt get server reply"));
+				_("Can not decrypt server reply"));
 		return QQ_LOGIN_REPLY_ERR;
 	}
 
@@ -404,18 +404,18 @@
 			return process_login_redirect(gc, data, data_len);
 
 		case 0x0A:		/* extend redirect used in QQ2006 */
-			error = g_strdup( _("Not support Redirect_EX now") );
+			error = g_strdup( _("Redirect_EX is not currently supported") );
 			reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
 			break;
 		case 0x05:		/* invalid password */
 			if (!purple_account_get_remember_password(gc->account)) {
 				purple_account_set_password(gc->account, NULL);
 			}
-			error = g_strdup( _("Error password"));
+			error = g_strdup( _("Incorrect password."));
 			reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
 			break;
 		case 0x06:		/* need activation */
-			error = g_strdup( _("Need active"));
+			error = g_strdup( _("Activation required"));
 			reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
 			break;
 
@@ -789,7 +789,7 @@
 	qd->send_seq++;
 	qq_send_cmd_encrypted(gc, QQ_CMD_TOKEN_EX, qd->send_seq, buf, bytes, TRUE);
 
-	purple_connection_update_progress(gc, _("Checking code of  captcha ..."), 3, QQ_CONNECT_STEPS);
+	purple_connection_update_progress(gc, _("Checking code of captcha ..."), 3, QQ_CONNECT_STEPS);
 }
 
 typedef struct {
@@ -873,7 +873,7 @@
 	purple_request_fields(account,
 		_("QQ Captcha Verifing"),
 		_("QQ Captcha Verifing"),
-		_("Please fill code according to image"),
+		_("Enter the text from the image"),
 		fields,
 		_("OK"), G_CALLBACK(captcha_input_ok_cb),
 		_("Cancel"), G_CALLBACK(captcha_input_cancel_cb),
@@ -1094,16 +1094,16 @@
 			if (!purple_account_get_remember_password(gc->account)) {
 				purple_account_set_password(gc->account, NULL);
 			}
-			error = g_strdup(_("Error password"));
+			error = g_strdup(_("Incorrect password."));
 			reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
 			break;
 		case 0x33:		/* need activation */
 		case 0x51:		/* need activation */
-			error = g_strdup(_("Need active"));
+			error = g_strdup(_("Activation required"));
 			reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
 			break;
 		case 0xBF:		/* uid is not exist */
-			error = g_strdup(_("invalid user name"));
+			error = g_strdup(_("Invalid username."));
 			reason = PURPLE_CONNECTION_ERROR_INVALID_USERNAME;
 			break;
 		default:
--- a/libpurple/protocols/qq/qq_network.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/qq/qq_network.c	Sun Nov 16 15:39:46 2008 +0000
@@ -204,7 +204,7 @@
 		if ( set_new_server(qd) != TRUE) {
 			purple_connection_error_reason(gc,
 					PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-					_("Failed to connect all servers"));
+					_("Unable to connect."));
 			return FALSE;
 		}
 		qd->connect_retry = QQ_CONNECT_MAX;
@@ -461,9 +461,6 @@
 			conn->tcp_rxqueue = NULL;
 		}
 
-		if (pkt == NULL) {
-			continue;
-		}
 		/* packet_process may call disconnect and destory data like conn
 		 * do not call packet_process before jump,
 		 * break if packet_process return FALSE */
--- a/libpurple/protocols/qq/qq_process.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/qq/qq_process.c	Sun Nov 16 15:39:46 2008 +0000
@@ -960,7 +960,7 @@
 				return ret_8;
 			}
 
-			purple_connection_update_progress(gc, _("Logined"), QQ_CONNECT_STEPS - 1, QQ_CONNECT_STEPS);
+			purple_connection_update_progress(gc, _("Logging in"), QQ_CONNECT_STEPS - 1, QQ_CONNECT_STEPS);
 			purple_debug_info("QQ", "Login repliess OK; everything is fine\n");
 			purple_connection_set_state(gc, PURPLE_CONNECTED);
 			qd->is_login = TRUE;	/* must be defined after sev_finish_login */
--- a/libpurple/protocols/simple/simple.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/protocols/simple/simple.c	Sun Nov 16 15:39:46 2008 +0000
@@ -1228,11 +1228,14 @@
 				if (purple_str_has_prefix(ssparts[i], "terminated"))
 				{
 					purple_debug_info("simple", "Subscription expired!");
-					g_free(b->dialog->ourtag);
-					g_free(b->dialog->theirtag);
-					g_free(b->dialog->callid);
-					g_free(b->dialog);
-					b->dialog = NULL;
+					if (b->dialog)
+					{
+						g_free(b->dialog->ourtag);
+						g_free(b->dialog->theirtag);
+						g_free(b->dialog->callid);
+						g_free(b->dialog);
+						b->dialog = NULL;
+					}
 
 					purple_prpl_got_user_status(sip->account, from, "offline", NULL);
 					break;
--- a/libpurple/server.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/server.c	Sun Nov 16 15:39:46 2008 +0000
@@ -259,7 +259,8 @@
 		purple_blist_server_alias_buddy(b, alias);
 
 		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, b->name, account);
-		if(conv != NULL && alias != NULL && strcmp(alias, who))
+		if(conv != NULL && alias != NULL &&
+		   who != NULL && strcmp(alias, who))
 		{
 			char *escaped = g_markup_escape_text(who, -1);
 			char *escaped2 = g_markup_escape_text(alias, -1);
--- a/libpurple/util.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/util.c	Sun Nov 16 15:39:46 2008 +0000
@@ -984,6 +984,8 @@
 	gchar *tmp;
 	gchar *ret;
 
+	g_return_val_if_fail(opt != NULL, NULL);
+
 	if (!css_str)
 		return NULL;
 
@@ -2390,6 +2392,7 @@
 	gunichar c;
 	char *tag;
 
+	g_return_val_if_fail(str != NULL, NULL);
 	g_return_val_if_fail(x <= y, NULL);
 
 	if (x == y)
@@ -3440,6 +3443,9 @@
 	char *cmd;
 	GHashTable *params = NULL;
 	int len;
+
+	g_return_if_fail(uri != NULL);
+
 	if (!(tmp = strchr(uri, ':')) || tmp == uri) {
 		purple_debug_error("util", "Malformed protocol handler message - missing protocol.\n");
 		return;
@@ -4145,6 +4151,8 @@
 	const char *c, *domain;
 	static char *rfc822_specials = "()<>@,;:\\\"[]";
 
+	g_return_val_if_fail(address != NULL, FALSE);
+
 	/* first we validate the name portion (name@domain) (rfc822)*/
 	for (c = address;  *c;  c++) {
 		if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == '\"')) {
@@ -4193,6 +4201,9 @@
 {
 	int c, o1, o2, o3, o4;
 	char end;
+
+	g_return_val_if_fail(ip != NULL, FALSE);
+
 	c = sscanf(ip, "%d.%d.%d.%d%c", &o1, &o2, &o3, &o4, &end);
 	if (c != 4 || o1 < 0 || o1 > 255 || o2 < 0 || o2 > 255 || o3 < 0 || o3 > 255 || o4 < 0 || o4 > 255)
 		return FALSE;
--- a/libpurple/xmlnode.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/libpurple/xmlnode.c	Sun Nov 16 15:39:46 2008 +0000
@@ -249,6 +249,7 @@
 	xmlnode *x;
 
 	g_return_val_if_fail(node != NULL, NULL);
+	g_return_val_if_fail(attr != NULL, NULL);
 
 	for(x = node->child; x; x = x->next) {
 		if(x->type == XMLNODE_TYPE_ATTRIB && !strcmp(attr, x->name)) {
@@ -265,6 +266,7 @@
 	xmlnode *x;
 
 	g_return_val_if_fail(node != NULL, NULL);
+	g_return_val_if_fail(attr != NULL, NULL);
 
 	for(x = node->child; x; x = x->next) {
 		if(x->type == XMLNODE_TYPE_ATTRIB &&
--- a/pidgin/gtkaccount.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/pidgin/gtkaccount.c	Sun Nov 16 15:39:46 2008 +0000
@@ -472,7 +472,7 @@
 					 G_CALLBACK(screenname_changed_cb), dialog);
 
 	/* Do the user split thang */
-	if (dialog->plugin == NULL) /* Yeah right. */
+	if (dialog->prpl_info == NULL)
 		user_splits = NULL;
 	else
 		user_splits = dialog->prpl_info->user_splits;
--- a/pidgin/gtkblist.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/pidgin/gtkblist.c	Sun Nov 16 15:39:46 2008 +0000
@@ -3344,7 +3344,7 @@
 			}
 		}
 
-		if (prpl_info->chat_info != NULL)
+		if (prpl_info && prpl_info->chat_info != NULL)
 			cur = prpl_info->chat_info(chat->account->gc);
 		else
 			cur = NULL;
--- a/pidgin/gtknotify.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/pidgin/gtknotify.c	Sun Nov 16 15:39:46 2008 +0000
@@ -703,7 +703,7 @@
 	gtk_widget_grab_focus(button);
 
 	g_signal_connect_swapped(G_OBJECT(button), "clicked",
-							 G_CALLBACK(gtk_widget_destroy), window);
+							 G_CALLBACK(formatted_close_cb), window);
 	g_signal_connect(G_OBJECT(window), "key_press_event",
 					 G_CALLBACK(formatted_input_cb), NULL);
 
--- a/pidgin/gtksavedstatuses.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/pidgin/gtksavedstatuses.c	Sun Nov 16 15:39:46 2008 +0000
@@ -475,7 +475,8 @@
 static void
 savedstatus_activated_cb(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *column, StatusWindow *dialog)
 {
-	status_window_modify_cb(NULL, dialog);
+	status_window_use_cb(NULL, dialog);
+	status_window_close_cb(NULL, dialog);
 }
 
 static void
--- a/pidgin/plugins/sendbutton.c	Thu Nov 13 19:51:47 2008 +0000
+++ b/pidgin/plugins/sendbutton.c	Sun Nov 16 15:39:46 2008 +0000
@@ -37,9 +37,26 @@
 }
 
 static void
+input_buffer_changed(GtkTextBuffer *text_buffer, GtkWidget *send_button)
+{
+	if (gtk_text_buffer_get_char_count(text_buffer) != 0)
+		gtk_widget_set_sensitive(send_button, TRUE);
+	else
+		gtk_widget_set_sensitive(send_button, FALSE);
+}
+
+static void
 create_send_button_pidgin(PidginConversation *gtkconv)
 {
 	GtkWidget *send_button;
+	GtkTextBuffer *buf;
+	guint signal_id;
+
+	send_button = g_object_get_data(G_OBJECT(gtkconv->lower_hbox),
+	                                "send_button");
+
+	if (send_button != NULL)
+		return;
 
 	send_button = gtk_button_new_with_mnemonic(_("_Send"));
 	g_signal_connect(G_OBJECT(send_button), "clicked",
@@ -48,6 +65,16 @@
 	                 FALSE, 0);
 	gtk_widget_show(send_button);
 
+	buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->entry));
+	if (buf) {
+		signal_id = g_signal_connect(G_OBJECT(buf), "changed",
+		                             G_CALLBACK(input_buffer_changed),
+		                             send_button);
+		g_object_set_data(G_OBJECT(send_button), "buffer-signal",
+		                  GINT_TO_POINTER(signal_id));
+		input_buffer_changed(buf, send_button);
+	}
+ 
 	g_object_set_data(G_OBJECT(gtkconv->lower_hbox), "send_button",
 	                  send_button);
 }
@@ -60,7 +87,18 @@
 	send_button = g_object_get_data(G_OBJECT(gtkconv->lower_hbox),
 	                                "send_button");
 	if (send_button != NULL) {
+		GtkTextBuffer *buf;
+		guint signal_id;
+
+		buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->entry));
+		signal_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(send_button),
+		                                              "buffer-signal"));
+		if (buf && signal_id)
+			g_signal_handler_disconnect(G_OBJECT(buf), signal_id);
+
 		gtk_widget_destroy(send_button);
+		g_object_set_data(G_OBJECT(gtkconv->lower_hbox),
+		                  "send_button", NULL);
 	}
 }