adium.1-4: bf4b720f: pidgin-facebookcaht @ 732, which fixes s...

evands at pidgin.im evands at pidgin.im
Thu May 6 12:01:04 EDT 2010


-----------------------------------------------------------------
Revision: bf4b720f9231b395fb51bf1e27440328d46bceb5
Ancestor: 1f5f812e500972cfb805d2cf0b3bc423cf2b7f3f
Author: evands at pidgin.im
Date: 2010-05-06T15:53:42
Branch: im.pidgin.adium.1-4
URL: http://d.pidgin.im/viewmtn/revision/info/bf4b720f9231b395fb51bf1e27440328d46bceb5

Added files:
        libpurple/protocols/facebook/libfbxmpp.c
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_conversation.c
        libpurple/protocols/facebook/fb_friendlist.c
        libpurple/protocols/facebook/fb_info.c
        libpurple/protocols/facebook/fb_managefriends.c
        libpurple/protocols/facebook/fb_messages.c
        libpurple/protocols/facebook/fb_messages.h
        libpurple/protocols/facebook/fb_notifications.c
        libpurple/protocols/facebook/fb_search.c
        libpurple/protocols/facebook/fb_util.c
        libpurple/protocols/facebook/fb_util.h
        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/libfbxmpp.c

ChangeLog: 

pidgin-facebookcaht @ 732, which fixes status message retrieval

