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&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