adium: 7e1a5251: pidgin-facebookchat at r564.

zacw at adiumx.com zacw at adiumx.com
Mon Jun 29 19:05:34 EDT 2009


-----------------------------------------------------------------
Revision: 7e1a5251180b65c5f9c3242f700497baf7062721
Ancestor: 83638905971b97ae72bc7318a7f152adf5e8b6f1
Author: zacw at adiumx.com
Date: 2009-06-29T23:01:38
Branch: im.pidgin.adium
URL: http://d.pidgin.im/viewmtn/revision/info/7e1a5251180b65c5f9c3242f700497baf7062721

Added files:
        libpurple/protocols/facebook/fb_conversation.c
        libpurple/protocols/facebook/fb_conversation.h
        libpurple/protocols/facebook/fb_util.c
        libpurple/protocols/facebook/fb_util.h
Modified files:
        libpurple/protocols/facebook/facebook.nsi
        libpurple/protocols/facebook/fb_blist.c
        libpurple/protocols/facebook/fb_blist.h
        libpurple/protocols/facebook/fb_connection.c
        libpurple/protocols/facebook/fb_connection.h
        libpurple/protocols/facebook/fb_info.c
        libpurple/protocols/facebook/fb_managefriends.c
        libpurple/protocols/facebook/fb_messages.c
        libpurple/protocols/facebook/fb_notifications.c
        libpurple/protocols/facebook/libfacebook.c
        libpurple/protocols/facebook/libfacebook.h
        libpurple/protocols/facebook/pidgin-facebookchat.rc
        libpurple/protocols/facebook/rss.xml
Modified attrs:
        libpurple/protocols/facebook/fb_util.c
        libpurple/protocols/facebook/fb_util.h

ChangeLog: 

pidgin-facebookchat at r564.

-------------- next part --------------
============================================================
--- libpurple/protocols/facebook/fb_conversation.c	259358150129a9c835a26193282d46f2dd284d18
+++ libpurple/protocols/facebook/fb_conversation.c	259358150129a9c835a26193282d46f2dd284d18
@@ -0,0 +1,258 @@
+/*
+ * libfacebook
+ *
+ * libfacebook is the property of its developers.  See the COPYRIGHT file
+ * for more details.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "fb_conversation.h"
+#include "fb_connection.h"
+#include "fb_util.h"
+
+#include <json-glib/json-glib.h>
+
+#include "conversation.h"
+#include "signals.h"
+
+/*****************************************************************************
+ * MESSAGE PROCESSING                                                        *
+ *****************************************************************************/
+void fb_conversation_handle_message(FacebookAccount *fba, const char *from,
+	const char *to, gint64 message_time, const gchar *message_orig,
+	gboolean log)
+{
+	gchar *tmp, *message_text;
+
+	if (!log) {
+		purple_debug_info("facebook", "message with no logging\n");
+	}
+
+	// Process message.
+	message_text = fb_strdup_withhtml(message_orig);
+	tmp = message_text;
+	message_text = fb_replace_styled_text(message_text);
+	g_free(tmp);
+
+	if (fba->uid != atoll(from) || fba->uid == atoll(to)) {
+		purple_debug_info("facebook",
+			"displaying received message %lld: %s\n",
+			message_time, message_text);
+		// TODO/FIXME: cheat here by changing formatting colors.
+		// Or add an option to just disable history on conv open.  TBD.
+		serv_got_im(fba->pc, from, message_text,
+			log? 
+				PURPLE_MESSAGE_RECV :
+				PURPLE_MESSAGE_RECV,
+			message_time / 1000);
+		if (message_time > fba->last_message_time) {
+			fba->last_message_time = message_time;
+		} else {
+			purple_debug_warning("facebook",
+					"displaying message out of sync\n");
+		}
+	} else if (!g_hash_table_remove(
+		fba->sent_messages_hash, message_orig))
+	{
+		purple_debug_info("facebook",
+			"displaying sent message %lld: %s\n",
+			message_time, message_text);
+
+		serv_got_im(fba->pc, to, message_text,
+			log? 
+				PURPLE_MESSAGE_SEND :
+				PURPLE_MESSAGE_SEND,
+			message_time / 1000);
+		if (message_time > fba->last_message_time) {
+			fba->last_message_time = message_time;
+		} else {
+			purple_debug_warning("facebook",
+					"displaying message out of sync\n");
+		}
+	}
+
+	// Cleanup.
+	g_free(message_text);
+}
+
+
+/*****************************************************************************
+ * HISTORY CODE                                                              *
+ *****************************************************************************/
+
+static void fb_history_fetch_cb(FacebookAccount *fba, gchar *data,
+	gsize data_len, gpointer userdata)
+{
+	JsonParser *parser;
+	JsonNode *root;
+	JsonObject *object, *payload;
+	JsonArray *history;
+	guint i;
+	gint64 min_time;
+
+	parser = fb_get_parser(data, data_len);
+
+	if (!parser) {
+		// We didn't get data, but this isn't necessarily fatal.
+		purple_debug_warning("facebook",
+			"bad data while fetching history\n");
+		return;
+	}
+
+	min_time = atoll((char *) userdata);
+	g_free(userdata);
+	purple_debug_info("facebook", "history fetch with min time of %lld\n",
+		       min_time);	
+
+	root = json_parser_get_root(parser);
+	object = json_node_get_object(root);
+	payload = json_node_get_object(
+		json_object_get_member(object, "payload"));
+	history = json_node_get_array(
+		json_object_get_member(payload, "history"));
+
+	purple_debug_info("facebook",
+			"found %d history items to possibly render\n",
+			json_array_get_length(history));
+
+	for (i = 0; i < json_array_get_length(history); i++) {
+		const gchar *type;
+		JsonObject *message_obj;
+
+		message_obj = json_node_get_object(
+			json_array_get_element(history, i));
+		type = json_node_get_string(json_object_get_member(
+			message_obj, "type"));
+	
+		if (g_str_equal(type, "msg")) {
+			gint64 message_time;
+			const gchar *message;
+			gchar *from;
+			gchar *to;
+			JsonObject *text_obj;
+
+			from = g_strdup_printf("%d", json_node_get_int(
+				json_object_get_member(message_obj, "from")));
+			to = g_strdup_printf("%d", json_node_get_int(
+				json_object_get_member(message_obj, "to")));
+
+			text_obj = json_node_get_object(
+				json_object_get_member(message_obj, "msg"));
+			message = json_node_get_string(
+				json_object_get_member(text_obj, "text"));
+
+			message_time = fb_time_kludge(json_node_get_int(
+				json_object_get_member(message_obj, "time")));
+
+			if (message_time > min_time) {
+				purple_debug_info("facebook",
+					"displaying history message %lld\n",
+					message_time);
+				fb_conversation_handle_message(
+					fba, from, to, message_time, message,
+					min_time != 0);
+			}
+
+			g_free(from);
+			g_free(to);
+		}
+	}
+	
+	g_object_unref(parser);
+}
+
+void fb_history_fetch(FacebookAccount *fba, const char *who,
+		gboolean display_all)
+{
+	g_return_if_fail(fba != NULL);
+	
+	purple_debug_info("facebook", "fetching history with %s\n", who);
+
+	gint64 min_time = fba->last_message_time;
+	if (display_all) {
+		min_time = 0;
+	}
+
+	gchar *url = g_strdup_printf("/ajax/chat/history.php?id=%s", who);
+	fb_post_or_get(
+		fba, FB_METHOD_GET, NULL, url, NULL, fb_history_fetch_cb,
+		g_strdup_printf("%lld", min_time), FALSE);
+	g_free(url);
+}
+
+/*****************************************************************************
+ * GENERAL EVENTS CODE                                                       *
+ *****************************************************************************/
+
+void fb_conversation_closed(PurpleConnection *gc, const char *who)
+{
+	FacebookAccount *fba = gc->proto_data;
+	gchar *postdata;
+
+	g_return_if_fail(fba->post_form_id != NULL);
+
+	/* notify server that we closed the chat window */
+	/* close_chat=589039771&window_id=3168919846&
+	 * post_form_id=c258fe42460c7e8b61e242a37ef05afc */
+	postdata = g_strdup_printf("close_chat=%s&post_form_id=%s", who,
+			fba->post_form_id);
+	fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/chat/settings.php",
+			postdata, NULL, NULL, FALSE);
+	g_free(postdata);
+}
+
+static void fb_conversation_created(PurpleConversation *conv)
+{
+	PurpleAccount *account = purple_conversation_get_account(conv);
+
+	if (!fb_conversation_is_fb(conv)) {
+		return;
+	}
+
+	purple_debug_info("facebook", "conversation created with %s\n",
+		conv->name);
+
+	fb_history_fetch(account->gc->proto_data, conv->name, TRUE);
+}
+
+gboolean fb_conversation_is_fb(PurpleConversation *conv)
+{
+	PurpleAccount *account = purple_conversation_get_account(conv);
+	const gchar *prpl = purple_account_get_protocol_id(account);
+	return g_str_equal(prpl, FACEBOOK_PLUGIN_ID);
+}
+
+void fb_conversation_init(FacebookAccount *fba)
+{
+	fba->last_message_time = 0;
+
+	purple_signal_connect(
+		purple_conversations_get_handle(),
+		"conversation-created",
+		fba,
+		PURPLE_CALLBACK(fb_conversation_created),
+		NULL);
+}
+
+void fb_conversation_destroy(FacebookAccount *fba)
+{
+	purple_signal_disconnect(
+		purple_conversations_get_handle(),
+		"conversation-created",
+		fba,
+		PURPLE_CALLBACK(fb_conversation_created));
+}
+
+
============================================================
--- libpurple/protocols/facebook/fb_conversation.h	828d73df9a7ffcd3680ee051f49606328a742185
+++ libpurple/protocols/facebook/fb_conversation.h	828d73df9a7ffcd3680ee051f49606328a742185
@@ -0,0 +1,38 @@
+/*
+ * libfacebook
+ *
+ * libfacebook is the property of its developers.  See the COPYRIGHT file
+ * for more details.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FACEBOOK_CONVERSATION_H
+#define FACEBOOK_CONVERSATION_H
+
+#include "libfacebook.h"
+
+void fb_conversation_init(FacebookAccount *fba);
+void fb_conversation_destroy(FacebookAccount *fba);
+
+void fb_conversation_closed(PurpleConnection *gc, const char *who);
+gboolean fb_conversation_is_fb(PurpleConversation *conv);
+
+void fb_history_fetch(FacebookAccount *fba, const char *who,
+		gboolean display_all);
+void fb_conversation_handle_message(FacebookAccount *fba, const char *from,
+	const char *to, gint64 message_time, const gchar *message_orig,
+	gboolean log);
+
+#endif /* FACEBOOK_CONVERSATION_H */
============================================================
--- libpurple/protocols/facebook/fb_util.c	23606c4fef64d4b023b7dca41ac62a8b499a4924
+++ libpurple/protocols/facebook/fb_util.c	23606c4fef64d4b023b7dca41ac62a8b499a4924
@@ -0,0 +1,64 @@
+/*
+ * libfacebook
+ *
+ * libfacebook is the property of its developers.  See the COPYRIGHT file
+ * for more details.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "fb_util.h"
+
+/*****************************************************************************
+ * UTILITY CODE                                                              *
+ *****************************************************************************/
+
+/* Converts *text* into <b>text</b>  and _text_ into <i>text</i> */
+gchar *fb_replace_styled_text(const gchar *text)
+{
+	if (glib_check_version(2, 14, 0))
+	{
+		return g_strdup(text);
+	} else {
+		static GRegex *underline_regex = NULL;
+		static GRegex *bold_regex = NULL;
+		gchar *dup_text;
+		gchar *midway_string;
+		gchar *output_string;
+		
+		if (underline_regex == NULL)
+		{
+			underline_regex = g_regex_new(
+				"\\b_([^_\\*]+)_\\b", G_REGEX_OPTIMIZE,
+				0, NULL);
+		}
+		if (bold_regex == NULL)
+		{
+			bold_regex = g_regex_new(
+				"(\\s|^)\\*([^_\\*]+)\\*(?=$|\\s)",
+				G_REGEX_OPTIMIZE, 0, NULL);
+		}
+		
+		dup_text = g_strdup(text);
+		midway_string = g_regex_replace(underline_regex, dup_text,
+			-1, 0, "<u>\\1</u>", 0, NULL);
+		g_free(dup_text);
+		output_string = g_regex_replace(bold_regex, midway_string,
+			-1, 0, "\\1<b>\\2</b>", 0, NULL);
+		g_free(midway_string);
+		
+		return output_string;
+	}
+}
+
============================================================
--- libpurple/protocols/facebook/fb_util.h	33093b85583658b53d9519de66ab7da32ebd5076
+++ libpurple/protocols/facebook/fb_util.h	33093b85583658b53d9519de66ab7da32ebd5076
@@ -0,0 +1,29 @@
+/*
+ * libfacebook
+ *
+ * libfacebook is the property of its developers.  See the COPYRIGHT file
+ * for more details.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FACEBOOK_UTIL_H
+#define FACEBOOK_UTIL_H
+
+#include "libfacebook.h"
+
+gchar *fb_replace_styled_text(const gchar *text);
+
+#endif /* FACEBOOK_UTIL_H */
+
============================================================
--- libpurple/protocols/facebook/facebook.nsi	67598b3e9ead8be15c1e600b6dd3de05c0dd682e
+++ libpurple/protocols/facebook/facebook.nsi	86d06564f9bcb28939ce31fea5cf6e899cb530a9
@@ -6,7 +6,7 @@ SetCompress off
 ; todo: SetBrandingImage
 ; HM NIS Edit Wizard helper defines
 !define PRODUCT_NAME "pidgin-facebookchat"