-------------- next part --------------
============================================================
--- libpurple/protocols/facebook/libfbxmpp.c	38da058c5179316f6e6428d84ce4449dd1d6c263
+++ libpurple/protocols/facebook/libfbxmpp.c	38da058c5179316f6e6428d84ce4449dd1d6c263
@@ -0,0 +1,584 @@
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ *
+ */
+
+/* libxmpp is the XMPP protocol plugin. It is linked against libjabbercommon,
+ * which may be used to support other protocols (Bonjour) which may need to
+ * share code.
+ */
+
+#include "libfacebook.h"
+#include "fb_util.h"
+#include "fb_connection.h"
+#include "fb_messages.h"
+#include "jabber.h"
+
+#define FACEBOOK_APP_ID "107899262577150"
+#define FACEBOOK_API_KEY "ff26b9e09239e33babaeaf747c778926"
+#define FACEBOOK_SECRET "57a7da14aa16458ab1490fd305b6f545"
+
+#define FACEBOOK_XMPP_PLUGIN_ID "prpl-bigbrownchunx-facebookxmpp"
+
+/*
+http://www.facebook.com/connect/prompt_permissions.php?api_key=ff26b9e09239e33babaeaf747c778926&v=1.0&next=http%3A%2F%2Fwww.facebook.com%2Fconnect%2Flogin_success.html&cancel=http%3A%2F%2Fwww.facebook.com%2Fconnect%2Flogin_failure.html&ext_perm=xmpp_login%2Cread_stream%2Cpublish_stream%2Cread_mailbox%2Coffline_access&channel_url=&display=page&canvas=0&return_session=1&source=login&fbconnect=1&offline_access=0&required=1
+charset_test	?,?,?,?,?,?,?
+fb_dtsg	1Oi8s
+post_form_id	7c5917b2dfc9c709d03c10e0d45b631b
+ext_perm	64,16384,32768,524288,32
+perms_granted	{"32":["800753867"],"64":["800753867"],"16384":["800753867"],"32768":["800753867"],"524288":["800753867"]}
+session_version	
+data_perms_user	0
+data_perms_friends	0
+
+Location	http://www.facebook.com/connect/login_success.html?session=%7B%22session_key%22%3A%22f665d3b753064a328f8c0372-800753867%22%2C%22uid%22%3A800753867%2C%22expires%22%3A0%2C%22secret%22%3A%225b07b330e4d9754b8476927830b462e8%22%2C%22sig%22%3A%22573dd1e21d1f8f22450cba4ea060f3fb%22%7D
+*/
+
+
+
+static void fb_cookie_foreach_cb(gchar *cookie_name,
+								 gchar *cookie_value, GString *str)
+{
+	/* TODO: Need to escape name and value? */
+	g_string_append_printf(str, "%s=%s;", cookie_name, cookie_value);
+}
+
+/**
+ * Serialize the fba->cookie_table hash table to a string.
+ */
+static gchar *fb_cookies_to_string(FacebookAccount *fba)
+{
+	GString *str;
+	
+	str = g_string_new(NULL);
+	
+	g_hash_table_foreach(fba->cookie_table,
+						 (GHFunc)fb_cookie_foreach_cb, str);
+	
+	return g_string_free(str, FALSE);
+}
+
+void fb_authorise_app_cb(FacebookAccount *fba, const gchar *response, gsize len,
+						 gpointer userdata)
+{
+	// session_key is stored in cookies somehow
+	if (len && g_str_equal(response, "Success"))
+	{
+		purple_debug_info("facebookxmpp", "Autorised app cookies: %s", fb_cookies_to_string(fba));
+	}
+}
+
+void fb_authorise_app(FacebookAccount *fba)
+{
+	gchar *postdata;
+	gchar *url;
+	gchar *encoded_charset_test;
+	
+	url = g_strdup_printf("/connect/prompt_permissions.php?api_key=" FACEBOOK_API_KEY "&v=1.0&"
+						  "next=http%%3A%%2F%%2Fwww.facebook.com%%2Fconnect%%2Flogin_success.html&"
+						  "cancel=http%%3A%%2F%%2Fwww.facebook.com%%2Fconnect%%2Flogin_failure.html&"
+						  "ext_perm=xmpp_login%%2Cread_stream%%2Cpublish_stream%%2Cread_mailbox%%2Coffline_access&"
+						  "channel_url=&display=page&canvas=0&return_session=1&source=login&"
+						  "fbconnect=1&offline_access=0&required=1");
+	
+	
+	encoded_charset_test = g_strdup(purple_url_encode("EUR,?,EUR,?,?,?,?"));
+	postdata = g_strdup_printf("charset_test=%s&fb_dtsg=%s&post_form_id=%s&"
+							   "ext_perm=64,16384,32768,524288,32&"
+							   "perms_granted={\"32\":[\"%" G_GINT64_FORMAT "\"],\"64\":[\"%" G_GINT64_FORMAT "\"],\"16384\":[\"%" G_GINT64_FORMAT "\"],\"32768\":[\"%" G_GINT64_FORMAT "\"],\"524288\":[\"%" G_GINT64_FORMAT "\"]}&"
+							   "session_version=&data_perms_user=0&data_perms_friends=0",
+							   encoded_charset_test, (fba->dtsg?fba->dtsg:"(null)"),
+							   (fba->post_form_id?fba->post_form_id:"(null)"),
+							   fba->uid, fba->uid, fba->uid, fba->uid, fba->uid);
+	fb_post_or_get(fba, FB_METHOD_POST, NULL, url, postdata, fb_authorise_app_cb, NULL, FALSE);
+	
+	g_free(url);
+	g_free(postdata);
+	g_free(encoded_charset_test);
+}
+
+gboolean api_request_traverse_func(gchar *key, gchar *value, GString *ret)
+{
+	ret = g_string_append(ret, purple_url_encode(key));
+	ret = g_string_append_c(ret, '=');
+	ret = g_string_append(ret, purple_url_encode(value));
+	ret = g_string_append_c(ret, '&');
+	return FALSE;
+}
+
+static gchar *prepare_api_request(GTree *request_vars, const gchar *method, const gchar *secret)
+{
+	gchar *ret, *sig, *temp;
+	GString *retstring = g_string_new("");
+	
+	g_tree_replace(request_vars, "api_key", g_strdup(FACEBOOK_API_KEY));
+	g_tree_replace(request_vars, "call_id", g_strdup_printf("%d", (int) time(NULL)));
+	if (method)
+	{
+		g_tree_replace(request_vars, "method", g_strdup(method));
+	}
+	g_tree_replace(request_vars, "v", g_strdup("1.0"));
+	g_tree_foreach(request_vars, (GTraverseFunc)api_request_traverse_func, ret);
+	ret = g_string_free(retstring, FALSE);
+	
+	// Compute the 'sig' value
+	sig = g_strdup(ret);
+	purple_str_strip_char(sig, '&');
+	temp = g_strconcat(purple_url_decode(sig), secret, NULL);
+	g_free(sig);
+	sig = fb_md5_encode(temp);
+	g_free(temp);
+	
+	temp = g_strconcat(ret, "sig=", sig, NULL);
+	g_free(ret);
+	g_free(sig);
+	
+	return temp;
+}
+
+void fb_fbconnect_request(FacebookAccount *fba, char *fb_method,
+		GTree *request_vars,
+		FacebookProxyCallbackFunc callback_func, gpointer user_data,
+		gboolean keepalive)
+{
+	gchar *postdata;
+	
+	postdata = prepare_api_request(request_vars, fb_method, 
+								   purple_account_get_string(fba->account, "session_key", ""));
+	
+	fb_post_or_get(fba, FB_METHOD_POST,
+		"api.facebook.com", "/restserver.php", postdata,
+		callback_func, user_data, keepalive);
+	
+	g_free(postdata);
+}
+
+static void handle_jabber_receiving_xmlnode_signal(PurpleConnection *gc, xmlnode **packet, gpointer userdata) 
+{
+	JabberStream *js = userdata;
+	xmlnode *mechnode;
+	
+	if(xmlnode_get_child(*packet, "mechanisms"))
+	{
+		//hack the JabberStream to only use our mech
+		mechnode = xmlnode_get_child(*packet, "mechanisms");
+		xmlnode_insert_data(mechnode, "X-FACEBOOK-PLATFORM", -1);
+		js->auth_mech = facebook_mech;
+	}
+}
+				   
+static void fb_jabber_http_login_cb(FacebookAccount *fba, const gchar *response, gsize len,
+										   gpointer userdata)
+{
+	gchar *user_cookie;
+	
+	purple_connection_update_progress(fba->pc, _("Authenticating"), 2, 3);
+	
+	/* Look for our uid */
+	user_cookie = g_hash_table_lookup(fba->cookie_table, "c_user");
+	if (user_cookie == NULL) 
+	{
+		/*
+		 * Server didn't set the c_user cookie, so we must have given
+		 * them a bad username or password
+		 */
+		purple_connection_error_reason(fba->pc,
+									   PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
+									   _("Incorrect username or password."));
+		return;
+	}
+	fba->uid = atoll(user_cookie);
+	purple_debug_info("facebook", "uid %" G_GINT64_FORMAT "\n", fba->uid);
+
+	fb_get_post_form_id(fba, fb_authorise_app);
+}
+				   
+static void fb_jabber_login(PurpleAccount *account)
+{
+	FacebookAccount *fba;
+	PurpleConnection *pc = purple_account_get_connection(account);
+	JabberStream *js;
+	PurpleStoredImage *image;
+	const gchar *old_username;
+	gchar *new_username;
+
+	purple_account_set_bool(account, "require_tls", FALSE);
+	purple_account_set_bool(account, "old_ssl", FALSE);
+	purple_account_set_bool(account, "auth_plain_in_clear", TRUE);
+	purple_account_set_int(account, "port", 5222);
+	purple_account_set_string(account, "connect_server", "chat.facebook.com");
+	purple_account_set_string(account, "ft_proxies", "");
+	purple_account_set_bool(account, "custom_smileys", FALSE);
+
+	/* Hack the username so that it's a valid XMPP username */
+	old_username = account->username;
+	new_username = g_strconcat(purple_url_encode(old_username), "@", "chat.facebook.com", "/", "Pidgin", NULL);
+	account->username = new_username;
+	js = jabber_stream_new(account);
+	account->username = old_username;
+	g_free(new_username);
+	
+	if (js == NULL)
+		return;
+	
+	fba = g_new0(FacebookAccount, 1);
+	fba->account = account;
+	fba->pc = pc;
+	fba->uid = -1;
+	
+	purple_connection_set_state(pc, PURPLE_CONNECTING);
+	purple_connection_update_progress(pc, _("Connecting"), 1, 3);
+	
+	//we want to hook into the "jabber-receiving-xmlnode" signal to be able to listen to our connect event
+	purple_signal_connect(pc, "jabber-receiving-xmlnode", js,
+						  PURPLE_CALLBACK(handle_jabber_receiving_xmlnode_signal), js);
+	
+	
+	/* Have we authorised access to Facebook on this account? */
+	if (purple_account_get_string(account, "session_key", NULL) == NULL)
+	{
+		fb_do_http_login(fba, fb_jabber_http_login_cb, js);
+		/* Need to wait for the logins to happen before connecting to jabber */
+		return;
+	}
+	
+	jabber_stream_connect(js);
+}
+
+static void fb_jabber_close(PurpleConnection *pc)
+{
+	purple_signals_unregister_by_instance(pc);
+	fb_close(pc);
+	jabber_close(pc);
+}
+
+static PurplePluginProtocolInfo prpl_info =
+{
+	OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME | OPT_PROTO_MAIL_CHECK |
+	OPT_PROTO_PASSWORD_OPTIONAL |
+	OPT_PROTO_SLASH_COMMANDS_NATIVE,
+	NULL,							/* user_splits */
+	NULL,							/* protocol_options */
+	{"png", 32, 32, 96, 96, 0, PURPLE_ICON_SCALE_SEND | PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */
+	fb_list_icon,				/* list_icon */
+	NULL,			/* list_emblems */
+	fb_status_text,				/* status_text */
+	fb_tooltip_text,			/* tooltip_text */
+	jabber_status_types,			/* status_types */
+	jabber_blist_node_menu,			/* blist_node_menu */
+	NULL,				/* chat_info */
+	NULL,		/* chat_info_defaults */
+	fb_jabber_login,					/* login */
+	fb_jabber_close,					/* close */
+	jabber_message_send_im,			/* send_im */
+	NULL,				/* set_info */
+	jabber_send_typing,				/* send_typing */
+	jabber_buddy_get_info,			/* get_info */
+	fb_set_status_p,				/* set_status */
+	jabber_idle_set,				/* set_idle */
+	NULL,							/* change_passwd */
+	fb_add_buddy,		/* add_buddy */
+	NULL,							/* add_buddies */
+	fb_remove_buddy,		/* remove_buddy */
+	NULL,							/* remove_buddies */
+	NULL,							/* add_permit */
+	NULL,				/* add_deny */
+	NULL,							/* rem_permit */
+	NULL,				/* rem_deny */
+	NULL,							/* set_permit_deny */
+	NULL,				/* join_chat */
+	NULL,							/* reject_chat */
+	NULL,			/* get_chat_name */
+	NULL,				/* chat_invite */
+	NULL,				/* chat_leave */
+	NULL,							/* chat_whisper */
+	NULL,		/* chat_send */
+	jabber_keepalive,				/* keepalive */
+	NULL,		/* register_user */
+	NULL,							/* get_cb_info */
+	NULL,							/* get_cb_away */
+	jabber_roster_alias_change,		/* alias_buddy */
+	fb_group_buddy_move,		/* group_buddy */
+	fb_group_rename,		/* rename_group */
+	fb_buddy_free,							/* buddy_free */
+	jabber_convo_closed,			/* convo_closed */
+	jabber_normalize,				/* normalize */
+	NULL,			/* set_buddy_icon */
+	fb_group_remove,							/* remove_group */
+	NULL,	/* get_cb_real_name */
+	NULL,			/* set_chat_topic */
+	NULL,			/* find_blist_chat */
+	NULL,		/* roomlist_get_list */
+	NULL,			/* roomlist_cancel */
+	NULL,							/* roomlist_expand_category */
+	NULL,		/* can_receive_file */
+	NULL,			/* send_file */
+	NULL,				/* new_xfer */
+	NULL,			/* offline_message */
+	NULL,							/* whiteboard_prpl_ops */
+	jabber_prpl_send_raw,			/* send_raw */
+	NULL, /* roomlist_room_serialize */
+	NULL,		/* unregister_user */
+	NULL,			/* send_attention */
+	NULL,			/* attention_types */
+#if PURPLE_MAJOR_VERSION > 2 || PURPLE_MAJOR_VERSION >= 2 && PURPLE_MINOR_VERSION >= 5
+	sizeof(PurplePluginProtocolInfo),       /* struct_size */
+	fb_get_account_text_table, /* get_account_text_table */
+	NULL,          /* initiate_media */
+	NULL,                  /* get_media_caps */
+#else
+	(gpointer) sizeof(PurplePluginProtocolInfo)
+#endif
+};
+
+static gboolean load_plugin(PurplePlugin *plugin)
+{
+	purple_signal_register(plugin, "jabber-receiving-xmlnode",
+			purple_marshal_VOID__POINTER_POINTER, NULL, 2,
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION),
+			purple_value_new_outgoing(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_XMLNODE));
+
+	purple_signal_register(plugin, "jabber-sending-xmlnode",
+			purple_marshal_VOID__POINTER_POINTER, NULL, 2,
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION),
+			purple_value_new_outgoing(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_XMLNODE));
+
+	/*
+	 * Do not remove this or the plugin will fail. Completely. You have been
+	 * warned!
+	 */
+	purple_signal_connect_priority(plugin, "jabber-sending-xmlnode",
+			plugin, PURPLE_CALLBACK(jabber_send_signal_cb),
+			NULL, PURPLE_SIGNAL_PRIORITY_HIGHEST);
+
+	purple_signal_register(plugin, "jabber-sending-text",
+			     purple_marshal_VOID__POINTER_POINTER, NULL, 2,
+			     purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION),
+			     purple_value_new_outgoing(PURPLE_TYPE_STRING));
+
+	purple_signal_register(plugin, "jabber-receiving-message",
+			purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER_POINTER,
+			purple_value_new(PURPLE_TYPE_BOOLEAN), 6,
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION),
+			purple_value_new(PURPLE_TYPE_STRING), /* type */
+			purple_value_new(PURPLE_TYPE_STRING), /* id */
+			purple_value_new(PURPLE_TYPE_STRING), /* from */
+			purple_value_new(PURPLE_TYPE_STRING), /* to */
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_XMLNODE));
+
+	purple_signal_register(plugin, "jabber-receiving-iq",
+			purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER,
+			purple_value_new(PURPLE_TYPE_BOOLEAN), 5,
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION),
+			purple_value_new(PURPLE_TYPE_STRING), /* type */
+			purple_value_new(PURPLE_TYPE_STRING), /* id */
+			purple_value_new(PURPLE_TYPE_STRING), /* from */
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_XMLNODE));
+
+	purple_signal_register(plugin, "jabber-watched-iq",
+			purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER,
+			purple_value_new(PURPLE_TYPE_BOOLEAN), 5,
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION),
+			purple_value_new(PURPLE_TYPE_STRING), /* type */
+			purple_value_new(PURPLE_TYPE_STRING), /* id */
+			purple_value_new(PURPLE_TYPE_STRING), /* from */
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_XMLNODE)); /* child */
+
+	/* Modifying these? Look at jabber_init_plugin for the ipc versions */
+	purple_signal_register(plugin, "jabber-register-namespace-watcher",
+			purple_marshal_VOID__POINTER_POINTER,
+			NULL, 2,
+			purple_value_new(PURPLE_TYPE_STRING),  /* node */
+			purple_value_new(PURPLE_TYPE_STRING)); /* namespace */
+
+	purple_signal_register(plugin, "jabber-unregister-namespace-watcher",
+			purple_marshal_VOID__POINTER_POINTER,
+			NULL, 2,
+			purple_value_new(PURPLE_TYPE_STRING),  /* node */
+			purple_value_new(PURPLE_TYPE_STRING)); /* namespace */
+
+	purple_signal_connect(plugin, "jabber-register-namespace-watcher",
+			plugin, PURPLE_CALLBACK(jabber_iq_signal_register), NULL);
+	purple_signal_connect(plugin, "jabber-unregister-namespace-watcher",
+			plugin, PURPLE_CALLBACK(jabber_iq_signal_unregister), NULL);
+
+	purple_signal_register(plugin, "jabber-receiving-presence",
+			purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER,
+			purple_value_new(PURPLE_TYPE_BOOLEAN), 4,
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION),
+			purple_value_new(PURPLE_TYPE_STRING), /* type */
+			purple_value_new(PURPLE_TYPE_STRING), /* from */
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_XMLNODE));
+
+	return TRUE;
+}
+
+static gboolean unload_plugin(PurplePlugin *plugin)
+{
+	purple_signals_unregister_by_instance(plugin);
+
+	/* reverse order of init_plugin */
+	jabber_data_uninit();
+	jabber_si_uninit();
+	jabber_ibb_uninit();
+	/* PEP things should be uninit via jabber_pep_uninit, not here */
+	jabber_pep_uninit();
+	jabber_caps_uninit();
+	jabber_iq_uninit();
+
+	jabber_unregister_commands();
+
+	/* Stay on target...stay on target... Almost there... */
+	jabber_uninit_plugin(plugin);
+
+	return TRUE;
+}
+
+static PurplePluginInfo info =
+{
+	PURPLE_PLUGIN_MAGIC,
+	2,
+	3,
+	PURPLE_PLUGIN_PROTOCOL,                             /**< type           */
+	NULL,                                             /**< ui_requirement */
+	0,                                                /**< flags          */
+	NULL,                                             /**< dependencies   */
+	PURPLE_PRIORITY_DEFAULT,                            /**< priority       */
+
+	FACEBOOK_XMPP_PLUGIN_ID,                                    /**< id             */
+	"Facebook (XMPP)", 					/* 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 */
+
+	load_plugin,                                      /**< load           */
+	unload_plugin,                                    /**< unload         */
+	NULL,                                             /**< destroy        */
+
+	NULL,                                             /**< ui_info        */
+	&prpl_info,                                       /**< extra_info     */
+	NULL,                                             /**< prefs_info     */
+	fb_actions,
+
+	/* padding */
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+
+static JabberSaslState
+fb_facebook_mech_start(JabberStream *js, xmlnode *packet, xmlnode **response,
+                 char **error)
+{
+	xmlnode *auth = xmlnode_new("auth");
+	xmlnode_set_namespace(auth, NS_XMPP_SASL);
+	xmlnode_set_attrib(auth, "mechanism", "X-FACEBOOK-PLATFORM");
+
+	*response = auth;
+	return JABBER_SASL_STATE_CONTINUE;
+}
+
+/* Parts of this algorithm are inspired by stuff in libgsasl */
+static GHashTable* parse_challenge(const char *challenge)
+{
+	GHashTable *ret = g_hash_table_new_full(g_str_hash, g_str_equal,
+			g_free, g_free);
+	
+	return ret;
+}
+
+static JabberSaslState
+fb_facebook_handle_challenge(JabberStream *js, xmlnode *packet,
+                            xmlnode **response, char **msg)
+{
+	xmlnode *reply = NULL;
+	char *enc_in = xmlnode_get_data(packet);
+	char *dec_in;
+	char *enc_out;
+	GHashTable *parts;
+	JabberSaslState state = JABBER_SASL_STATE_CONTINUE;
+	GTree *response_tree;
+	FacebookAccount *fba;
+
+	if (!enc_in) {
+		*msg = g_strdup(_("Invalid response from server"));
+		return JABBER_SASL_STATE_FAIL;
+	}
+
+	dec_in = (char *)purple_base64_decode(enc_in, NULL);
+	purple_debug_misc("jabber", "decoded challenge (%"
+			G_GSIZE_FORMAT "): %s\n", strlen(dec_in), dec_in);
+			
+	parts = parse_challenge(dec_in);
+	
+	response_tree = g_tree_new_full((GCompareDataFunc)strcmp, NULL, NULL, g_free);
+	g_tree_insert(response_tree, "nonce", g_strdup(g_hash_table_lookup(parts, "nonce")));
+	g_tree_insert(response_tree, "session_key", g_strdup(purple_account_get_string(js->account, "session_key", "")));
+	
+	//method, api_key, call_id, sig, v already sent
+	prepare_api_request(response_tree, g_hash_table_lookup(parts, "method"), FACEBOOK_SECRET);
+	
+	g_hash_table_destroy(parts);
+}
+
+static JabberSaslMech facebook_mech = {
+	20, /* priority - needs to be more important than the DIGEST-MD5 priority */
+	"X-FACEBOOK-PLATFORM", /* name */
+	fb_facebook_mech_start,
+	fb_facebook_handle_challenge, /* handle_challenge */
+	NULL, /* handle_success */
+	NULL, /* handle_failure */
+	NULL  /* dispose */
+};
+
+JabberSaslMech *fb_auth_get_facebook_mech(void)
+{
+	return &facebook_mech;
+}
+
+static void
+init_plugin(PurplePlugin *plugin)
+{
+	
+	auth_mechs = g_slist_insert_sorted(auth_mechs, fb_auth_get_facebook_mech(), compare_mech);
+
+
+	my_protocol = plugin;
+	jabber_init_plugin(plugin);
+
+	purple_prefs_remove("/plugins/prpl/facebook");
+	jabber_register_commands();
+
+	/* reverse order of unload_plugin */
+	jabber_iq_init();
+	jabber_caps_init();
+	/* PEP things should be init via jabber_pep_init, not here */
+	jabber_pep_init();
+	jabber_data_init();
+
+	jabber_si_init();
+}
+
+
+PURPLE_INIT_PLUGIN(facebookxmpp, init_plugin, info);
============================================================
--- libpurple/protocols/facebook/facebook.nsi	909394612268d37159a9853b011b2d14d25bceca
+++ libpurple/protocols/facebook/facebook.nsi	97ea60c5d4a321ff9d8ba51c38f2f940518b8b7f
@@ -6,7 +6,7 @@ SetCompress off
 ; todo: SetBrandingImage
 ; HM NIS Edit Wizard helper defines
 !define PRODUCT_NAME "pidgin-facebookchat"
-!define PRODUCT_VERSION "1.64"
+!define PRODUCT_VERSION "1.65"
 !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	3574e613239518dc6b50c192632e0b956e2e3635
+++ libpurple/protocols/facebook/fb_blist.c	cb0dd67c0da50e91b4b2c27f0008ac45f385afce
@@ -38,7 +38,7 @@ static void set_buddies_offline(PurpleBu
 	}
 }
 