-!define PRODUCT_VERSION "1.51"
+!define PRODUCT_VERSION "1.53"
 !define PRODUCT_PUBLISHER "Eion Robb"
 !define PRODUCT_WEB_SITE "http://pidgin-facebookchat.googlecode.com/"
 !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
============================================================
--- libpurple/protocols/facebook/fb_blist.c	5074f94eb56fc5bfe2337b0e991d3ef9d0f20361
+++ libpurple/protocols/facebook/fb_blist.c	a756fad89ceaabc66d0f1f4798a348b416396471
@@ -40,6 +40,7 @@ static void buddy_icon_cb(FacebookAccoun
 {
 	gchar *buddyname;
 	PurpleBuddy *buddy;
+	FacebookBuddy *fbuddy;
 	gpointer buddy_icon_data;
 
 	buddyname = user_data;
@@ -53,10 +54,12 @@ static void buddy_icon_cb(FacebookAccoun
 	if (buddy == NULL)
 		return;
 
+	fbuddy = buddy->proto_data;
+
 	buddy_icon_data = g_memdup(data, data_len);
 
 	purple_buddy_icons_set_for_user(fba->account, buddy->name,
-			buddy_icon_data, data_len, NULL);
+			buddy_icon_data, data_len, fbuddy->thumb_url);
 }
 
 static void got_buddy_list_cb(FacebookAccount *fba, gchar *data,
@@ -86,7 +89,8 @@ static void got_buddy_list_cb(FacebookAc
 	if (fba == NULL)
 		return;
 
-	if (data == NULL) {
+	JsonParser *parser = fb_get_parser(data, data_len);
+	if (parser == NULL) {
 		purple_connection_error_reason(fba->pc,
 				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
 				_("Could not retrieve buddy list"));
@@ -95,23 +99,7 @@ static void got_buddy_list_cb(FacebookAc
 	
 	purple_debug_misc("facebook", "buddy list\n%s\n", data);
 	
-	tmp = g_strstr_len(data, data_len, "for (;;);");
-	if (tmp)
-	{
-		tmp += strlen("for (;;);");
-	}
-	
-	JsonParser *parser;
 	JsonNode *root;
-	
-	parser = json_parser_new();
-	if(!json_parser_load_from_data(parser, tmp, -1, NULL))
-	{
-		purple_connection_error_reason(fba->pc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-				_("Could not retrieve buddy list"));
-		return;	
-	}
 	root = json_parser_get_root(parser);
 	JsonObject *objnode;
 	objnode = json_node_get_object(root);
@@ -170,15 +158,13 @@ static void got_buddy_list_cb(FacebookAc
 		currentUserNode = g_list_next(currentUserNode))
 	{
 		uid = currentUserNode->data;
-		purple_debug_misc("facebook", "uid: %s\n", uid);
 
 		JsonObject *userInfo;
 		userInfo = json_node_get_object(json_object_get_member(userInfos, uid));
 		name = json_node_dup_string(json_object_get_member(userInfo, "name"));
-		purple_debug_misc("facebook", "name: %s\n", name);
 
-		/* try updating the alias, just in case it was removed locally */
-		serv_got_alias(fba->pc, uid, name);
+		/* update the blist if we have no previous alias */
+		fb_blist_set_alias(fba, uid, name);
 
 		/* look for "uid":{"i":_____} */
 		if (json_object_has_member(nowAvailableList, uid))
@@ -186,7 +172,6 @@ static void got_buddy_list_cb(FacebookAc
 			JsonObject *userBlistInfo;
 			userBlistInfo = json_node_get_object(json_object_get_member(nowAvailableList, uid));
 			idle = json_node_get_boolean(json_object_get_member(userBlistInfo, "i"));
-			purple_debug_misc("facebook", "buddy idle: %s\n", (idle?"true":"false"));
 			current_buddy_online = TRUE;
 		} else {
 			/* if we're here, the buddy's info has been sent, but they're not actually online */
@@ -203,7 +188,7 @@ static void got_buddy_list_cb(FacebookAc
 		}
 
 		/* is this us? */
-		if (atoi(uid) == fba->uid)
+		if (atoll(uid) == fba->uid)
 		{
 			purple_connection_set_display_name(fba->pc, name);
 
@@ -235,7 +220,6 @@ static void got_buddy_list_cb(FacebookAc
 			}
 			purple_blist_add_buddy(buddy, NULL, fb_group, NULL);
 		}
-		serv_got_alias(fba->pc, uid, name);
 		purple_presence_set_idle(purple_buddy_get_presence(buddy), idle, 0);
 
 		/* Set the FacebookBuddy structure */
@@ -244,13 +228,13 @@ static void got_buddy_list_cb(FacebookAc
 			fbuddy = g_new0(FacebookBuddy, 1);
 			fbuddy->buddy = buddy;
 			fbuddy->fba = fba;
-			fbuddy->uid = atoi(uid);
+			fbuddy->uid = atoll(uid);
 			fbuddy->name = g_strdup(name);
 
-			/* load the old buddy icon from the account settings */
-			tmp = g_strdup_printf("buddy_icon_%d_cache", fbuddy->uid);
-			fbuddy->thumb_url = g_strdup(purple_account_get_string(fba->account, tmp, ""));
-			g_free(tmp);
+			/* load the old buddy icon url from the icon 'checksum' */
+			buddy_icon_url = (char *)purple_buddy_icons_get_checksum_for_user(buddy);
+			if (buddy_icon_url != NULL)
+				fbuddy->thumb_url = g_strdup(buddy_icon_url);
 
 			buddy->proto_data = fbuddy;
 		} else {
@@ -264,7 +248,6 @@ static void got_buddy_list_cb(FacebookAc
 			tmp = fb_strdup_withhtml(status_text);
 			g_free(status_text);
 			status_text = tmp;
-			purple_debug_misc("facebook", "status: %s\n", status_text);
 
 			status_time_text = json_node_dup_string(json_object_get_member(userInfo, "statusTimeRel"));
 			if (strlen(status_time_text) == 0)
@@ -276,7 +259,7 @@ static void got_buddy_list_cb(FacebookAc
 			if (status_time_text != NULL)
 			{
 				fbuddy->status_rel_time = fb_strdup_withhtml(status_time_text);
-				purple_debug_misc("facebook", "status time: %s\n", fbuddy->status_rel_time);
+				g_free(status_time_text);
 			} else {
 				fbuddy->status_rel_time = NULL;
 			}
@@ -310,37 +293,28 @@ static void got_buddy_list_cb(FacebookAc
 		if (fbuddy->thumb_url == NULL || !g_str_equal(fbuddy->thumb_url, buddy_icon_url))
 		{
 			g_free(fbuddy->thumb_url);
-			fbuddy->thumb_url = g_strdup(buddy_icon_url);
-
-			/* Save the buddy icon so that they don't all need to be reloaded at startup */
-			tmp = g_strdup_printf("buddy_icon_%d_cache", fbuddy->uid);
-			purple_account_set_string(fba->account, tmp, buddy_icon_url);
-			g_free(tmp);
-
-			/* Turn the \/ into / */
-			tmp = g_strcompress(buddy_icon_url);
-
-			if (g_str_equal(tmp, "http://static.ak.fbcdn.net/pics/q_silhouette.gif"))
+			if (g_str_equal(buddy_icon_url, "http://static.ak.fbcdn.net/pics/q_silhouette.gif"))
 			{
+				fbuddy->thumb_url = NULL;
 				/* User has no icon */
 				purple_buddy_icons_set_for_user(fba->account,
 						purple_buddy_get_name(buddy), NULL, 0, NULL);
 			}
 			else
 			{
+				fbuddy->thumb_url = g_strdup(buddy_icon_url);
+
 				/* small icon at http://profile.ak.facebook.com/profile6/1845/74/q800753867_2878.jpg */
 				/* bigger icon at http://profile.ak.facebook.com/profile6/1845/74/n800753867_2878.jpg */
-				search_tmp = strstr(tmp, "/q");
+				search_tmp = strstr(buddy_icon_url, "/q");
 				if (search_tmp)
 					*(search_tmp + 1) = 'n';
 				
 				/* Fetch their icon */
 				fb_post_or_get(fba, FB_METHOD_GET, "profile.ak.facebook.com",
-						tmp + strlen("http://profile.ak.facebook.com"), NULL,
-						buddy_icon_cb, g_strdup(purple_buddy_get_name(buddy)),
-					FALSE);
+						buddy_icon_url + strlen("http://profile.ak.facebook.com"), NULL,
+						buddy_icon_cb, g_strdup(purple_buddy_get_name(buddy)), FALSE);
 			}
-			g_free(tmp);
 		}
 		g_free(buddy_icon_url);
 
@@ -364,7 +338,7 @@ static void got_buddy_list_cb(FacebookAc
 	}
 	g_hash_table_destroy(online_buddies_list);
 	
-	if (notifications != NULL)
+	if (notifications != NULL && purple_account_get_check_mail(fba->account))
 	{
 		JsonNode *inboxCount_node = json_object_get_member(notifications, "inboxCount");
 		if (inboxCount_node)
@@ -391,7 +365,7 @@ gboolean fb_get_buddy_list(gpointer data
 	fba = data;
 
 	postdata = g_strdup_printf(
-			"user=%d&popped_out=true&force_render=true&buddy_list=1&notifications=1",
+			"user=%" G_GINT64_FORMAT "&popped_out=true&force_render=true&buddy_list=1&notifications=1",
 			fba->uid);
 	fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/presence/update.php",
 			postdata, got_buddy_list_cb, NULL, FALSE);
@@ -419,7 +393,7 @@ void fb_blist_poke_buddy(PurpleBlistNode
 	if (!fba)
 		return;
 	
-	postdata = g_strdup_printf("uid=%d&pokeback=0&post_form_id=%s", fbuddy->uid, fba->post_form_id);
+	postdata = g_strdup_printf("uid=%" G_GINT64_FORMAT "&pokeback=0&post_form_id=%s", fbuddy->uid, fba->post_form_id);
 	
 	fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/poke.php",
 				postdata, NULL, NULL, FALSE);
@@ -427,3 +401,28 @@ void fb_blist_poke_buddy(PurpleBlistNode
 	g_free(postdata);
 }
 
+void fb_blist_set_alias(FacebookAccount *fba, const gchar *id,
+		const gchar *name)
+{
+	const char *current_alias;
+	PurpleBuddy *buddy;
+
+	buddy = purple_find_buddy(fba->account, id);
+	if (!buddy) {
+		return;
+	}	
+
+	/* Set an alias if no user-defined alias is set yet.  This provides
+	 * a basic name alias for each user which is more useful than a
+	 * number.  A small corner case bug here- aliases will not change
+	 * in accordance with people changing their names on Facebook.
+	 */
+	current_alias = purple_buddy_get_alias_only(buddy);
+	if (!current_alias) {
+		purple_debug_info("facebook", "aliasing %s to %s\n", id, name);
+		purple_blist_alias_buddy(buddy, name);
+	}
+
+	/* In case user removes an alias, we have the server as fallback */
+	serv_got_alias(fba->pc, id, name);
+}
============================================================
--- libpurple/protocols/facebook/fb_blist.h	25ed459fca57c9f2b6e324cbba392d29081ce75c
+++ libpurple/protocols/facebook/fb_blist.h	282d636d6e7f6011bec4f39d5cc9483b1be8b199
@@ -26,4 +26,7 @@ void fb_blist_poke_buddy(PurpleBlistNode
 gboolean fb_get_buddy_list(gpointer data);
 void fb_blist_poke_buddy(PurpleBlistNode *node, gpointer data);
 
+void fb_blist_set_alias(FacebookAccount *fba, const char *id,
+		const char *name);
+
 #endif /* FACEBOOK_BLIST_H */
============================================================
--- libpurple/protocols/facebook/fb_connection.c	8668d97080d9afe72ca0519bb5f0ab641daa34c5
+++ libpurple/protocols/facebook/fb_connection.c	557b8518d7576ae548b710f016cbca9d3f76f606
@@ -123,6 +123,7 @@ void fb_connection_destroy(FacebookConne
 	if (fbconn->input_watcher > 0)
 		purple_input_remove(fbconn->input_watcher);
 
+	g_free(fbconn->url);
 	g_free(fbconn->hostname);
 	g_free(fbconn);
 }
@@ -153,9 +154,6 @@ static void fb_update_cookies(FacebookAc
 		cookie_value= g_strndup(cookie_start, cookie_end-cookie_start);
 		cookie_start = cookie_end;
 
-		purple_debug_info("facebook", "got cookie %s=%s\n",
-				cookie_name, cookie_value);
-
 		g_hash_table_replace(fba->cookie_table, cookie_name,
 				cookie_value);
 	}
@@ -184,8 +182,6 @@ static void fb_connection_process_data(F
 		tmp = g_memdup(tmp, len + 1);
 		tmp[len] = '\0';
 		fbconn->rx_buf[fbconn->rx_len - len] = '\0';
-		purple_debug_misc("facebook", "response headers\n%s\n",
-				fbconn->rx_buf);
 		fb_update_cookies(fbconn->fba, fbconn->rx_buf);
 
 #ifdef HAVE_ZLIB
@@ -203,8 +199,10 @@ static void fb_connection_process_data(F
 	g_free(fbconn->rx_buf);
 	fbconn->rx_buf = NULL;
 
-	if (fbconn->callback != NULL)
+	if (fbconn->callback != NULL) {
+		purple_debug_info("facebook", "executing callback for %s\n", fbconn->url);
 		fbconn->callback(fbconn->fba, tmp, len, fbconn->user_data);
+	}
 
 	g_free(tmp);
 }
@@ -312,13 +310,13 @@ static void fb_post_or_get_connect_cb(gp
 
 	if (error_message)
 	{
+		purple_debug_error("facebook", "post_or_get_connect failure to %s\n", fbconn->url);
 		purple_debug_error("facebook", "post_or_get_connect_cb %s\n",
 				error_message);
 		fb_fatal_connection_cb(fbconn);
 		return;
 	}
 
-	purple_debug_info("facebook", "post_or_get_connect_cb\n");
 	fbconn->fd = source;
 
 	/* TODO: Check the return value of write() */
@@ -356,8 +354,6 @@ static void fb_host_lookup_cb(GSList *ho
 	FacebookAccount *fba;
 	PurpleDnsQueryData *query;
 
-	purple_debug_info("facebook", "updating cache of dns addresses\n");
-
 	/* Extract variables */
 	host_lookup_list = data;
 
@@ -412,9 +408,6 @@ static void fb_host_lookup_cb(GSList *ho
 		hosts = g_slist_delete_link(hosts, hosts);
 	}
 
-	purple_debug_info("facebook", "Host %s has IP %s\n",
-			hostname, ip_address);
-
 	g_hash_table_insert(fba->hostname_ip_cache, hostname, ip_address);
 }
 
@@ -538,8 +531,7 @@ void fb_post_or_get(FacebookAccount *fba
 	g_string_append_printf(request, "Accept-Language: %s\r\n", language_names);
 	g_free(language_names);
 
-	purple_debug_misc("facebook", "sending request headers:\n%s\n",
-			request->str);
+	purple_debug_info("facebook", "getting url %s\n", url);
 
 	g_string_append_printf(request, "\r\n");
 	if (method & FB_METHOD_POST)
@@ -549,11 +541,11 @@ void fb_post_or_get(FacebookAccount *fba
 	 * it in the debug log.  Without this condition a user's password is
 	 * printed in the debug log */
 	if (method == FB_METHOD_POST)
-		purple_debug_misc("facebook", "sending request data:\n%s\n",
+		purple_debug_info("facebook", "sending request data:\n%s\n",
 			postdata);
 
 	g_free(cookies);
-	g_free(real_url);
+
 	/*
 	 * Do a separate DNS lookup for the given host name and cache it
 	 * for next time.
@@ -574,9 +566,6 @@ void fb_post_or_get(FacebookAccount *fba
 
 		host_ip = g_hash_table_lookup(fba->hostname_ip_cache, host);
 		if (host_ip != NULL) {
-			purple_debug_info("facebook",
-					"swapping original host %s with cached value of %s\n",
-					host, host_ip);
 			host = host_ip;
 		} else if (fba->account && !fba->account->disconnecting) {
 			GSList *host_lookup_list = NULL;
@@ -596,6 +585,7 @@ void fb_post_or_get(FacebookAccount *fba
 
 	fbconn = g_new0(FacebookConnection, 1);
 	fbconn->fba = fba;
+	fbconn->url = real_url;
 	fbconn->method = method;
 	fbconn->hostname = g_strdup(host);
 	fbconn->request = request;
============================================================
--- libpurple/protocols/facebook/fb_connection.h	89a1161f53d976e628a64a9f9d7a189db6e25f47
+++ libpurple/protocols/facebook/fb_connection.h	e3c87874ac44ae6437066264c6a9996be5333a0e
@@ -38,6 +38,7 @@ struct _FacebookConnection {
 	FacebookAccount *fba;
 	FacebookMethod method;
 	gchar *hostname;
+	gchar *url;
 	GString *request;
 	FacebookProxyCallbackFunc callback;
 	gpointer user_data;
============================================================
--- libpurple/protocols/facebook/fb_info.c	e106afd4c3c6b0a50eabe2befdffa860563a6f33
+++ libpurple/protocols/facebook/fb_info.c	3eb9ceaf6170bc0b2ab8f2ef73d9adec28363839
@@ -65,6 +65,7 @@ static void fb_get_info_cb(FacebookAccou
 	FacebookBuddy *fbuddy = NULL;
 
 	purple_debug_info("facebook", "get_info_cb\n");
+	purple_debug_info("facebook", "%s\n", data);
 
 	buddy = purple_find_buddy(fba->account, uid);
 	if (buddy)
@@ -86,6 +87,33 @@ static void fb_get_info_cb(FacebookAccou
 	search_start = g_strstr_len(data, data_len, "<div id=\"info_tab\" class=\"info_tab\">");
 	if (search_start == NULL)
 	{
+		search_start = g_strstr_len(data, data_len, "http:\\/\\/");
+		if (search_start)
+		{
+			search_end = strstr(search_start, "\"");
+			value_tmp = g_strndup(search_start, search_end - search_start);
+			value_tmp2 = value_tmp;
+			if (value_tmp) {
+				char * buf = g_new(char, strlen(value_tmp) + 1); 
+				char * url = buf;
+				while(*value_tmp) { 
+				if (*value_tmp=='\\') {
+						// skip escape char 
+						*buf++ = value_tmp[1]; 
+						value_tmp += 2; 
+					} else { 
+						*buf++ = *value_tmp++; 
+					}
+				}
+				*buf = 0;
+				purple_debug_info("facebook", "info url: %s\n", url);
+				fb_post_or_get(fba->pc->proto_data, FB_METHOD_GET, NULL, url, NULL, fb_get_info_cb, g_strdup(uid), FALSE);
+				g_free(uid);
+				g_free(url);
+				g_free(value_tmp2);
+				return;
+			}
+		}
 		purple_debug_warning("facebook",
 				"could not find user info, showing default");
 		purple_notify_userinfo(fba->pc, uid, user_info, NULL, NULL);
@@ -177,12 +205,16 @@ static void fb_get_info_cb(FacebookAccou
 		}
 
 		/* turn html to plaintext */
-		value_tmp2 = g_strchomp(purple_markup_strip_html(value_tmp));
-		g_free(value_tmp);
+		if (strcmp(label_tmp, "AIM")) {
+			value_tmp2 = g_strchomp(purple_markup_strip_html(value_tmp));
+			g_free(value_tmp);
+			value_tmp = value_tmp2;
 
-		/* remove the silly links */
-		value_tmp = fb_remove_useless_stripped_links(value_tmp2);
-		g_free(value_tmp2);
+			/* remove the silly links */
+			value_tmp2 = fb_remove_useless_stripped_links(value_tmp);
+			g_free(value_tmp);
+			value_tmp = value_tmp2;
+		}
 
 		purple_debug_info("facebook", "label: %s\n", label_tmp);
 		purple_debug_info("facebook", "value: %s\n", value_tmp);
============================================================
--- libpurple/protocols/facebook/fb_managefriends.c	13711a39b329088119005f6dd7c6ec6617de8f26
+++ libpurple/protocols/facebook/fb_managefriends.c	48d9104fae04b40e366b570f78e4b366e0d87a43
@@ -25,46 +25,52 @@ static void fb_auth_accept_cb(gpointer d
 {
 	FacebookBuddy *fbuddy = data;
 	FacebookAccount *fba = fbuddy->fba;
+	gchar *buddy_uid;
 	gchar *postdata;
 
 	g_return_if_fail(fba != NULL);
 	g_return_if_fail(fba->post_form_id != NULL);
 	g_return_if_fail(fbuddy->uid != 0);
 
+	buddy_uid = g_strdup_printf("%" G_GINT64_FORMAT, fbuddy->uid);
+
 	postdata = g_strdup_printf(
-			"type=friend_add&id=%d&action=accept&post_form_id=%s",
-			fbuddy->uid, fba->post_form_id);
+			"type=friend_add&id=%s&action=accept&post_form_id=%s",
+			buddy_uid, fba->post_form_id);
 	fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/reqs.php",
 			postdata, NULL, NULL, FALSE);
-	g_free(postdata);
 
-	fba->auth_buddies = g_slist_remove(fba->auth_buddies,
-			GINT_TO_POINTER(fbuddy->uid));
-
+	g_hash_table_remove(fba->auth_buddies, buddy_uid);
+	
+	g_free(postdata);
 	g_free(fbuddy);
+	g_free(buddy_uid);
 }
 
 static void fb_auth_reject_cb(gpointer data)
 {
 	FacebookBuddy *fbuddy = data;
 	FacebookAccount *fba = fbuddy->fba;
+	gchar *buddy_uid;
 	gchar *postdata;
 
 	g_return_if_fail(fba != NULL);
 	g_return_if_fail(fba->post_form_id != NULL);
 	g_return_if_fail(fbuddy->uid != 0);
 
+	buddy_uid = g_strdup_printf("%" G_GINT64_FORMAT, fbuddy->uid);
+
 	postdata = g_strdup_printf(
-			"type=friend_add&id=%d&action=reject&post_form_id=%s",
-			fbuddy->uid, fba->post_form_id);
+			"type=friend_add&id=%s&action=reject&post_form_id=%s",
+			buddy_uid, fba->post_form_id);
 	fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/reqs.php",
 			postdata, NULL, NULL, FALSE);
-	g_free(postdata);
 
-	fba->auth_buddies = g_slist_remove(fba->auth_buddies,
-			GINT_TO_POINTER(fbuddy->uid));
-
+	g_hash_table_remove(fba->auth_buddies, buddy_uid);
+	
+	g_free(postdata);
 	g_free(fbuddy);
+	g_free(buddy_uid);
 }
 
 static void fb_check_friend_request_cb(FacebookAccount *fba, gchar *data,
@@ -89,10 +95,10 @@ static void fb_check_friend_request_cb(F
 				strchr(search_start, '"') - search_start);
 		purple_debug_info("facebook", "uid: %s\n", uid);
 
-		uid_int = atoi(uid);
+		uid_int = atoll(uid);
 
-		if (g_slist_find(fba->auth_buddies,
-				GINT_TO_POINTER(uid_int)) != NULL)
+		if (g_hash_table_lookup_extended(fba->auth_buddies,
+						uid, NULL, NULL))
 		{
 			/* we've already notified the user of this friend request */
 			g_free(uid);
@@ -130,13 +136,12 @@ static void fb_check_friend_request_cb(F
 				name, msg_plain, TRUE,
 				fb_auth_accept_cb, fb_auth_reject_cb, buddy);
 
+		/* Don't display an auth request for this buddy again */
+		g_hash_table_insert(fba->auth_buddies, uid, NULL);
+		
 		g_free(name);
 		g_free(uid);
-		g_free(msg_plain);
-		
-		/* Don't display an auth request for this buddy again */
-		fba->auth_buddies = g_slist_prepend(
-				fba->auth_buddies, GINT_TO_POINTER(uid_int));
+		g_free(msg_plain);		
 	}
 }
 
@@ -171,7 +176,7 @@ void fb_add_buddy(PurpleConnection *pc, 
 		return;
 	}
 
-	if (atoi(buddy->name) == fba->uid)
+	if (atoll(buddy->name) == fba->uid)
 	{
 		purple_account_set_bool(fba->account,
 				"facebook_hide_self", FALSE);
@@ -200,7 +205,7 @@ static void fb_remove_buddy(PurpleConnec
 	gchar *postdata;
 	FacebookAccount *fba = pc->proto_data;
 
-	if (atoi(buddy->name) == fba->uid)
+	if (atoll(buddy->name) == fba->uid)
 	{
 		purple_account_set_bool(fba->account, "facebook_hide_self", TRUE);
 		return;
============================================================
--- libpurple/protocols/facebook/fb_messages.c	f5bc0e080df2dcc102667479e7940791008251bd
+++ libpurple/protocols/facebook/fb_messages.c	55cba18f6f06fcf967d93af64fce1cbb06224521
@@ -20,9 +20,13 @@
 
 #include "fb_messages.h"
 #include "fb_connection.h"
+#include "fb_conversation.h"
+#include "fb_blist.h"
 
 #include <json-glib/json-glib.h>
 
+#include "conversation.h"
+
 typedef struct _FacebookOutgoingMessage FacebookOutgoingMessage;
 
 struct _FacebookOutgoingMessage {
@@ -38,7 +42,6 @@ static gboolean fb_get_new_messages(Face
 static gboolean fb_send_im_fom(FacebookOutgoingMessage *msg);
 static gboolean fb_resend_im_fom(FacebookOutgoingMessage *msg);
 static gboolean fb_get_new_messages(FacebookAccount *fba);
-static gchar *fb_replace_styled_text(const gchar *text);
 
 static FacebookOutgoingMessage *fb_msg_create(FacebookAccount *fba)
 {
@@ -68,33 +71,94 @@ void fb_cancel_resending_messages(Facebo
 		fb_msg_destroy(msg);
 	}	
 }
-								  
-static void got_new_messages(FacebookAccount *fba, gchar *data,
-		gsize data_len, gpointer userdata)
+
+static void parse_message(PurpleConnection *pc, FacebookAccount *fba,
+	JsonObject *messageObj, const char* from, const char* to)
 {
-	gchar *message;
-	gchar *message_text;
-	gchar *message_time;
-	gchar *from;
-	gchar *to;
-	gchar *tmp;
-	gchar *type;
-	gchar *start;
-	gchar *end;
-	gint64 msgID;
+	gint64 message_time;
+	const gchar *message;
+
+	purple_debug_info("facebook", "message from %s to %s\n", from, to);
+
+	message = json_node_get_string(
+		json_object_get_member(messageObj, "text"));
+
+	message_time = fb_time_kludge(json_node_get_int(
+				json_object_get_member(messageObj, "time")));
+
+	fb_conversation_handle_message(fba, from, to, message_time, message, TRUE);			
+}
+
+static void parse_new_messages(PurpleConnection *pc, FacebookAccount *fba, JsonArray *messages)
+{
 	int i;
-	PurpleConnection *pc = userdata;
 	PurpleBuddy *buddy;
 
-	/* NULL data will crash on Windows */
-	if (data == NULL)
-		data = "(null)";
+	purple_debug_info("facebook", "parsing new messages\n");
 
-	purple_debug_misc("facebook", "got new messages: %s\n", data);
+	for (i = 0; i < json_array_get_length(messages); i++) {
+		const gchar *type;
+		gchar *from, *to;
 
-	/* purple_debug_info("facebook", "fba: %d\n", fba); */
-	/* purple_debug_info("facebook", "account: %d\n", fba->account); */
+		JsonObject *object = json_node_get_object(json_array_get_element(messages, i));
+		type = json_node_get_string(json_object_get_member(object, "type"));
 
+		from = g_strdup_printf("%d", json_node_get_int(json_object_get_member(object, "from")));
+		to = g_strdup_printf("%d", json_node_get_int(json_object_get_member(object, "to")));
+		
+		/* Use the in-line buddy name if the buddy list hasn't been downloaded yet */
+		buddy = purple_find_buddy(pc->account, from);
+		if (buddy == NULL || buddy->server_alias == NULL || buddy->alias == NULL)
+		{
+			if (json_object_has_member(object, "from_name"))
+			{
+				const gchar *from_name = json_node_get_string(json_object_get_member(
+					object, "from_name"));
+				fb_blist_set_alias(fba, from, from_name);
+			}
+		}
+
+		if (from && to && g_str_equal(type, "msg")) {
+			JsonObject *messageObj = json_node_get_object(json_object_get_member(object, "msg"));
+			parse_message(pc, fba, messageObj, from, to);
+		} else if (from && g_str_equal(type, "typ")) {
+			purple_debug_info("facebook", "handling typing notification\n");
+
+			gint typing = json_node_get_int(json_object_get_member(object, "st"));
+			if (typing == 0) {
+				serv_got_typing(pc, from, 10, PURPLE_NOT_TYPING);
+			} else {
+				serv_got_typing(pc, from, 10, PURPLE_TYPING);
+			}
+		}
+
+		/*
+		 * we've received something from a buddy, assume they're online
+		 * only if it's not from ourselves
+		 */
+		if (from && fba->uid != atoll(from)) {
+			purple_prpl_got_user_status(
+				fba->account, from, 
+				purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE), NULL);
+
+		}
+	
+		g_free(from);
+		g_free(to);
+
+		fba->message_fetch_sequence++;
+	}
+}
+								  
+static void got_new_messages(FacebookAccount *fba, gchar *data,
+		gsize data_len, gpointer userdata)
+{
+	JsonParser *parser;
+
+	PurpleConnection *pc = userdata;
+
+	purple_debug_misc("facebook", "got new messages:\n%s\n", data);
+
 	/* for (;;);{"t":"msg","c":"p_800753867","ms":[{"type":"msg",
 		"msg":{"text":"yes","time":1211176515861,"clientTime":1211176514750,
 		"msgID":"367146364"},"from":596176850,"to":800753867,
@@ -124,12 +188,10 @@ static void got_new_messages(FacebookAcc
 		"msgID":"3382240259"},"from":596176850,"to":800753867,
 		"from_name":"Jeremy Lawson","to_name":"Eion Robb",
 		"from_first_name":"Jeremy","to_first_name":"Eion"}]} */
-
 	/* for (;;);{"t":"refresh", "seq":1} */
 
-	/* look for the start of the JSON, and ignore any proxy headers */
-	data = g_strstr_len(data, data_len, "for (;;);");
-	if (!data)
+	parser = fb_get_parser(data, data_len);
+	if (!parser)
 	{
 		/* Sometimes proxies will return incorrect data, so we just shrug 
 		 * it off.
@@ -145,198 +207,49 @@ static void got_new_messages(FacebookAcc
 		return;
 	}
 
-	/* refresh means that the channel is invalid */
-	if (g_str_equal(data, "for (;;);{\"t\":\"refresh\"}"))
-	{
-		fb_reconnect(fba);
-		return;
-	}
+	JsonNode *root;
+	root = json_parser_get_root(parser);
 
-	/* continue means that the server wants us to remake the connection */
-	if (g_str_equal(data, "for (;;);{\"t\":\"continue\"}"))
-	{
-		/* Continue looping, waiting for more messages */
-		fb_get_new_messages(fba);
-		return;
-	}
+	JsonObject *objnode;
+	objnode = json_node_get_object(root);
 
-	tmp = strstr(data, "\"seq\":");
-	if (tmp != NULL)
-	{
-		tmp = tmp + 6;
-		tmp = g_strndup(tmp, strchr(tmp, '}') - tmp);
-		purple_debug_info("facebook", "new seq number: %s\n", tmp);
-		fba->message_fetch_sequence = atoi(tmp);
-		g_free(tmp);
-	} else {
-		fba->message_fetch_sequence++;
-	}
-
-	if (strncmp(data, "for (;;);{\"t\":\"msg\"", 19) == 0)
-	{
-		start = g_strstr_len(data, data_len, "\"ms\":[");
-		if (!start)
-		{
-			/* Continue looping, waiting for more messages */
-			fb_get_new_messages(fba);
-			return;
-		}
-		start += 6;
-		while (*start != ']')
-		{
-			tmp = strstr(start, "\"type\":\"");
-			if (tmp)
-			{
-				tmp += 8;
-				type = g_strndup(tmp, strchr(tmp, '"') - tmp);
-				purple_debug_info("facebook", "type: %s\n", type);
-			} else {
-				type = g_strdup("unknown");
+	if (json_object_has_member(objnode, "t")) {
+		const gchar* command = json_node_get_string(json_object_get_member(objnode, "t"));
+		if (g_str_equal(command, "refresh")) {
+			int seq = json_node_get_int(json_object_get_member(objnode, "seq"));
+			if (seq) {
+				fba->message_fetch_sequence = seq;	
 			}
 
-			tmp = strstr(start, "\"from\":");
-			if (tmp)
-			{
-				tmp += 7;
-				from = g_strndup(tmp, strchr(tmp, ',') - tmp);
-				if (from[0] == '"')
-					snprintf(from, strlen(from), "%d", atoi(from + 1));
-				purple_debug_info("facebook", "from: %s\n", from);
-			} else {
-				from = NULL;
-			}
-			tmp = strstr(start, "\"to\":");
-			if (tmp)
-			{
-				tmp += 5;
-				end = strchr(tmp, ',');
-				if (end == NULL || strchr(tmp, '}') < end)
-					end = strchr(tmp, '}');
-				to = g_strndup(tmp, end - tmp);
-				if (to[0] == '"')
-					snprintf(to, strlen(to), "%d", atoi(to + 1));
-				purple_debug_info("facebook", "to: %s\n", to);
-			} else {
-				to = NULL;
-			}
-
-			if (from && to && g_str_equal(type, "msg"))
-			{
-				/* IM message */
-					tmp = strstr(start, "\"msgID\":");
-					tmp += 9;
-					tmp = g_strndup(tmp, strchr(tmp, '"') - tmp);
-					msgID = atoll(tmp);
-					purple_debug_info("facebook", "message id: %s %" G_GINT64_FORMAT " %lld\n", tmp, msgID, atoll(tmp));
-					g_free(tmp);
-					/* loop through all the previous messages that we have stored */
-					/* to make sure that we havn't already received this message */
-					for(i = 0; i < FB_LAST_MESSAGE_MAX; i++)
-					{
-						purple_debug_info("facebook", "last_messages[%d] = %" G_GINT64_FORMAT "\n", i, fba->last_messages[i]);
-						if (fba->last_messages[i] == msgID)
-							break;
-					}
-					purple_debug_info("facebook", "i: %d\n", i);
-					if (i == FB_LAST_MESSAGE_MAX)
-					{
-						/* if we're here, it must be a new message */
-						fba->last_messages[fba->next_message_pointer++] = msgID;
-						if (fba->next_message_pointer >= FB_LAST_MESSAGE_MAX)
-							fba->next_message_pointer = 0;
-
-						tmp = strstr(start, "\"text\":\"");
-						tmp += 8;
-						tmp = g_strndup(tmp, strstr(tmp, "\",\"time\":") - tmp);
-						message = fb_convert_unicode(tmp);
-						g_free(tmp);
-						message_text = fb_strdup_withhtml(message);
-						tmp = fb_replace_styled_text(message_text);
-						g_free(message_text);
-						message_text = tmp;
-						purple_debug_info("facebook", "text: %s\n", message_text);
-						
-						tmp = strstr(start, "\"time\":");
-						tmp += 7;
-						message_time = g_strndup(tmp, strchr(tmp, ',') - tmp - 3);
-						purple_debug_info("facebook", "time: %s\n", message_time);
-						
-						/* Use the in-line buddy name if the buddy list hasn't been downloaded yet */
-						buddy = purple_find_buddy(pc->account, from);
-						if (buddy == NULL || buddy->server_alias == NULL)
-						{
-							tmp = strstr(start, "\"from_name\":\"");
-							if (tmp)
-							{
-								tmp += 13;
-								tmp = g_strndup(tmp, strstr(tmp, "\",") - tmp);
-								serv_got_alias(pc, from, tmp);
-								g_free(tmp);
-							}
-						}
-						
-						if (fba->uid != atoi(from) || fba->uid == atoi(to))
-							serv_got_im(pc, from, message_text, PURPLE_MESSAGE_RECV, atoi(message_time));
-						else if (!g_hash_table_remove(fba->sent_messages_hash, message))
-							serv_got_im(pc, to, message_text, PURPLE_MESSAGE_SEND, atoi(message_time));
-						g_free(message);
-						
-						/*
-						 * Acknowledge receipt of the message by simulating
-						 * focusing the window.  Not sure what the window_id
-						 * is here, but it doesn't seem to matter.  Maybe
-						 * something internal to the Facebook javascript that
-						 * is used for maintaining UI state across page loads?
-						 */
-						if (!fba->is_idle && fba->uid != atoi(from))
-						{
-							gchar *postdata;
-	
-							postdata = g_strdup_printf(
-									"focus_chat=%s&window_id=12345&post_form_id=%s",
-									from, fba->post_form_id);
-							fb_post_or_get(fba, FB_METHOD_POST, NULL,
-									"/ajax/chat/settings.php?_ecdc=false",
-									postdata, NULL, NULL, FALSE);
-							g_free(postdata);
-						}
-
-						g_free(message_text);
-						g_free(message_time);
-					}
-				
-				start = strchr(start, '}')+1;
-			} else if (from && g_str_equal(type, "typ"))
-			{
-				/* typing notification */
-				tmp = strstr(start, "\"st\":");
-				if (tmp != NULL)
-				{
-					tmp += 5;
-					if (*tmp == '0')
-						serv_got_typing(pc, from, 10, PURPLE_TYPED);
-					else
-						serv_got_typing(pc, from, 10, PURPLE_TYPING);
+			/* grab history items for all open conversations */
+			GList *conversations = purple_get_conversations();
+			while (conversations != NULL) {
+				PurpleConversation *conv =
+					(PurpleConversation *)conversations->data;
+				if (fb_conversation_is_fb(conv)) {
+					purple_debug_info("facebook",
+						"checking for dropped messages with %s\n",
+						conv->name);
+					fb_history_fetch(fba, conv->name, FALSE);
 				}
+				conversations = conversations->next;
 			}
 
-			/*
-			 * we've received something from a buddy, assume they're online
-			 * only if it's not from ourselves
-			 */
-			if (from && fba->uid != atoi(from))
-				purple_prpl_got_user_status(fba->account, from, purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE), NULL);
-
-			g_free(from);
-			g_free(to);
-			g_free(type);
-
-			start = strchr(start, '}')+1;
-			while (*start == ',')
-				start++;
+			/* refresh means that the channel is invalid */
+			fb_reconnect(fba);
+			g_object_unref(parser);
+			return;
+		} else if (g_str_equal(command, "continue")) {
+			/* continue means that the server wants us to remake the connection.
+ 			 * continue the loop and wait for messages. noop. */
+		} else if (g_str_equal(command, "msg")) {
+			parse_new_messages(pc, fba,
+				json_node_get_array(json_object_get_member(objnode, "ms")));
 		}
 	}
 
+	g_object_unref(parser);
+
 	/* Continue looping, waiting for more messages */
 	fb_get_new_messages(fba);
 }
@@ -351,9 +264,6 @@ static gboolean fb_get_new_messages(Face
  */
 static gboolean fb_get_new_messages(FacebookAccount *fba)
 {
-	/* MARKCONFLICT (r283,r286): Mark uses the fba->chanel_number variable here,
-	 * where this patch/fix eschews that in favor of some hacks.
-	 */
 	time_t now;
 	gchar *fetch_url;
 	gchar *fetch_server;
@@ -387,7 +297,7 @@ static gboolean fb_get_new_messages(Face
 
 	fetch_server = g_strdup_printf("%d.channel%s.facebook.com", 0, channel_number);
 	/* use the current time in the url to get past any transparent proxy caches */
-	fetch_url = g_strdup_printf("/x/%lu/%s/p_%d=%d", time(NULL), (fba->is_idle?"false":"true"), fba->uid, fba->message_fetch_sequence);
+	fetch_url = g_strdup_printf("/x/%lu/%s/p_%" G_GINT64_FORMAT "=%d", time(NULL), (fba->is_idle?"false":"true"), fba->uid, fba->message_fetch_sequence);
 
 	fb_post_or_get(fba, FB_METHOD_GET, fetch_server, fetch_url, NULL, got_new_messages, fba->pc, TRUE);
 	fba->last_messages_download_time = now;
@@ -401,14 +311,16 @@ static void fb_send_im_cb(FacebookAccoun
 static void fb_send_im_cb(FacebookAccount *fba, gchar *data, gsize data_len, gpointer user_data)
 {
 	FacebookOutgoingMessage *msg = user_data;
-	gchar *error_summary = NULL;
-	gchar *tmp;
-	gboolean was_an_error = FALSE;
+	gint error_number;
+	const gchar *error_summary;
+	JsonParser *parser;
+	JsonNode *root;
+	JsonObject *object;
+	PurpleConversation *conv;
 
 	/* NULL data crashes on Windows */
 	if (data == NULL)
 	{
-		was_an_error = TRUE;
 		data = "(null)";
 	}
 	
@@ -422,48 +334,42 @@ static void fb_send_im_cb(FacebookAccoun
 		"payload":[],"bootload":[{"name":"js\/common.js.pkg.php","type":"js",
 		"src":"http:\/\/static.ak.fbcdn.net\/rsrc.php\/pkg\/59\/98936\
 		/js\/common.js.pkg.php"}]} */
-
-	tmp = g_strstr_len(data, data_len, "\"error\":");
-	if (tmp != NULL)
+	
+	parser = fb_get_parser(data, data_len);
+	if (!parser) {
+		// We didn't get data, but this isn't necessarily fatal.
+		purple_debug_warning("facebook", "bad data while parsing sent IM\n");
+		return;
+	}
+	root = json_parser_get_root(parser);
+	object = json_node_get_object(root);
+	
+	error_number = json_node_get_int(json_object_get_member(object, "error"));
+	error_summary = json_node_get_string(json_object_get_member(object, "errorSummary"));
+	
+	if (error_number)
 	{
-		tmp += 8;
-		tmp = g_strndup(tmp, strchr(tmp, ',') - tmp);
-		if (strlen(tmp) > 1 || tmp[0] != '0')
+		purple_debug_error("facebook", "sent im error: %s\n", error_summary);
+		/* there was an error, either report it or retry */
+		if (msg->retry_count++ < FB_MAX_MSG_RETRY)
 		{
-			g_free(tmp);
-			tmp = g_strstr_len(data, data_len, "\"errorSummary\":\"");
-			tmp += 16;
-			error_summary = g_strndup(tmp, strchr(tmp, '"') - tmp);
-			purple_debug_error("facebook", "sent im error: %s\n", error_summary);
-			if (*error_summary)
-			{
-				/* there was an error, either report it or retry */
-				if (msg->retry_count++ < FB_MAX_MSG_RETRY)
-				{
-					msg->resend_timer = purple_timeout_add_seconds(1, (GSourceFunc)fb_resend_im_fom, msg);
-					fba->resending_messages = g_slist_prepend(fba->resending_messages, msg);
-					g_free(error_summary);
-					return;
-				}
-				else
-				{
-					PurpleConversation *conv;
-					conv = purple_conversation_new(PURPLE_CONV_TYPE_IM,
-							fba->account, msg->who);
-					purple_conversation_write(conv, NULL, error_summary,
-							PURPLE_MESSAGE_ERROR, msg->time);
-					was_an_error = TRUE;
-				}
-			}
+			msg->resend_timer = purple_timeout_add_seconds(1, (GSourceFunc)fb_resend_im_fom, msg);
+			fba->resending_messages = g_slist_prepend(fba->resending_messages, msg);
+			g_object_unref(parser);
+			return;
 		}
-	}
-
-	if (was_an_error)
-	{
+		else
+		{
+			conv = purple_conversation_new(PURPLE_CONV_TYPE_IM,
+					fba->account, msg->who);
+			purple_conversation_write(conv, NULL, error_summary,
+					PURPLE_MESSAGE_ERROR, msg->time);
+		}
+		
 		g_hash_table_remove(fba->sent_messages_hash, msg->message);
 	}
 
-	g_free(error_summary);
+	g_object_unref(parser);
 	fb_msg_destroy(msg);
 }
 
@@ -517,11 +423,7 @@ int fb_send_im(PurpleConnection *pc, con
 
 	fb_send_im_fom(msg);
 
-	/* gchar *styled_message = fb_replace_styled_text(msg->message);
-	serv_got_im(pc, msg->who, styled_message, PURPLE_MESSAGE_SEND, msg->time);
-	g_free(styled_message);
-
-	return 0; */
+	/* Return 1 so UI will display message */
 	return 1;
 }
 
@@ -532,26 +434,17 @@ void got_reconnect_json(FacebookAccount 
 	JsonParser *parser;
 	JsonNode *root;
 
-	if (data == NULL)
-		data = "(null)";	
+	parser = fb_get_parser(data, data_len);
 
-	gchar *tmp = g_strstr_len(data, data_len, "for (;;);");
-	if (tmp)
-	{
-		tmp += strlen("for (;;);");
-	}
-	
-	parser = json_parser_new();
-	if(!json_parser_load_from_data(parser, tmp, -1, NULL))
-	{
+	if (!parser) {
 		purple_debug_error("facebook", "couldn't parse reconnect data\n");
 		purple_debug_info("facebook", "page content: %s\n", data);
 		purple_connection_error_reason(fba->pc,
 				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
 				_("Chat service currently unavailable"));
-		g_object_unref(parser);
 		return;
 	}
+
 	root = json_parser_get_root(parser);
 	JsonObject *objnode;
 	objnode = json_node_get_object(root);
@@ -567,7 +460,7 @@ void got_reconnect_json(FacebookAccount 
 		purple_debug_info("facebook", "page content: %s\n", data);
 		purple_connection_error_reason(fba->pc,
 				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-				_("Chat service currently unavailable"));
+				_("Error fetching channel; did you log in elsewhere?"));
 		g_object_unref(parser);
 		return;
 	}
@@ -589,7 +482,7 @@ gboolean fb_reconnect(FacebookAccount *f
 
 gboolean fb_reconnect(FacebookAccount *fba)
 {
-	gchar *url = g_strdup_printf("/ajax/presence/reconnect.php?post_form_id=%s", fba->post_form_id);
+	gchar *url = g_strdup_printf("/ajax/presence/reconnect.php?reason=3&post_form_id=%s", fba->post_form_id);
 	fb_post_or_get(fba, FB_METHOD_GET, NULL, url, NULL, got_reconnect_json, NULL, FALSE);
 	g_free(url);
 	
@@ -637,33 +530,3 @@ gboolean fb_get_post_form_id(FacebookAcc
 	fb_post_or_get(fba, FB_METHOD_GET, NULL, "/presence/popout.php", NULL, got_form_id_page, NULL, FALSE);
 	return FALSE;
 }
-
-/* Converts *text* into <b>text</b>  and _text_ into <i>text</i> */
-static gchar *fb_replace_styled_text(const gchar *text)
-{
-	if (glib_check_version(2, 14, 0))
-	{
-		return g_strdup(text);
-	} else {
-		static GRegex *underline_regex = NULL;
-		static GRegex *bold_regex = NULL;
-		gchar *midway_string;
-		gchar *output_string;
-		
-		if (underline_regex == NULL)
-		{
-			underline_regex = g_regex_new("\\b_([^_\\*]+)_\\b", G_REGEX_OPTIMIZE, 0, NULL);
-		}
-		if (bold_regex == NULL)
-		{
-			bold_regex = g_regex_new("(\\s|^)\\*([^_\\*]+)\\*(?=$|\\s)", G_REGEX_OPTIMIZE, 0, NULL);
-		}
-		
-		midway_string = g_regex_replace(underline_regex, text, -1, 0, "<u>\\1</u>", 0, NULL);
-		output_string = g_regex_replace(bold_regex, midway_string, -1, 0, "\\1<b>\\2</b>", 0, NULL);
-		g_free(midway_string);
-		
-		return output_string;
-	}
-}
-
============================================================
--- libpurple/protocols/facebook/fb_notifications.c	1066c720340c2b996497a69a99de13e422bf285b
+++ libpurple/protocols/facebook/fb_notifications.c	ca23fe8908d98aa815fb521ef82a9c2937652dae
@@ -30,8 +30,7 @@ static void fb_got_notifications_cb(Face
 	gchar month_string[4], weekday[4];
 	guint year, month, day, hour, minute, second;
 	long timezone;
-	gchar *subject, *url, *stripped_subject;
-	gchar *search_start = (gchar *)url_text;
+	gchar *subject, *url;
 
 	month_string[3] = weekday[3] = '\0';
 	year = month = day = hour = minute = second = 0;
@@ -42,21 +41,25 @@ static void fb_got_notifications_cb(Face
 	last_fetch_time = purple_account_get_int(fba->account, "facebook_notifications_last_fetch", 0);
 	/* purple_debug_info("facebook", "last fetch time: %zu\n", last_fetch_time); */
 
-	while (search_start && (search_start = strstr(search_start, "<item>")))
+	xmlnode *rss_root = xmlnode_from_str(url_text, len);
+	if (rss_root == NULL)
 	{
-		search_start = search_start + 6;
-
-		tmp = strstr(search_start, "<pubDate>");
-		if (!tmp)
-		{
-			purple_debug_error("facebook", "couldn't find date in rss feed\n");
-			return;
-		}
-		tmp += 9;
-		tmp = g_strndup(tmp, strchr(tmp, '<')-tmp);
-
+		return;
+	}
+	xmlnode *channel = xmlnode_get_child(rss_root, "channel");
+	if (channel == NULL)
+	{
+		xmlnode_free(rss_root);
+		return;
+	}
+	xmlnode *item = xmlnode_get_child(channel, "item");
+	for (; item != NULL; item = xmlnode_get_next_twin(item))
+	{
+		xmlnode *pubDate = xmlnode_get_child(item, "pubDate");
+		if (!pubDate)
+			continue;
+		tmp = xmlnode_get_data_unescaped(pubDate);
 		/* rss times are in Thu, 19 Jun 2008 15:51:25 -1100 format */
-		/* purple_debug_info("facebook", "pre time: %s\n", tmp); */
 		sscanf(tmp, "%3s, %2u %3s %4u %2u:%2u:%2u %5ld", (char*)&weekday, &day, (char*)&month_string, &year, &hour, &minute, &second, &timezone);
 		if (g_str_equal(month_string, "Jan")) month = 0;
 		else if (g_str_equal(month_string, "Feb")) month = 1;
@@ -79,14 +82,11 @@ static void fb_got_notifications_cb(Face
 
 		if (time_of_message <= 0)
 		{
-			/* there's no cross-platform, portable way of converting string to time */
-			/* that doesn't need a new version of glib, so just cheat */
+			/* there's no cross-platform, portable way of converting string to time
+			   which doesn't need a new version of glib, so just cheat */
 			time_of_message = second + 60*minute + 3600*hour + 86400*day + 2592000*month + 31536000*(year-1970);
 		}
 
-		/* purple_debug_info("facebook", "time of message: %zu\n", time_of_message); */
-		/* purple_debug_info("facebook", "time of message: %s\n", ctime(&time_of_message)); */
-
 		if (time_of_message > newest_message)
 		{
 			/* we'll keep the newest message to save */
@@ -99,40 +99,28 @@ static void fb_got_notifications_cb(Face
 			/* so if this message is older than the last one, ignore rest */
 			break;
 		}
-
-		tmp = strstr(search_start, "<link>");
-		if (!tmp)
+		
+		xmlnode *link = xmlnode_get_child(item, "link");
+		if (link)
 		{
-			url = g_strdup("");
+			url = xmlnode_get_data_unescaped(link);
 		} else {
-			tmp += 6;
-			url = g_strndup(tmp, strchr(tmp, '<')-tmp);
-			/* convert &amp; to & */
-			tmp = purple_unescape_html(url);
-			g_free(url);
-			url = tmp;
+			url = g_strdup("");
 		}
-
-		tmp = strstr(search_start, "<title>");
-		if (!tmp)
+		
+		xmlnode *title = xmlnode_get_child(item, "title");
+		if (title)
 		{
-			subject = g_strdup("");
+			subject = xmlnode_get_data_unescaped(title);
 		} else {
-			tmp += 7;
-			subject = g_strndup(tmp, strchr(tmp, '<')-tmp);
+			subject = g_strdup("");
 		}
-		stripped_subject = purple_unescape_html(subject);
-		g_free(subject);
-		subject = stripped_subject;
 		
-		purple_debug_info("facebook", "subject: %s\n", subject);
-
 		purple_notify_email(fba->pc, subject, NULL, fba->account->username, url, NULL, NULL);
 		g_free(subject);
 		g_free(url);
-
-		search_start = strstr(search_start, "</item>");
 	}
+	xmlnode_free(rss_root);
 
 	if (newest_message > last_fetch_time)
 	{
============================================================
--- libpurple/protocols/facebook/libfacebook.c	343796cc30236c62ce8522c5fe370f43924f7194
+++ libpurple/protocols/facebook/libfacebook.c	4a5dcafa34bf51425459fa4d44852b720bbc3661
@@ -21,6 +21,7 @@
 #include "libfacebook.h"
 #include "fb_blist.h"
 #include "fb_connection.h"
+#include "fb_conversation.h"
 #include "fb_info.h"
 #include "fb_managefriends.h"
 #include "fb_messages.h"
@@ -119,6 +120,43 @@ gchar *fb_strdup_withhtml(const gchar *s
 	return dest;
 }
 
+JsonParser *fb_get_parser(const gchar *data, gsize data_len)
+{
+	JsonParser *parser;
+
+	if (data == NULL) {
+		return NULL;
+	}
+
+	data = g_strstr_len(data, data_len, "for (;;);");
+	if (!data) {
+		return NULL;
+	} else {
+		data += strlen("for (;;);");
+	}
+
+	parser = json_parser_new();
+	if (!json_parser_load_from_data(parser, data, -1, NULL)) {
+		g_object_unref(parser);
+		return NULL;
+	}
+
+	return parser;
+}
+
+gint64 fb_time_kludge(gint initial_time)
+{
+	if (sizeof(gint) >= sizeof(gint64))
+		return initial_time;
+	
+	gint64 now_millis = (gint64) time(NULL);
+	now_millis *= 1000;
+	now_millis &= 0xFFFFFFFF00000000LL;
+	gint64 final_time = now_millis | initial_time;
+
+	return final_time;
+}
+
 /******************************************************************************/
 /* PRPL functions */
 /******************************************************************************/
@@ -177,7 +215,11 @@ static GList *fb_statuses(PurpleAccount 
 	types = g_list_append(types, status);
 	
 	/* Cave into feature requests and allow people to set themselves to be idle */
-	status = purple_status_type_new_full(PURPLE_STATUS_AWAY, NULL, _("Idle"), FALSE, TRUE, FALSE);
+	status = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY,
+		NULL, _("Idle"), FALSE, TRUE, FALSE, "message",
+		_("Message"), purple_value_new(PURPLE_TYPE_STRING),
+		"message_date", _("Message changed"),
+		purple_value_new(PURPLE_TYPE_STRING), NULL);
 	types = g_list_append(types, status);
 
 	/* Offline people dont have messages */
@@ -219,8 +261,8 @@ static void fb_login_cb(FacebookAccount 
 				_("Incorrect username or password."));
 		return;
 	}
-	fba->uid = atoi(user_cookie);
-	purple_debug_info("facebook", "uid %d\n", fba->uid);
+	fba->uid = atoll(user_cookie);
+	purple_debug_info("facebook", "uid %" G_GINT64_FORMAT "\n", fba->uid);
 
 	/* ok, we're logged in now! */
 	purple_connection_set_state(fba->pc, PURPLE_CONNECTED);
@@ -255,12 +297,14 @@ static void fb_login_cb(FacebookAccount 
 	 */
 	fba->perpetual_messages_timer = purple_timeout_add_seconds(15,
 			(GSourceFunc)fb_get_messages_failsafe, fba);
+
+	/* init conversation subsystem */
+	fb_conversation_init(fba);
 }
 
 static void fb_login(PurpleAccount *account)
 {
 	FacebookAccount *fba;
-	guint16 i;
 	gchar *postdata, *encoded_username, *encoded_password, *encoded_charset_test;
 	const gchar* const *languages;
 	const gchar *locale;
@@ -277,13 +321,12 @@ static void fb_login(PurpleAccount *acco
 			g_free, g_free);
 	fba->sent_messages_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
 			g_free, NULL);
+	fba->auth_buddies = g_hash_table_new_full(g_str_hash, g_str_equal,
+			g_free, NULL);
 
 	g_hash_table_replace(fba->cookie_table, g_strdup("test_cookie"),
 			g_strdup("1"));
 
-	for (i = 0; i < FB_LAST_MESSAGE_MAX; i++)
-		fba->last_messages[i] = 0;
-
 	account->gc->proto_data = fba;
 
 	/* Error localized in libpurple jabber.c */
@@ -331,6 +374,11 @@ static void fb_close(PurpleConnection *p
 	
 	fba = pc->proto_data;
 
+	purple_debug_info("facebook", "unloading plugin\n");
+
+	/* destroy conversation subsystem */
+	fb_conversation_destroy(fba);
+
 	/* Tell Facebook that we've logged out. */
 	/*
 	 * TODO
@@ -398,9 +446,9 @@ static void fb_close(PurpleConnection *p
 
 	g_hash_table_destroy(fba->cookie_table);
 	g_hash_table_destroy(fba->hostname_ip_cache);
+	g_hash_table_destroy(fba->auth_buddies);
 	g_free(fba->post_form_id);
 	g_free(fba->channel_number);
-	g_slist_free(fba->auth_buddies);
 	g_free(fba->last_status_message);
 	g_free(fba);
 }
@@ -419,7 +467,7 @@ static unsigned int fb_send_typing(Purpl
 	typing_state = (state == PURPLE_TYPING) ? 1 : 0;
 
 	/* Don't send typing notifications to self */
-	if (atoi(name) != fba->uid)
+	if (atoll(name) != fba->uid)
 	{
 		encoded_name = g_strdup(purple_url_encode(name));
 		postdata = g_strdup_printf("typ=%d&to=%s&post_form_id=%s",
@@ -462,12 +510,12 @@ static void fb_set_status_ok_cb(gpointer
 	if (*status_text_new != '\0')
 	{
 		status_tmp = g_strdup(purple_url_encode(status_text_new));
-		postdata = g_strdup_printf("profile_id=%d&status=%s&post_form_id=%s",
+		postdata = g_strdup_printf("profile_id=%" G_GINT64_FORMAT "&status=%s&post_form_id=%s",
 				fba->uid, status_tmp, fba->post_form_id);
 		g_free(status_tmp);
 	}
 	else
-		postdata = g_strdup_printf("profile_id=%d&clear=1&post_form_id=%s",
+		postdata = g_strdup_printf("profile_id=%" G_GINT64_FORMAT "&clear=1&post_form_id=%s",
 				fba->uid, fba->post_form_id);
 
 	fb_post_or_get(fba, FB_METHOD_POST, NULL, "/updatestatus.php",
@@ -519,23 +567,6 @@ static void fb_buddy_free(PurpleBuddy *b
 	}
 }
 
-static void fb_convo_closed(PurpleConnection *gc, const char *who)
-{
-	FacebookAccount *fba = gc->proto_data;
-	gchar *postdata;
-
-	g_return_if_fail(fba->post_form_id != NULL);
-
-	/* notify server that we closed the chat window */
-	/* close_chat=589039771&window_id=3168919846&
-	 * post_form_id=c258fe42460c7e8b61e242a37ef05afc */
-	postdata = g_strdup_printf("close_chat=%s&post_form_id=%s", who,
-			fba->post_form_id);
-	fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/chat/settings.php",
-			postdata, NULL, NULL, FALSE);
-	g_free(postdata);
-}
-
 static GHashTable *fb_get_account_text_table(PurpleAccount *account)
 {
 	GHashTable *table;
@@ -567,7 +598,7 @@ static void fb_set_status_cb(PurplePlugi
 	FacebookAccount *fba = pc->proto_data;
 	gchar *uid_str;
 
-	uid_str = g_strdup_printf("%d", fba->uid);
+	uid_str = g_strdup_printf("%" G_GINT64_FORMAT, fba->uid);
 
 	purple_request_input(pc, NULL, _("Set your Facebook status"),
 			purple_account_get_alias(pc->account), "is ",
@@ -658,7 +689,7 @@ static PurplePluginProtocolInfo prpl_inf
 
 static PurplePluginProtocolInfo prpl_info = {
 	/* options */
-	OPT_PROTO_UNIQUE_CHATNAME,
+	OPT_PROTO_MAIL_CHECK,
 
 	NULL,                   /* user_splits */
 	NULL,                   /* protocol_options */
@@ -705,7 +736,7 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL,                   /* group_buddy */
 	NULL,                   /* rename_group */
 	fb_buddy_free,          /* buddy_free */
-	fb_convo_closed,        /* convo_closed */
+	fb_conversation_closed, /* convo_closed */
 	purple_normalize_nocase,/* normalize */
 	NULL,                   /* set_buddy_icon */
 	NULL,                   /* remove_group */
@@ -731,29 +762,29 @@ static PurplePluginInfo info = {
 
 static PurplePluginInfo info = {
 	PURPLE_PLUGIN_MAGIC,
-	2, /* major_version */
-	3, /* minor version */
-	PURPLE_PLUGIN_PROTOCOL, /* type */
-	NULL, /* ui_requirement */
-	0, /* flags */
-	NULL, /* dependencies */
-	PURPLE_PRIORITY_DEFAULT, /* priority */
-	"prpl-bigbrownchunx-facebookim", /* id */
-	"Facebook", /* name */
-	FACEBOOK_PLUGIN_VERSION, /* version */
-	N_("Facebook Protocol Plugin"), /* summary */
-	N_("Facebook Protocol Plugin"), /* description */
-	"Eion Robb <eionrobb at gmail.com>", /* author */
-	"http://pidgin-facebookchat.googlecode.com/", /* homepage */
-	plugin_load, /* load */
-	plugin_unload, /* unload */
-	NULL, /* destroy */
-	NULL, /* ui_info */
-	&prpl_info, /* extra_info */
-	NULL, /* prefs_info */
-	fb_actions, /* actions */
+	2,						/* major_version */
+	3, 						/* minor version */
+	PURPLE_PLUGIN_PROTOCOL, 			/* type */
+	NULL, 						/* ui_requirement */
+	0, 						/* flags */
+	NULL, 						/* dependencies */
+	PURPLE_PRIORITY_DEFAULT, 			/* priority */
+	FACEBOOK_PLUGIN_ID,				/* id */
+	"Facebook", 					/* name */
+	FACEBOOK_PLUGIN_VERSION, 			/* version */
+	N_("Facebook Protocol Plugin"), 		/* summary */
+	N_("Facebook Protocol Plugin"), 		/* description */
+	"Eion Robb <eionrobb at gmail.com>", 		/* author */
+	"http://pidgin-facebookchat.googlecode.com/",	/* homepage */
+	plugin_load, 					/* load */
+	plugin_unload, 					/* unload */
+	NULL, 						/* destroy */
+	NULL, 						/* ui_info */
+	&prpl_info, 					/* extra_info */
+	NULL, 						/* prefs_info */
+	fb_actions, 					/* actions */
 
-	/* padding */
+							/* padding */
 	NULL,
 	NULL,
 	NULL,
============================================================
--- libpurple/protocols/facebook/libfacebook.h	30723f2d8d98def05c0e4811c6f95f4f5242364d
+++ libpurple/protocols/facebook/libfacebook.h	e5edab36948064137e8888d3aa9da077f34e2589
@@ -21,7 +21,8 @@
 #ifndef LIBFACEBOOK_H
 #define LIBFACEBOOK_H
 
-#define FACEBOOK_PLUGIN_VERSION "1.51"
+#define FACEBOOK_PLUGIN_VERSION "1.53"
+#define FACEBOOK_PLUGIN_ID "prpl-bigbrownchunx-facebookim"
 
 #include <glib.h>
 
@@ -70,9 +71,10 @@
 #	include <zlib.h>
 #endif
 
-#define FB_LAST_MESSAGE_MAX 10
 #define FB_MAX_MSG_RETRY 2
 
+#include <json-glib/json-glib.h>
+
 typedef struct _FacebookAccount FacebookAccount;
 typedef struct _FacebookBuddy FacebookBuddy;
 
@@ -85,16 +87,14 @@ struct _FacebookAccount {
 	GSList *dns_queries;
 	GHashTable *cookie_table;
 	gchar *post_form_id;
-	guint post_form_id_refresh_timer;
-	gint32 uid;
+	gint64 uid;
 	guint buddy_list_timer;
 	guint friend_request_timer;
 	gchar *channel_number;
 	guint message_fetch_sequence;
-	gint64 last_messages[FB_LAST_MESSAGE_MAX];
-	guint16 next_message_pointer;
+	gint64 last_message_time;
 	GSList *resending_messages;
-	GSList *auth_buddies;
+	GHashTable *auth_buddies;
 	GHashTable *hostname_ip_cache;
 	guint notifications_timer;
 	time_t last_messages_download_time;
@@ -109,14 +109,17 @@ struct _FacebookBuddy {
 struct _FacebookBuddy {
 	FacebookAccount *fba;
 	PurpleBuddy *buddy;
-	gint32 uid;
+	gint64 uid;
 	gchar *name;
 	gchar *status;
 	gchar *status_rel_time;
 	gchar *thumb_url;
 };
 
+/* TODO: move util functions into a utils file */
 gchar *fb_strdup_withhtml(const gchar *src);
 gchar *fb_convert_unicode(const gchar *input);
+JsonParser *fb_get_parser(const gchar *data, gsize data_len);
+gint64 fb_time_kludge(int initial_time);
 
 #endif /* LIBFACEBOOK_H */
============================================================
--- libpurple/protocols/facebook/pidgin-facebookchat.rc	c5f4af2b3b3bf3614532c11fbff8e7d901d8b8ca
+++ libpurple/protocols/facebook/pidgin-facebookchat.rc	1254a3c5068a1788a466179ff715a73c2a695c6b
@@ -1,7 +1,7 @@ 1 VERSIONINFO
 
 1 VERSIONINFO
-FILEVERSION 1,51,0,0
-PRODUCTVERSION 1,51,0,0
+FILEVERSION 1,53,0,0
+PRODUCTVERSION 1,53,0,0
 FILEOS 0x40004 // VOS_NT_WINDOWS32
 FILETYPE 0x2 // VFT_DLL
 {
@@ -12,10 +12,10 @@ BLOCK "StringFileInfo"
 		VALUE "CompanyName", "Eion Robb\0"
 		VALUE "FileDescription",  "Facebook Chat plugin for Pidgin\0"
 		VALUE "ProductName", "pidgin-facebookchat\0"
-		VALUE "FileVersion", "1.51\0"
-		VALUE "ProductVersion", "1.51\0"
+		VALUE "FileVersion", "1.53\0"
+		VALUE "ProductVersion", "1.53\0"
 		VALUE "InternalName", "pidgin-facebookchat\0"
-		VALUE "OriginalFilename", "pidgin-facebookchat.dll\0"
+		VALUE "OriginalFilename", "libfacebook.dll\0"
 		VALUE "Comments", "http://pidgin-facebookchat.googlecode.com/\0"
 	}
 }
============================================================
--- libpurple/protocols/facebook/rss.xml	63a62d482440ae47b29631cfb4f7bb866184134c
+++ libpurple/protocols/facebook/rss.xml	29d247d04bd14b07d08d4df36a5456c2d89400bf
@@ -13,6 +13,32 @@
 			<width>48</width><height>48</height>
 		</image>
 		<item>
+			<title>Version 1.53</title>
+			<link>http://code.google.com/p/pidgin-facebookchat/issues/detail?id=24#c46</link>
+			<description><![CDATA[<a href="http://www.pidgin.im">Pidgin 2.5.8</a> is available and so is 1.53 of pidgin-facebookchat.
+			<br/><br/>
+			We've fixed some important things such as no more missing messages, and buddy names working.  You can see all the neat things we've done at:<br/>
+			<a href="http://code.google.com/p/pidgin-facebookchat/wiki/Changelog">http://code.google.com/p/pidgin-facebookchat/wiki/Changelog</a>
+			<br/><br/>
+			Thank you all for using the plugin!  If you feel like helping me pay for my fianc?es $300/month medication bills I'd really appreciate a donation.  Even one or two dollars can go a long way.  You can donate at:<br/>
+			<a href="http://code.google.com/p/pidgin-facebookchat/wiki/Donate">http://code.google.com/p/pidgin-facebookchat/wiki/Donate</a>
+			<br/><br/>
+			Otherwise, go grab the update from the usual place:<br/>
+			<a href="http://code.google.com/p/pidgin-facebookchat/downloads/list">http://code.google.com/p/pidgin-facebookchat/downloads/list</a>]]></description>
+			<pubDate>Mon, 29 June 2009 20:56:20 +1200</pubDate>
+			<guid isPermaLink="true">http://code.google.com/p/pidgin-facebookchat/issues/detail?id=24#c46</guid>
+		</item>
+		<item>
+			<title>Version 1.52</title>
+			<link>http://code.google.com/p/pidgin-facebookchat/issues/detail?id=24#c45</link>
+			<description><![CDATA[Just uploaded version 1.52 which fixes an annoying crash sometimes.  Don't forget to download 2.5.7 of Pidgin while you're at it
+			<br/><br/>
+			Download pidgin-facebookchat from:<br/>
+			http://code.google.com/p/pidgin-facebookchat/downloads/list]]></description>
+			<pubDate>Mon, 22 June 2009 19:04:56 +1200</pubDate>
+			<guid isPermaLink="true">http://code.google.com/p/pidgin-facebookchat/issues/detail?id=24#c45</guid>
+		</item>
+		<item>
 			<title>Version 1.51</title>
 			<link>http://code.google.com/p/pidgin-facebookchat/issues/detail?id=24#c44</link>
 			<description><![CDATA[Version 1.51 of the pidgin-facebookchat plugin is available for download.<br/>


More information about the Commits mailing list