-static void buddy_icon_cb(FacebookAccount *fba, gchar *data, gsize data_len,
+static void buddy_icon_cb(FacebookAccount *fba, const gchar *data, gsize data_len,
 		gpointer user_data)
 {
 	gchar *buddyname;
@@ -110,23 +110,18 @@ static GList *get_buddies(FacebookAccoun
 	return buddies;
 }
 
-static void process_buddy_icon(FacebookAccount *fba, PurpleBuddy *buddy,
-	JsonObject *userInfo)
+static void process_buddy_icon(FacebookAccount *fba, FacebookBuddy *fbuddy,
+	const gchar *buddy_icon_url)
 {
-	FacebookBuddy *fbuddy;
-	gchar *buddy_icon_url;
+	PurpleBuddy *buddy;
 	gchar *icon_host;
 	gchar *icon_path, *real_path;
 	gchar *search_tmp;
 
-	fbuddy = buddy->proto_data;
+	buddy = fbuddy->buddy;
 	
-	/* Set the buddy icon (if it hasn't changed) */
-	buddy_icon_url = g_strdup(json_node_get_string(json_object_get_member(
-			userInfo, "thumbSrc")));
 	/* Seperate the URL into pieces */
 	purple_url_parse(buddy_icon_url, &icon_host, NULL, &icon_path, NULL, NULL);
-	g_free(buddy_icon_url);
 	
 	if (icon_path != NULL && icon_path[0] != '/')
 	{
@@ -155,7 +150,13 @@ static void process_buddy_icon(FacebookA
 			/* bigger icon at /profile6/1845/74/n800753867_2878.jpg */
 			search_tmp = strstr(icon_path, "/q");
 			if (search_tmp)
-				*(search_tmp + 1) = 'n';			
+				*(search_tmp + 1) = 'n';
+			else
+			{
+				search_tmp = strstr(icon_path, "_q.jpg");
+				if (search_tmp)
+					*(search_tmp + 1) = 'n';
+			}
 			purple_debug_info("facebook", "buddy %s has a new buddy icon at http://%s%s\n", buddy->name, icon_host, icon_path);
 			/* Fetch their icon */
 			fb_post_or_get(fba, FB_METHOD_GET, icon_host,
@@ -215,10 +216,13 @@ static void process_buddies(FacebookAcco
 	for (cur = buddies; cur != NULL; cur = cur->next)
 	{
 		PurpleBuddy *buddy;
+		FacebookBuddy *fbuddy;
 
 		buddy = (PurpleBuddy *)cur->data;
+		fbuddy = buddy->proto_data;
 
-		process_buddy_icon(fba, buddy, userInfo);
+		process_buddy_icon(fba, fbuddy, json_node_get_string(
+			json_object_get_member(userInfo, "thumbSrc")));
 
 		purple_presence_set_idle(purple_buddy_get_presence(buddy),
 				idle, 0);
@@ -272,7 +276,7 @@ static void process_notifications(Facebo
 	}
 }
 
-static void got_status_stream_cb(FacebookAccount *fba, gchar *data,
+static void got_status_stream_cb(FacebookAccount *fba, const gchar *data,
 		gsize data_len, gpointer userdata)
 {
 	gchar *error = NULL;
@@ -317,7 +321,7 @@ static void got_status_stream_cb(Faceboo
 			objnode, "html"));
 	//purple_debug_misc("facebook", "html data\n%s\n", html);
 	
-	messages = g_strsplit(html, "/h3>", -1);
+	messages = g_strsplit(html, "/h6>", -1);
 	for(i = 0; messages[i]; i++)
 	{
 		message = messages[i];
@@ -389,7 +393,7 @@ static void got_status_stream_cb(Faceboo
 	json_parser_free(parser);
 }
 
-static void got_buddy_list_cb(FacebookAccount *fba, gchar *data,
+static void got_buddy_list_cb(FacebookAccount *fba, const gchar *data,
 		gsize data_len, gpointer userdata)
 {
 	GSList *buddies_list;
@@ -531,6 +535,85 @@ gboolean fb_get_buddy_list(gpointer data
 	return TRUE;
 }
 
+static void got_full_buddy_list(FacebookAccount *fba, const gchar *data,
+		gsize data_len, gpointer userdata)
+{
+	int i;
+	PurpleGroup *fb_group;
+	JsonParser *parser;
+	gchar *error = NULL;
+	JsonObject *objnode, *node;
+	JsonArray *entries;
+	
+	purple_debug_info("facebook", "parsing full buddy list\n");
+
+	if (fba == NULL)
+		return;
+
+	parser = fb_get_parser(data, data_len);
+	if (parser == NULL)
+		return;
+
+	purple_debug_misc("facebook", "full buddy list\n%s\n", data);
+
+	objnode = fb_get_json_object(parser, &error);
+	if (!json_object_has_member(objnode, "payload"))
+	{
+		json_parser_free(parser);
+		return;
+	}
+	objnode = json_node_get_object(json_object_get_member(
+			objnode, "payload"));
+	if (!json_object_has_member(objnode, "entries"))
+	{
+		json_parser_free(parser);
+		return;
+	}
+	entries = json_node_get_array(json_object_get_member(
+			objnode, "entries"));
+			
+	fb_group = purple_find_group(DEFAULT_GROUP_NAME);
+	if (fb_group == NULL)
+	{
+		fb_group = purple_group_new(DEFAULT_GROUP_NAME);
+		purple_blist_add_group(fb_group, NULL);
+	}
+	for(i = 0; i < json_array_get_length(entries); i++)
+	{
+		node = json_node_get_object(json_array_get_element(entries, i));
+		const gchar *type = json_node_get_string(json_object_get_member(node, "ty"));
+		if (type[0] != 'u')
+			continue;
+		const gchar *uid = json_node_get_string(json_object_get_member(node, "i"));
+		if (purple_find_buddy(fba->account, uid))
+			continue;
+		
+		const gchar *name = json_node_get_string(json_object_get_member(node, "t"));
+		PurpleBuddy *buddy = purple_buddy_new(fba->account, uid, name);
+		purple_blist_add_buddy(buddy, NULL, fb_group, NULL);
+		FacebookBuddy *fbuddy = g_new0(FacebookBuddy, 1);
+		fbuddy->buddy = buddy;
+		fbuddy->fba = fba;
+		fbuddy->uid = atoll(uid);
+		fbuddy->name = g_strdup(name);
+		buddy->proto_data = fbuddy;
+		
+		const gchar *thumb_url = json_node_get_string(json_object_get_member(node, "it"));
+		process_buddy_icon(fba, fbuddy, thumb_url);
+	}
+
+	json_parser_free(parser);	
+}
+
+void fb_get_full_buddy_list(FacebookAccount *fba)
+{
+	gchar *url;
+	
+	url = g_strdup_printf("/ajax/typeahead_search.php?u=%" G_GINT64_FORMAT "&__a=1", fba->uid);
+	fb_post_or_get(fba, FB_METHOD_GET, NULL, url, NULL, got_full_buddy_list, NULL, FALSE);
+	g_free(url);
+}
+
 void fb_blist_poke_buddy(PurpleBlistNode *node, gpointer data)
 {
 	PurpleBuddy *buddy;
@@ -594,6 +677,7 @@ void fb_blist_init(FacebookAccount *fba)
 	fba->buddy_list_timer = purple_timeout_add_seconds(60,
 			fb_get_buddy_list, fba);
 
+	fb_get_full_buddy_list(fba);
 }
 
 void fb_blist_destroy(FacebookAccount *fba)
============================================================
--- libpurple/protocols/facebook/fb_blist.h	e77ea2b71a92a022052a1083631d810b540385b4
+++ libpurple/protocols/facebook/fb_blist.h	a663d54c3277085efa235c39cbc950faf816c05c
@@ -32,4 +32,6 @@ void fb_blist_destroy(FacebookAccount *f
 void fb_blist_init(FacebookAccount *fba);
 void fb_blist_destroy(FacebookAccount *fba);
 
+void fb_get_full_buddy_list(FacebookAccount *fba);
+
 #endif /* FACEBOOK_BLIST_H */
============================================================
--- libpurple/protocols/facebook/fb_connection.c	c1ecafbe42cd0342e8d0ab24a052e0258c85e3d5
+++ libpurple/protocols/facebook/fb_connection.c	51f2c6c9baa639ede1d17c752fd02b4ca7ba8187
@@ -21,6 +21,7 @@ static void fb_attempt_connection(Facebo
 #include "fb_connection.h"
 
 static void fb_attempt_connection(FacebookConnection *);
+static void fb_next_connection(FacebookAccount *fba);
 
 #ifdef HAVE_ZLIB
 #include <zlib.h>
@@ -98,6 +99,8 @@ static gchar *fb_gunzip(const guchar *gz
 
 	return g_string_free(output_string, FALSE);
 }
+#else /* !HAVE_ZLIB */
+#warning You really want to compile with -DHAVE_ZLIB
 #endif
 
 void fb_connection_destroy(FacebookConnection *fbconn)
@@ -227,10 +230,12 @@ static void fb_post_or_get_readdata_cb(g
 		PurpleInputCondition cond)
 {
 	FacebookConnection *fbconn;
+	FacebookAccount *fba;
 	gchar buf[4096];
 	ssize_t len;
 
 	fbconn = data;
+	fba = fbconn->fba;
 
 	if (fbconn->method & FB_METHOD_SSL) {
 		len = purple_ssl_read(fbconn->ssl_conn,
@@ -290,6 +295,8 @@ static void fb_post_or_get_readdata_cb(g
 	fb_connection_process_data(fbconn);
 
 	fb_connection_destroy(fbconn);
+	
+	fb_next_connection(fba);
 }
 
 static void fb_post_or_get_ssl_readdata_cb (gpointer data,
@@ -593,9 +600,25 @@ void fb_post_or_get(FacebookAccount *fba
 	fbconn->fd = -1;
 	fbconn->connection_keepalive = keepalive;
 	fbconn->request_time = time(NULL);
-	fba->conns = g_slist_prepend(fba->conns, fbconn);
+	
+	g_queue_push_head(fba->waiting_conns, fbconn);
+	fb_next_connection(fba);
+}
 
-	fb_attempt_connection(fbconn);
+static void fb_next_connection(FacebookAccount *fba)
+{
+	FacebookConnection *fbconn;
+	
+	g_return_if_fail(fba != NULL);	
+	
+	if (!g_queue_is_empty(fba->waiting_conns))
+	{
+		if(g_slist_length(fba->conns) < FB_MAX_CONNECTIONS)
+		{
+			fbconn = g_queue_pop_tail(fba->waiting_conns);
+			fb_attempt_connection(fbconn);
+		}
+	}
 }
 
 static void fb_attempt_connection(FacebookConnection *fbconn)
@@ -621,6 +644,8 @@ static void fb_attempt_connection(Facebo
 	 * runs at blinding speed.  Slow it down. */
 	/* TODO/FIXME: this doesn't retry properly on non-ssl connections */
 #endif
+	
+	fba->conns = g_slist_prepend(fba->conns, fbconn);
 
 	if (fbconn->method & FB_METHOD_SSL) {
 		fbconn->ssl_conn = purple_ssl_connect(fba->account, fbconn->hostname,
============================================================
--- libpurple/protocols/facebook/fb_conversation.c	74b428320820601cd596b8496f17af90b5631045
+++ libpurple/protocols/facebook/fb_conversation.c	2dece593f09b3a8e8a8f18a0b26daad0b9a52240
@@ -91,7 +91,7 @@ void fb_conversation_handle_message(Face
  * HISTORY CODE                                                              *
  *****************************************************************************/
 
-static void fb_history_fetch_cb(FacebookAccount *fba, gchar *data,
+static void fb_history_fetch_cb(FacebookAccount *fba, const gchar *data,
 	gsize data_len, gpointer userdata)
 {
 	JsonParser *parser;
============================================================
--- libpurple/protocols/facebook/fb_friendlist.c	008d6195eb30a403d41c4755c98c5402de4fac31
+++ libpurple/protocols/facebook/fb_friendlist.c	f79866a79682445e0b77bd3d7cfaf014817cfc97
@@ -81,7 +81,7 @@ static void handle_move_request(Facebook
 	g_free(request);
 }
 
-static void create_list_cb(FacebookAccount *fba, gchar *data,
+static void create_list_cb(FacebookAccount *fba, const gchar *data,
 	gsize data_len, gpointer userdata)
 {
 	// NOTE: this method can also be used for movements between
============================================================
--- libpurple/protocols/facebook/fb_info.c	ddcf349b1b8238ecd2ee0a9729a599b8d73fafda
+++ libpurple/protocols/facebook/fb_info.c	67afa65f38125540d235bda3b66cd7dceb54ddd1
@@ -49,7 +49,7 @@ static gchar *fb_remove_useless_stripped
 	return output;
 }
 
-static void fb_get_info_cb(FacebookAccount *fba, gchar *data, gsize data_len, gpointer user_data)
+static void fb_get_info_cb(FacebookAccount *fba, const gchar *data, gsize data_len, gpointer user_data)
 {
 	PurpleNotifyUserInfo *user_info;
 	PurpleBuddyIcon *buddy_icon;
============================================================
--- libpurple/protocols/facebook/fb_managefriends.c	711a945a595b2c353cfa8991e9546b7b90828048
+++ libpurple/protocols/facebook/fb_managefriends.c	46d4a0dc588110af5c4d9ceef4cf8369af7e8586
@@ -77,7 +77,7 @@ static void fb_auth_reject_cb(gpointer d
 	g_free(buddy_uid);
 }
 
-static void fb_check_friend_request_cb(FacebookAccount *fba, gchar *data,
+static void fb_check_friend_request_cb(FacebookAccount *fba, const gchar *data,
 		gsize data_len, gpointer user_data)
 {
 	const char *uid_pre_text = "class=\"confirm\" id=\"friend_connect_";
@@ -89,7 +89,7 @@ static void fb_check_friend_request_cb(F
 	gchar *msg;
 	gchar *msg_plain;
 	FacebookBuddy *buddy;
-	gchar *search_start = data;
+	const gchar *search_start = data;
 
 	g_return_if_fail(data_len > 0);
 	g_return_if_fail(data != NULL);
============================================================
--- libpurple/protocols/facebook/fb_messages.c	9e4b7c098e5407d1d6eafbf51c9f3cc4773e2a24
+++ libpurple/protocols/facebook/fb_messages.c	a68e3d53c5d9556d30ff11a48f4c70fdf56f189a
@@ -40,7 +40,6 @@ static gboolean fb_resend_im_fom(Faceboo
 
 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 FacebookOutgoingMessage *fb_msg_create(FacebookAccount *fba)
 {
@@ -150,7 +149,7 @@ static void parse_new_messages(PurpleCon
 	}
 }
 								  
-static void got_new_messages(FacebookAccount *fba, gchar *data,
+static void got_new_messages(FacebookAccount *fba, const gchar *data,
 		gsize data_len, gpointer userdata)
 {
 	JsonParser *parser;
@@ -258,7 +257,7 @@ static void got_new_messages(FacebookAcc
  * called ONCE and only ONCE.  After that the timers will take care of
  * themselves until final cleanup.
  */
-static gboolean fb_get_new_messages(FacebookAccount *fba)
+gboolean fb_get_new_messages(FacebookAccount *fba)
 {
 	time_t now;
 	gchar *fetch_url;
@@ -304,7 +303,7 @@ static gboolean fb_get_new_messages(Face
 	return FALSE;
 }
 
-static void fb_send_im_cb(FacebookAccount *fba, gchar *data, gsize data_len, gpointer user_data)
+static void fb_send_im_cb(FacebookAccount *fba, const gchar *data, gsize data_len, gpointer user_data)
 {
 	FacebookOutgoingMessage *msg = user_data;
 	JsonParser *parser;
@@ -405,7 +404,7 @@ int fb_send_im(PurpleConnection *pc, con
 	return 1;
 }
 
-void got_reconnect_json(FacebookAccount *fba, gchar *data, gsize data_len, gpointer userdata)
+void got_reconnect_json(FacebookAccount *fba, const gchar *data, gsize data_len, gpointer userdata)
 {
 	JsonParser *parser;
 	JsonObject *objnode;
@@ -462,7 +461,7 @@ gboolean fb_reconnect(FacebookAccount *f
 	return FALSE;
 }
 
-static void got_form_id_page(FacebookAccount *fba, gchar *data, gsize data_len, gpointer userdata)
+static void got_form_id_page(FacebookAccount *fba, const gchar *data, gsize data_len, gpointer userdata)
 {
 	const gchar *start_text = "id=\"post_form_id\" name=\"post_form_id\" value=\"";
 	const gchar *dtsg_start = "fb_dtsg:\"";
@@ -471,6 +470,7 @@ static void got_form_id_page(FacebookAcc
 	gchar *post_form_id;
 	gchar *channel = NULL;
 	gchar *tmp = NULL;
+	FacebookFunc callback;
 	
 	/* NULL data crashes on Windows */
 	if (data == NULL)
@@ -516,22 +516,16 @@ static void got_form_id_page(FacebookAcc
 		g_free(fba->channel_number);
 		fba->channel_number = channel;
 	}
-
-	tmp = g_strdup_printf("visibility=true&post_form_id=%s", post_form_id);
-	fb_post_or_get(fba, FB_METHOD_POST, "apps.facebook.com", "/ajax/chat/settings.php", tmp, NULL, NULL, FALSE);
-	g_free(tmp);
 	
-	if (channel == NULL)
+	if (userdata)
 	{
-		/* Grab new channel number */
-		fb_reconnect(fba);
-	} else {
-		fb_get_new_messages(fba);
+		callback = userdata;
+		callback(fba);
 	}
 }
 
-gboolean fb_get_post_form_id(FacebookAccount *fba)
+gboolean fb_get_post_form_id(FacebookAccount *fba, FacebookFunc callback)
 {
-	fb_post_or_get(fba, FB_METHOD_GET, NULL, "/presence/popout.php", NULL, got_form_id_page, NULL, FALSE);
+	fb_post_or_get(fba, FB_METHOD_GET, NULL, "/presence/popout.php", NULL, got_form_id_page, callback, FALSE);
 	return FALSE;
 }
============================================================
--- libpurple/protocols/facebook/fb_messages.h	aaab76c0a6d161f4e6e522833e4aae633a952997
+++ libpurple/protocols/facebook/fb_messages.h	7ecfce3f7074f5876a23403922ec0ae691eaedde
@@ -23,11 +23,13 @@
 
 #include "libfacebook.h"
 
-gboolean fb_get_post_form_id(FacebookAccount *fba);
+gboolean fb_get_post_form_id(FacebookAccount *fba, FacebookFunc callback);
 gboolean fb_reconnect(FacebookAccount *fba);
 int fb_send_im(PurpleConnection *pc, const gchar *who, const gchar *message,
 		PurpleMessageFlags flags);
 
 void fb_cancel_resending_messages(FacebookAccount *fba);
 
+gboolean fb_get_new_messages(FacebookAccount *fba);
+
 #endif /* FACEBOOK_MESSAGES_H */
============================================================
--- libpurple/protocols/facebook/fb_notifications.c	4dfffc8a8452bc56f856c94b2dec1e27d6287ca4
+++ libpurple/protocols/facebook/fb_notifications.c	3358d387fd6f063dd96182632bf38084f62bdcf3
@@ -21,7 +21,7 @@
 #include "fb_notifications.h"
 #include "fb_connection.h"
 
-static void fb_got_notifications_cb(FacebookAccount *fba, gchar *url_text, gsize len, gpointer userdata)
+static void fb_got_notifications_cb(FacebookAccount *fba, const gchar *url_text, gsize len, gpointer userdata)
 {
 	gchar *salvaged;
 	time_t last_fetch_time;
@@ -138,7 +138,7 @@ static void fb_got_notifications_cb(Face
 	}
 }
 
-static void find_feed_url_cb(FacebookAccount *fba, gchar *data, gsize data_len, gpointer userdata)
+static void find_feed_url_cb(FacebookAccount *fba, const gchar *data, gsize data_len, gpointer userdata)
 {
 	const gchar *search_string = "/feeds/notifications.php";
 	gchar *feed_url;
============================================================
--- libpurple/protocols/facebook/fb_search.c	7e2e0235ae16731b82bb781e8e1d05c3b78a4c5a
+++ libpurple/protocols/facebook/fb_search.c	5fe1103a70f6d161889aa7658b41b35399fac8a0
@@ -42,12 +42,13 @@ static void fb_searchresults_info_buddy(
 		fb_get_info(pc, g_list_nth_data(row, 0));
 }
 
-static void fb_found_friends(FacebookAccount *fba, gchar *data,
+static void fb_found_friends(FacebookAccount *fba, const gchar *data,
 		gsize data_len, gpointer user_data)
 {
 	PurpleNotifySearchResults *results;
 	PurpleNotifySearchColumn *column;
-	gchar *id, *tmp, *stripped, *last_id_pos = 0, *id_pos = data;
+	gchar *id, *tmp, *stripped;
+	const gchar *id_pos = data, *last_id_pos = 0;
 	gchar *search_term = user_data;
 	const gchar *id_search_term =
 			"facebook.com/inbox/?compose&amp;id="; /* " */
============================================================
--- libpurple/protocols/facebook/fb_util.c	db25bbe26ed405a613ac050b45a0567df3ee5aa8
+++ libpurple/protocols/facebook/fb_util.c	892bc0b45bd3472256d7c28b4e3952a760abbabd
@@ -283,3 +283,19 @@ gchar *fb_replace_styled_text(const gcha
 #endif /*__ARM_EABI__*/
 }
 
+gchar *fb_md5_encode(const gchar *string)
+{
+	PurpleCipher *cipher;
+	PurpleCipherContext *context;
+	gchar md5Hash[33];
+	
+	cipher = purple_ciphers_find_cipher("md5");
+	context = purple_cipher_context_new(cipher, NULL);
+
+	purple_cipher_context_append(context, (guchar *)string, strlen(string));
+	purple_cipher_context_digest_to_str(context, sizeof(md5Hash), md5Hash, NULL);
+	purple_cipher_context_destroy(context);
+	
+	return g_strdup(md5Hash);
+}
+
============================================================
--- libpurple/protocols/facebook/fb_util.h	97d1d52c6ee49b764654ac3ae448284bfa071c81
+++ libpurple/protocols/facebook/fb_util.h	2b0447d3d889abed3c90b5c633c11edab4179255
@@ -24,6 +24,8 @@
 #include "libfacebook.h"
 #include "fb_json.h"
 
+#include <cipher.h>
+
 JsonParser *fb_get_parser(const gchar *data, gsize data_len);
 JsonObject *fb_get_json_object(JsonParser *parser, char **error_message);
 
@@ -31,6 +33,7 @@ gint64 fb_time_kludge(gint64 initial_tim
 gchar *fb_strdup_withhtml(const gchar *src);
 gchar *fb_convert_unicode(const gchar *input);
 gint64 fb_time_kludge(gint64 initial_time);
+gchar *fb_md5_encode(const gchar *string);
 
 #endif /* FACEBOOK_UTIL_H */
 
============================================================
--- libpurple/protocols/facebook/libfacebook.c	fa11c84086db93bf96b87de14a10d37ddc540995
+++ libpurple/protocols/facebook/libfacebook.c	26b3f5f2fae2cd652f04d3dfd42b1c83525e6c51
@@ -29,7 +29,7 @@
 #include "fb_search.h"
 #include "fb_friendlist.h"
 
-static void fb_login_cb(FacebookAccount *fba, gchar *response, gsize len,
+static void fb_login_cb(FacebookAccount *fba, const gchar *response, gsize len,
 		gpointer userdata);
 static void fb_close(PurpleConnection *pc);
 static void fb_buddy_free(PurpleBuddy *buddy);
@@ -96,6 +96,23 @@ static GList *fb_statuses(PurpleAccount 
 	return types;
 }
 
+void fb_post_form_id_cb(FacebookAccount *fba)
+{
+	gchar *tmp;
+	
+	tmp = g_strdup_printf("visibility=true&post_form_id=%s", fba->post_form_id);
+	fb_post_or_get(fba, FB_METHOD_POST, "apps.facebook.com", "/ajax/chat/settings.php", tmp, NULL, NULL, FALSE);
+	g_free(tmp);
+	
+	if (fba->channel_number == NULL)
+	{
+		/* Grab new channel number */
+		fb_reconnect(fba);
+	} else {
+		fb_get_new_messages(fba);
+	}
+}
+
 static gboolean fb_get_messages_failsafe(FacebookAccount *fba)
 {
 	if (fba->last_messages_download_time < (time(NULL) - (60*5))) {
@@ -103,7 +120,7 @@ static gboolean fb_get_messages_failsafe
 		 * something is probably wrong */
 		purple_debug_warning("facebook",
 				"executing message check failsafe\n");
-		fb_get_post_form_id(fba);
+		fb_get_post_form_id(fba, fb_post_form_id_cb);
 	}
 
 	return TRUE;
@@ -173,7 +190,7 @@ void fb_login_captcha_ok_cb(PurpleConnec
 	fba->captcha_session = NULL;
 }
 
-static void fb_login_captcha_image_cb(FacebookAccount *fba, gchar *response, 
+static void fb_login_captcha_image_cb(FacebookAccount *fba, const gchar *response, 
 		gsize len, gpointer userdata)
 {
 	PurpleRequestFields *fields;
@@ -200,7 +217,7 @@ static void fb_login_captcha_image_cb(Fa
 	);
 }
 
-static void fb_login_captcha_cb(FacebookAccount *fba, gchar *response, 
+static void fb_login_captcha_cb(FacebookAccount *fba, const gchar *response, 
 		gsize len, gpointer userdata)
 {
 	const gchar *challenge_start = "challenge : '";
@@ -220,7 +237,7 @@ static void fb_login_captcha_cb(Facebook
 	}
 }
 
-static void fb_login_cb(FacebookAccount *fba, gchar *response, gsize len,
+static void fb_login_cb(FacebookAccount *fba, const gchar *response, gsize len,
 		gpointer userdata)
 {
 	gchar *user_cookie;
@@ -305,7 +322,7 @@ static void fb_login_cb(FacebookAccount 
 	purple_connection_set_state(fba->pc, PURPLE_CONNECTED);
 
 	/* This will kick off our long-poll message retrieval loop */
-	fb_get_post_form_id(fba);
+	fb_get_post_form_id(fba, &fb_post_form_id_cb);
 	fb_check_friend_requests(fba);
 
 	/* periodically check for people adding you to their facebook friend list */
@@ -337,13 +354,62 @@ static void fb_login_cb(FacebookAccount 
 	fb_conversation_init(fba);
 }
 
-static void fb_login(PurpleAccount *account)
+gboolean fb_do_http_login(FacebookAccount *fba, 
+		FacebookProxyCallbackFunc callback_func, gpointer user_data)
 {
-	FacebookAccount *fba;
 	gchar *postdata, *encoded_username, *encoded_password, *encoded_charset_test;
 	const gchar* const *languages;
 	const gchar *locale;
 	
+	if (fba == NULL)
+		return FALSE;
+	
+	/* Error localized in libpurple jabber.c */
+	if (!purple_ssl_is_supported()) {
+		purple_connection_error_reason (fba->pc,
+										PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT,
+										_("Server requires TLS/SSL for login.  No TLS/SSL support found."));
+		return FALSE;
+	}
+	
+	if (fba->cookie_table == NULL)
+		fba->cookie_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+	if (fba->hostname_ip_cache == NULL)
+		fba->hostname_ip_cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+	if (fba->waiting_conns == NULL)
+		fba->waiting_conns = g_queue_new();
+	
+	g_hash_table_replace(fba->cookie_table, g_strdup("test_cookie"), g_strdup("1"));
+	g_hash_table_replace(fba->cookie_table, g_strdup("lsd"), g_strdup("abcde"));
+	
+	encoded_username = g_strdup(purple_url_encode(purple_account_get_username(fba->account)));
+	encoded_password = g_strdup(purple_url_encode(purple_account_get_password(fba->account)));
+	encoded_charset_test = g_strdup(purple_url_encode("EUR,?,EUR,?,?,?,?"));
+	languages = g_get_language_names();
+	locale = languages[0];
+	if (locale == NULL || g_str_equal(locale, "C"))
+		locale = "en_US";
+	
+	postdata = g_strdup_printf("charset_test=%s&locale=%s&email=%s&pass=%s&"
+							   "pass_placeHolder=Password&persistent=1&"
+							   "login=Login&charset_test=%s&lsd=abcde",
+							   encoded_charset_test, locale, encoded_username, 
+							   encoded_password, encoded_charset_test);
+	g_free(encoded_username);
+	g_free(encoded_password);
+	g_free(encoded_charset_test);
+	
+	fb_post_or_get(fba, FB_METHOD_POST | FB_METHOD_SSL, "login.facebook.com",
+				   "/login.php?login_attempt=1&_fb_noscript=1", postdata, callback_func, user_data, FALSE);
+	g_free(postdata);
+	
+	return TRUE;
+}
+
+static void fb_login(PurpleAccount *account)
+{
+	FacebookAccount *fba;
+	
 	/* Create account and initialize state */
 	fba = g_new0(FacebookAccount, 1);
 	fba->account = account;
@@ -359,44 +425,12 @@ static void fb_login(PurpleAccount *acco
 	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"));
-
 	account->gc->proto_data = fba;
 
-	/* Error localized in libpurple jabber.c */
-	if (!purple_ssl_is_supported()) {
-		purple_connection_error_reason (purple_account_get_connection(account),
-				PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT,
-				_("Server requires TLS/SSL for login.  No TLS/SSL support found."));
-		return;
-	}
-
 	purple_connection_set_state(fba->pc, PURPLE_CONNECTING);
 	purple_connection_update_progress(fba->pc, _("Connecting"), 1, 3);
 
-	encoded_username = g_strdup(purple_url_encode(
-			purple_account_get_username(fba->account)));
-	encoded_password = g_strdup(purple_url_encode(
-			purple_account_get_password(fba->account)));
-	encoded_charset_test = g_strdup(purple_url_encode("EUR,?,EUR,?,?,?,?"));
-	languages = g_get_language_names();
-	locale = languages[0];
-	if (locale == NULL || g_str_equal(locale, "C"))
-		locale = "en_US";
-
-	g_hash_table_replace(fba->cookie_table, g_strdup("lsd"), g_strdup("abcde"));
-
-	postdata = g_strdup_printf(
-			"charset_test=%s&locale=%s&email=%s&pass=%s&pass_placeHolder=Password&persistent=1&login=Login&charset_test=%s&lsd=abcde",
-			encoded_charset_test, locale, encoded_username, encoded_password, encoded_charset_test);
-	g_free(encoded_username);
-	g_free(encoded_password);
-	g_free(encoded_charset_test);
-
-	fb_post_or_get(fba, FB_METHOD_POST | FB_METHOD_SSL, "login.facebook.com",
-			"/login.php?login_attempt=1&_fb_noscript=1", postdata, fb_login_cb, NULL, FALSE);
-	g_free(postdata);
+	fb_do_http_login(fba, fb_login_cb, NULL);
 }
 
 static void fb_close(PurpleConnection *pc)
@@ -438,7 +472,14 @@ static void fb_close(PurpleConnection *p
 	if (fba->perpetual_messages_timer) {
 		purple_timeout_remove(fba->perpetual_messages_timer);
 	}
-
+	
+	purple_debug_info("facebook", "destroying %d waiting connections\n",
+					  g_queue_get_length(fba->waiting_conns));
+	
+	while (!g_queue_is_empty(fba->waiting_conns))
+		fb_connection_destroy(g_queue_pop_tail(fba->waiting_conns));
+	g_queue_free(fba->waiting_conns);
+	
 	purple_debug_info("facebook", "destroying %d incomplete connections\n",
 			g_slist_length(fba->conns));
 
@@ -457,6 +498,7 @@ static void fb_close(PurpleConnection *p
 		fb_cancel_resending_messages(fba);
 	}
 
+	g_hash_table_destroy(fba->sent_messages_hash);
 	g_hash_table_destroy(fba->cookie_table);
 	g_hash_table_destroy(fba->hostname_ip_cache);
 	g_hash_table_destroy(fba->auth_buddies);
@@ -548,9 +590,13 @@ static void fb_set_status_p(PurpleAccoun
 	FacebookAccount *fba = account->gc->proto_data;
 
 	/* if "away" set idle */
-	if (fba && purple_status_type_get_primitive(purple_status_get_type(status)) == PURPLE_STATUS_AWAY)
+	if (purple_status_type_get_primitive(purple_status_get_type(status)) == PURPLE_STATUS_AWAY)
 	{
-		fba->is_idle = TRUE;	
+		if (fba)
+		{
+			fba->is_idle = TRUE;
+		}
+		return;
 	}
 
 	/* first check that we actually want to set this through Pidgin */
============================================================
--- libpurple/protocols/facebook/libfacebook.h	f4be461d1adef3dd6cec62c050ba9e9f3953f3cf
+++ libpurple/protocols/facebook/libfacebook.h	c7f920d377b94b738396470d9fe9a34ba09fcbbf
@@ -21,10 +21,13 @@
 #ifndef LIBFACEBOOK_H
 #define LIBFACEBOOK_H
 
-#define FACEBOOK_PLUGIN_VERSION "1.64"
+#define FACEBOOK_PLUGIN_VERSION "1.65"
 #define FACEBOOK_PLUGIN_ID "prpl-bigbrownchunx-facebookim"
 #define FACEBOOK_CAPTCHA_SITE "6LezHAAAAAAAADqVjseQ3ctG3ocfQs2Elo1FTa_a"
 
+/* Maximum number of simultaneous connections to a server */
+#define FB_MAX_CONNECTIONS 32
+
 #include <glib.h>
 
 #include <errno.h>
@@ -77,12 +80,14 @@ typedef struct _FacebookBuddy FacebookBu
 typedef struct _FacebookAccount FacebookAccount;
 typedef struct _FacebookBuddy FacebookBuddy;
 
-typedef void (*FacebookProxyCallbackFunc)(FacebookAccount *fba, gchar *data, gsize data_len, gpointer user_data);
+typedef void (*FacebookProxyCallbackFunc)(FacebookAccount *fba, const gchar *data, gsize data_len, gpointer user_data);
+typedef void (*FacebookFunc)(FacebookAccount *fba);
 
 struct _FacebookAccount {
 	PurpleAccount *account;
 	PurpleConnection *pc;
 	GSList *conns; /**< A list of all active FacebookConnections */
+	GQueue *waiting_conns; /**< A list of all FacebookConnections waiting to process */
 	GSList *dns_queries;
 	GHashTable *cookie_table;
 	gchar *post_form_id;
@@ -122,4 +127,8 @@ struct _FacebookBuddy {
 	gchar *thumb_url;
 };
 
+
+gboolean fb_do_http_login(FacebookAccount *fba, 
+		FacebookProxyCallbackFunc callback_func, gpointer user_data);
+
 #endif /* LIBFACEBOOK_H */
============================================================
--- libpurple/protocols/facebook/pidgin-facebookchat.rc	7315a1099a7e1134eee2f5d9079b10f38583caeb
+++ libpurple/protocols/facebook/pidgin-facebookchat.rc	ad98bb312d865fa1422790bf78d4e9d3730582f8
@@ -1,7 +1,7 @@ 1 VERSIONINFO
 
 1 VERSIONINFO
-FILEVERSION 1,64,0,0
-PRODUCTVERSION 1,64,0,0
+FILEVERSION 1,65,0,0
+PRODUCTVERSION 1,65,0,0
 FILEOS 0x40004 // VOS_NT_WINDOWS32
 FILETYPE 0x2 // VFT_DLL
 {
@@ -12,8 +12,8 @@ BLOCK "StringFileInfo"
 		VALUE "CompanyName", "Eion Robb\0"
 		VALUE "FileDescription",  "Facebook Chat plugin for Pidgin\0"
 		VALUE "ProductName", "pidgin-facebookchat\0"
-		VALUE "FileVersion", "1.64\0"
-		VALUE "ProductVersion", "1.64\0"
+		VALUE "FileVersion", "1.65\0"
+		VALUE "ProductVersion", "1.65\0"
 		VALUE "InternalName", "pidgin-facebookchat\0"
 		VALUE "OriginalFilename", "libfacebook.dll\0"
 		VALUE "Comments", "http://pidgin-facebookchat.googlecode.com/\0"
============================================================
--- libpurple/protocols/facebook/rss.xml	18460f314830faedf07748921a27b26307716023
+++ libpurple/protocols/facebook/rss.xml	567c3aa5d4fa196f8211764630cd6d709b89aa31
@@ -13,6 +13,37 @@
 			<width>48</width><height>48</height>
 		</image>
 		<item>
+			<title>Version 1.65</title>
+			<link>http://code.google.com/p/pidgin-facebookchat/issues/detail?id=24#c53</link>
+			<description><![CDATA[Hi all. Been a wee while since the last version of the plugin.  This version has a 
+			fix for newer buddy icons being too small, and also downloads all your offline 
+			buddies as well as your online ones.<br/>
+			Download from usual place<br/>
+			<a href="http://code.google.com/p/pidgin-facebookchat/wiki/Downloads">http://code.google.com/p/pidgin-facebookchat/wiki/Downloads</a><br/>
+			<br/>
+			Also, in case you haven't heard, Facebook has come out with an XMPP interface (so 
+			you dont *have* to use this plugin to connect to FB anymore).  I'm currently 
+			working on rewriting a new, more stable version 2.0 of the plugin, which will use 
+			XMPP, while filling in some of the gaps of features that you're all used to by now :)<br/>]]></description>
+			<pubDate>Fri 26 Feb 2010 14:40:29 +1300</pubDate>
+			<guid isPermaLink="true">http://code.google.com/p/pidgin-facebookchat/issues/detail?id=24#c53</guid>
+		</item>
+		<item>
+			<title>Version 1.64</title>
+			<link>http://code.google.com/p/pidgin-facebookchat/issues/detail?id=24#c52</link>
+			<description><![CDATA[I've just dropped v1.64 out for download at<br/>
+			<a href="http://code.google.com/p/pidgin-facebookchat/wiki/Downloads">http://code.google.com/p/pidgin-facebookchat/wiki/Downloads</a><br/>
+			<br/>
+			It fixes up some really annoying things like buddy icons not working and some strange status message stuffs.<br/>
+			<br/>
+			Changelog:<br/>
+			<a href="http://code.google.com/p/pidgin-facebookchat/wiki/Changelog">http://code.google.com/p/pidgin-facebookchat/wiki/Changelog</a><br/>
+			<br/>
+			(Apologies to rss feed subscribers for the slow post) ]]></description>
+			<pubDate>Fri 4 December 2009 17:43:30 +1300</pubDate>
+			<guid isPermaLink="true">http://code.google.com/p/pidgin-facebookchat/issues/detail?id=24#c52</guid>
+		</item>
+		<item>
 			<title>Version 1.63</title>
 			<link>http://code.google.com/p/pidgin-facebookchat/issues/detail?id=24#c51</link>
 			<description><![CDATA[Just pushed out v1.63 which fixes up a few of the little annoying things that didn't 


More information about the Commits mailing list