adium.1-3: 8b18fb33: pidgin-facebook-chat 1.6.0
evands at pidgin.im
evands at pidgin.im
Tue Aug 18 12:36:19 EDT 2009
-----------------------------------------------------------------
Revision: 8b18fb3333bff7877236c43a6da78fa7a66362bc
Ancestor: 83dc5c1c57c15d70073f794b5d980374875c967d
Author: evands at pidgin.im
Date: 2009-08-18T16:32:28
Branch: im.pidgin.adium.1-3
URL: http://d.pidgin.im/viewmtn/revision/info/8b18fb3333bff7877236c43a6da78fa7a66362bc
Modified files:
libpurple/protocols/facebook/facebook.nsi
libpurple/protocols/facebook/fb_blist.c
libpurple/protocols/facebook/fb_blist.h
libpurple/protocols/facebook/fb_conversation.c
libpurple/protocols/facebook/fb_info.c
libpurple/protocols/facebook/fb_managefriends.c
libpurple/protocols/facebook/fb_messages.c
libpurple/protocols/facebook/fb_util.c
libpurple/protocols/facebook/fb_util.h
libpurple/protocols/facebook/libfacebook.c
libpurple/protocols/facebook/libfacebook.h
ChangeLog:
pidgin-facebook-chat 1.6.0
-------------- next part --------------
============================================================
--- libpurple/protocols/facebook/facebook.nsi 86d06564f9bcb28939ce31fea5cf6e899cb530a9
+++ libpurple/protocols/facebook/facebook.nsi 0ea82a12c41c433fc30f2431d1d6a0c9f53d1329
@@ -6,7 +6,7 @@ SetCompress off
; todo: SetBrandingImage
; HM NIS Edit Wizard helper defines
!define PRODUCT_NAME "pidgin-facebookchat"
-!define PRODUCT_VERSION "1.53"
+!define PRODUCT_VERSION "1.60"
!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 a756fad89ceaabc66d0f1f4798a348b416396471
+++ libpurple/protocols/facebook/fb_blist.c 4bba8ded502f2a2210836c692c63af63ba0abcd0
@@ -21,16 +21,19 @@
#include "libfacebook.h"
#include "fb_connection.h"
#include "fb_blist.h"
+#include "fb_util.h"
+#include "fb_friendlist.h"
+#include "blist.h"
-#include <json-glib/json-glib.h>
-
-static void set_buddies_offline(PurpleBuddy *buddy, GHashTable *online_buddies_list)
+static void set_buddies_offline(PurpleBuddy *buddy,
+ GHashTable *online_buddies_list)
{
if (PURPLE_BUDDY_IS_ONLINE(buddy) &&
g_hash_table_lookup(online_buddies_list, buddy->name) == NULL)
{
purple_prpl_got_user_status(buddy->account, buddy->name,
- purple_primitive_get_id_from_type(PURPLE_STATUS_OFFLINE),
+ purple_primitive_get_id_from_type(
+ PURPLE_STATUS_OFFLINE),
NULL);
}
}
@@ -51,39 +54,280 @@ static void buddy_icon_cb(FacebookAccoun
buddy = purple_find_buddy(fba->account, buddyname);
g_free(buddyname);
- if (buddy == NULL)
- return;
+ g_return_if_fail(buddy != NULL);
+
fbuddy = buddy->proto_data;
+ g_return_if_fail(fbuddy != NULL);
+
buddy_icon_data = g_memdup(data, data_len);
purple_buddy_icons_set_for_user(fba->account, buddy->name,
buddy_icon_data, data_len, fbuddy->thumb_url);
}
-static void got_buddy_list_cb(FacebookAccount *fba, gchar *data,
- gsize data_len, gpointer userdata)
+/**
+ * Find buddy names
+ */
+static GList *get_buddies(FacebookAccount *fba, const gchar *uid,
+ const gchar *name, JsonArray *friend_list_ids)
{
- GSList *buddies_list;
- GHashTable *online_buddies_list = g_hash_table_new(g_str_hash, g_str_equal);
- PurpleBuddy *buddy;
+ GList *buddies;
+ GList *cur;
+
+ buddies = fb_get_buddies_friend_list(fba, uid, friend_list_ids);
+
+ // Initialize proto data for each buddy.
+ for (cur = buddies; cur != NULL; cur = cur->next)
+ {
+ PurpleBuddy *buddy;
+
+ buddy = (PurpleBuddy *) cur->data;
+
+ /* Set the FacebookBuddy structure */
+ if (buddy->proto_data == NULL)
+ {
+ FacebookBuddy *fbuddy;
+ gchar *buddy_icon_url;
+
+ fbuddy = g_new0(FacebookBuddy, 1);
+ fbuddy->buddy = buddy;
+ fbuddy->fba = fba;
+ fbuddy->uid = atoll(uid);
+ fbuddy->name = g_strdup(name);
+
+ // load the old buddy icon url from the icon 'checksum'
+ buddy_icon_url = (char *)
+ purple_buddy_icons_get_checksum_for_user(buddy);
+ if (buddy_icon_url != NULL)
+ fbuddy->thumb_url = g_strdup(buddy_icon_url);
+
+ buddy->proto_data = fbuddy;
+ }
+ }
+
+ return buddies;
+}
+
+static gboolean process_buddy_status(FacebookAccount *fba, PurpleBuddy *buddy,
+ JsonObject *userInfo)
+{
FacebookBuddy *fbuddy;
- gchar *uid;
- gchar *name;
- gchar *status_text;
- gchar *status_time_text;
+ gboolean status_changed;
+
+ status_changed = FALSE;
+ fbuddy = buddy->proto_data;
+
+ if (json_object_has_member(userInfo, "status"))
+ {
+ gchar *status_text;
+ const gchar *status_time_text;
+
+ status_time_text = json_node_get_string(
+ json_object_get_member(userInfo, "statusTimeRel"));
+ status_text = fb_strdup_withhtml(json_node_get_string(
+ json_object_get_member(userInfo, "status")));
+
+ /* set our last known status so that we don't re-set it */
+ if (!fba->last_status_message &&
+ atoll(buddy->name) == fba->uid) {
+ fba->last_status_message = g_strdup(status_text);
+ }
+
+ if (strlen(status_time_text) == 0) {
+ status_time_text = NULL;
+ }
+
+ g_free(fbuddy->status_rel_time);
+ if (status_time_text != NULL) {
+ fbuddy->status_rel_time =
+ fb_strdup_withhtml(status_time_text);
+ } else {
+ fbuddy->status_rel_time = NULL;
+ }
+
+ /* if the buddy status has changed, update the contact list */
+ if (fbuddy->status == NULL ||
+ !g_str_equal(fbuddy->status, status_text))
+ {
+ g_free(fbuddy->status);
+ fbuddy->status = g_strdup(status_text);
+ status_changed = TRUE;
+ }
+
+ g_free(status_text);
+ } else {
+ if (fbuddy->status != NULL) {
+ g_free(fbuddy->status);
+ fbuddy->status = NULL;
+ status_changed = TRUE;
+ }
+ }
+
+ return status_changed;
+}
+
+static void process_buddy_icon(FacebookAccount *fba, PurpleBuddy *buddy,
+ JsonObject *userInfo)
+{
+ FacebookBuddy *fbuddy;
gchar *buddy_icon_url;
+
+ fbuddy = buddy->proto_data;
+
+ /* Set the buddy icon (if it hasn't changed) */
+ buddy_icon_url = json_node_dup_string(json_object_get_member(
+ userInfo, "thumbSrc"));
+ if (fbuddy->thumb_url == NULL ||
+ !g_str_equal(fbuddy->thumb_url, buddy_icon_url))
+ {
+ g_free(fbuddy->thumb_url);
+ if (g_str_equal(buddy_icon_url,
+ "http://static.ak.fbcdn.net/pics/q_silhouette.gif"))
+ {
+ fbuddy->thumb_url = NULL;
+ /* User has no icon */
+ purple_buddy_icons_set_for_user(fba->account,
+ purple_buddy_get_name(buddy), NULL, 0, NULL);
+ }
+ else
+ {
+ gchar *search_tmp;
+
+ fbuddy->thumb_url = g_strdup(buddy_icon_url);
+
+ /* small icon at http://profile.ak.facebook.com/profile6/1845/74/q800753867_2878.jpg */
+ /* bigger icon at http://profile.ak.facebook.com/profile6/1845/74/n800753867_2878.jpg */
+ search_tmp = strstr(buddy_icon_url, "/q");
+ if (search_tmp)
+ *(search_tmp + 1) = 'n';
+
+ /* Fetch their icon */
+ fb_post_or_get(fba, FB_METHOD_GET, "profile.ak.facebook.com",
+ buddy_icon_url, NULL,
+ buddy_icon_cb, g_strdup(purple_buddy_get_name(buddy)), FALSE);
+ }
+ }
+ g_free(buddy_icon_url);
+}
+
+static void process_buddies(FacebookAccount *fba, GHashTable *online_buddies_list,
+ JsonObject *nowAvailableList, gchar *uid, JsonObject *userInfo)
+{
+ const gchar *name;
gboolean idle;
- guint32 error_number;
+ GList *buddies, *cur;
+ gboolean current_buddy_online;
- gchar *search_tmp;
- gchar *tmp;
+ JsonArray *friend_list_ids;
- PurpleGroup *fb_group = NULL;
+ friend_list_ids = NULL;
+ name = json_node_get_string(json_object_get_member(userInfo, "name"));
- gboolean current_buddy_online = FALSE;
+ /* look for "uid":{"i":_____} */
+ if (json_object_has_member(nowAvailableList, uid))
+ {
+ JsonObject *userBlistInfo;
+ userBlistInfo = json_node_get_object(
+ json_object_get_member(nowAvailableList, uid));
+ idle = json_node_get_boolean(
+ json_object_get_member(userBlistInfo, "i"));
+ if (json_object_has_member(userBlistInfo, "fl")) {
+ friend_list_ids = json_node_get_array(
+ json_object_get_member(userBlistInfo, "fl"));
+ }
+ current_buddy_online = TRUE;
+ } else {
+ /* if we're here, the buddy's info has been sent,
+ * but they're not actually online */
+ current_buddy_online = FALSE;
+ idle = FALSE;
+ }
+
+ /* is this us? */
+ if (atoll(uid) == fba->uid)
+ {
+ purple_connection_set_display_name(fba->pc, name);
+
+ /* check that we don't want to show ourselves */
+ current_buddy_online = !purple_account_get_bool(
+ fba->account, "facebook_hide_self", TRUE);
+ }
+
+ buddies = get_buddies(fba, uid, name, friend_list_ids);
+ for (cur = buddies; cur != NULL; cur = cur->next)
+ {
+ PurpleBuddy *buddy;
+ gboolean status_changed;
+
+ buddy = (PurpleBuddy *)cur->data;
+
+ process_buddy_icon(fba, buddy, userInfo);
+ status_changed = process_buddy_status(fba, buddy, userInfo);
+
+ purple_presence_set_idle(purple_buddy_get_presence(buddy),
+ idle, 0);
+
+ if (current_buddy_online)
+ {
+ /* Add buddy to the list of online buddies */
+ g_hash_table_insert(online_buddies_list, buddy->name, buddy);
+
+ // Set buddy as online in buddy list. We check for several
+ // conditions before doing this, because if we set it always
+ // Pidgin has a bug where the logs go nuts with "x is online".
+ if (!PURPLE_BUDDY_IS_ONLINE(buddy) ||
+ status_changed ||
+ idle != purple_presence_is_idle(
+ purple_buddy_get_presence(buddy)))
+ {
+ purple_prpl_got_user_status(fba->account, buddy->name,
+ purple_primitive_get_id_from_type(
+ idle ? PURPLE_STATUS_AWAY :
+ PURPLE_STATUS_AVAILABLE), NULL);
+ }
+ }
+ }
+
+ /* update the blist if we have no previous alias */
+ fb_blist_set_alias(fba, uid, name);
+}
+
+static void process_notifications(FacebookAccount *fba,
+ JsonObject *notifications)
+{
+ if (notifications != NULL &&
+ purple_account_get_check_mail(fba->account))
+ {
+ JsonNode *inboxCount_node = json_object_get_member(
+ notifications, "inboxCount");
+ if (inboxCount_node) {
+ gint inbox_count = json_node_get_int(inboxCount_node);
+ if (inbox_count &&
+ inbox_count != fba->last_inbox_count) {
+ fba->last_inbox_count = inbox_count;
+ gchar *url = g_strdup("http://www.facebook.com/inbox/");
+ purple_notify_emails(
+ fba->pc, inbox_count,
+ FALSE, NULL, NULL,
+ (const char**) &(fba->account->username),
+ (const char**) &(url), NULL, NULL);
+ g_free(url);
+ }
+ }
+ }
+}
+
+static void got_buddy_list_cb(FacebookAccount *fba, gchar *data,
+ gsize data_len, gpointer userdata)
+{
+ GSList *buddies_list;
+ GHashTable *online_buddies_list = g_hash_table_new(
+ g_str_hash, g_str_equal);
+ gchar *uid;
+
purple_debug_info("facebook", "parsing buddy list\n");
if (fba == NULL)
@@ -96,60 +340,50 @@ static void got_buddy_list_cb(FacebookAc
_("Could not retrieve buddy list"));
return;
}
-
+
purple_debug_misc("facebook", "buddy list\n%s\n", data);
-
- JsonNode *root;
- root = json_parser_get_root(parser);
- JsonObject *objnode;
- objnode = json_node_get_object(root);
- /* Check if the facebook group already exists (fixes #13) */
- fb_group = purple_find_group("Facebook");
-
- /* if logged out, this comes up */
- /* for (;;);{"error":1357001,"errorSummary":"Not Logged In",
- "errorDescription":"You must be logged in to do that.",
- "payload":null,"bootload":[{"name":"js\/common.js.pkg.php",
- "type":"js","src":"http:\/\/static.ak.fbcdn.net\/rsrc.php\/pkg\/59\
- /98561\/js\/common.js.pkg.php"}]} */
- if (json_object_has_member(objnode, "error"))
- {
- error_number = json_node_get_int(json_object_get_member(objnode, "error"));
- if (error_number)
- {
- purple_connection_error_reason(fba->pc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- json_node_dup_string(json_object_get_member(objnode, "errorDescription")));
+ gchar *error = NULL;
+ JsonObject *objnode = fb_get_json_object(parser, &error);
+ if (error) {
+ purple_connection_error_reason(
+ fba->pc,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ error);
g_object_unref(parser);
return;
- }
}
-
+
/* look for "userInfos":{ ... }, */
if (!json_object_has_member(objnode, "payload"))
{
g_object_unref(parser);
return;
}
- objnode = json_node_get_object(json_object_get_member(objnode, "payload"));
+ objnode = json_node_get_object(json_object_get_member(
+ objnode, "payload"));
if (!json_object_has_member(objnode, "buddy_list"))
{
g_object_unref(parser);
return;
}
- JsonObject *buddy_list = json_node_get_object(json_object_get_member(objnode, "buddy_list"));
+ JsonObject *buddy_list = json_node_get_object(json_object_get_member(
+ objnode, "buddy_list"));
if (!json_object_has_member(buddy_list, "userInfos"))
{
g_object_unref(parser);
return;
}
- JsonObject *notifications = json_node_get_object(json_object_get_member(objnode, "notifications"));
-
+
+ fb_process_friend_lists(fba, buddy_list);
+
+ // Iterate through the list of buddy infos sent to us.
JsonObject *userInfos;
JsonObject *nowAvailableList;
- userInfos = json_node_get_object(json_object_get_member(buddy_list, "userInfos"));
- nowAvailableList = json_node_get_object(json_object_get_member(buddy_list, "nowAvailableList"));
+ userInfos = json_node_get_object(json_object_get_member(
+ buddy_list, "userInfos"));
+ nowAvailableList = json_node_get_object(json_object_get_member(
+ buddy_list, "nowAvailableList"));
GList *userIds;
userIds = json_object_get_members(userInfos);
GList *currentUserNode;
@@ -160,200 +394,34 @@ static void got_buddy_list_cb(FacebookAc
uid = currentUserNode->data;
JsonObject *userInfo;
- userInfo = json_node_get_object(json_object_get_member(userInfos, uid));
- name = json_node_dup_string(json_object_get_member(userInfo, "name"));
-
- /* update the blist if we have no previous alias */
- fb_blist_set_alias(fba, uid, name);
-
- /* look for "uid":{"i":_____} */
- if (json_object_has_member(nowAvailableList, uid))
- {
- JsonObject *userBlistInfo;
- userBlistInfo = json_node_get_object(json_object_get_member(nowAvailableList, uid));
- idle = json_node_get_boolean(json_object_get_member(userBlistInfo, "i"));
- current_buddy_online = TRUE;
- } else {
- /* if we're here, the buddy's info has been sent, but they're not actually online */
- current_buddy_online = FALSE;
- idle = FALSE;
- }
-
- /* Set the buddy status text and time */
- if (json_object_has_member(userInfo, "status"))
- {
- status_text = json_node_dup_string(json_object_get_member(userInfo, "status"));
- } else {
- status_text = NULL;
- }
-
- /* is this us? */
- if (atoll(uid) == fba->uid)
- {
- purple_connection_set_display_name(fba->pc, name);
-
- /* set our last known status so that we don't re-set it */
- if (status_text && !fba->last_status_message)
- fba->last_status_message = g_strdup(status_text);
-
- /* check that we don't want to show ourselves */
- if (purple_account_get_bool(fba->account, "facebook_hide_self", TRUE))
- {
- g_free(status_text);
- g_free(name);
- /* go on to the next buddy */
- continue;
- } else {
- current_buddy_online = TRUE;
- }
- }
-
- /* Is this a new buddy? */
- buddy = purple_find_buddy(fba->account, uid);
- if (buddy == NULL)
- {
- buddy = purple_buddy_new(fba->account, uid, NULL);
- if (fb_group == NULL)
- {
- fb_group = purple_group_new("Facebook");
- purple_blist_add_group(fb_group, NULL);
- }
- purple_blist_add_buddy(buddy, NULL, fb_group, NULL);
- }
- purple_presence_set_idle(purple_buddy_get_presence(buddy), idle, 0);
-
- /* Set the FacebookBuddy structure */
- if (buddy->proto_data == NULL)
- {
- fbuddy = g_new0(FacebookBuddy, 1);
- fbuddy->buddy = buddy;
- fbuddy->fba = fba;
- fbuddy->uid = atoll(uid);
- fbuddy->name = g_strdup(name);
-
- /* load the old buddy icon url from the icon 'checksum' */
- buddy_icon_url = (char *)purple_buddy_icons_get_checksum_for_user(buddy);
- if (buddy_icon_url != NULL)
- fbuddy->thumb_url = g_strdup(buddy_icon_url);
-
- buddy->proto_data = fbuddy;
- } else {
- fbuddy = buddy->proto_data;
- }
-
- g_free(name);
-
- if (status_text != NULL)
- {
- tmp = fb_strdup_withhtml(status_text);
- g_free(status_text);
- status_text = tmp;
-
- status_time_text = json_node_dup_string(json_object_get_member(userInfo, "statusTimeRel"));
- if (strlen(status_time_text) == 0)
- {
- g_free(status_time_text);
- status_time_text = NULL;
- }
- g_free(fbuddy->status_rel_time);
- if (status_time_text != NULL)
- {
- fbuddy->status_rel_time = fb_strdup_withhtml(status_time_text);
- g_free(status_time_text);
- } else {
- fbuddy->status_rel_time = NULL;
- }
-
- /* if the buddy status has changed, update the contact list */
- if (fbuddy->status == NULL || !g_str_equal(fbuddy->status, status_text))
- {
- tmp = fbuddy->status;
- fbuddy->status = status_text;
- g_free(tmp);
- if (current_buddy_online)
- purple_prpl_got_user_status(fba->account, buddy->name, purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE), NULL);
- } else {
- g_free(status_text);
- }
- } else {
- if (fbuddy->status != NULL)
- {
- g_free(fbuddy->status);
- fbuddy->status = NULL;
- if (current_buddy_online)
- {
- /* update the status in the contact list */
- purple_prpl_got_user_status(fba->account, buddy->name, purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE), NULL);
- }
- }
- }
-
- /* Set the buddy icon (if it hasn't changed) */
- buddy_icon_url = json_node_dup_string(json_object_get_member(userInfo, "thumbSrc"));
- if (fbuddy->thumb_url == NULL || !g_str_equal(fbuddy->thumb_url, buddy_icon_url))
- {
- g_free(fbuddy->thumb_url);
- if (g_str_equal(buddy_icon_url, "http://static.ak.fbcdn.net/pics/q_silhouette.gif"))
- {
- fbuddy->thumb_url = NULL;
- /* User has no icon */
- purple_buddy_icons_set_for_user(fba->account,
- purple_buddy_get_name(buddy), NULL, 0, NULL);
- }
- else
- {
- fbuddy->thumb_url = g_strdup(buddy_icon_url);
-
- /* small icon at http://profile.ak.facebook.com/profile6/1845/74/q800753867_2878.jpg */
- /* bigger icon at http://profile.ak.facebook.com/profile6/1845/74/n800753867_2878.jpg */
- search_tmp = strstr(buddy_icon_url, "/q");
- if (search_tmp)
- *(search_tmp + 1) = 'n';
-
- /* Fetch their icon */
- fb_post_or_get(fba, FB_METHOD_GET, "profile.ak.facebook.com",
- buddy_icon_url + strlen("http://profile.ak.facebook.com"), NULL,
- buddy_icon_cb, g_strdup(purple_buddy_get_name(buddy)), FALSE);
- }
- }
- g_free(buddy_icon_url);
-
- if (current_buddy_online)
- {
- /* Add buddy to the list of online buddies */
- g_hash_table_insert(online_buddies_list, buddy->name, buddy);
-
- /* Update the display of the buddy in the buddy list and make the user online */
- if (!PURPLE_BUDDY_IS_ONLINE(buddy))
- purple_prpl_got_user_status(fba->account, buddy->name, purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE), NULL);
- }
+ userInfo = json_node_get_object(json_object_get_member(
+ userInfos, uid));
+ // Process the user, which generally consists of updating
+ // state info such as name, idle item, status message,etc.
+ process_buddies(fba, online_buddies_list, nowAvailableList,
+ uid, userInfo);
}
g_list_free(userIds);
+ // Set users offline. We do this in a seperate function because FB
+ // only sends us a list of users who are online. We find the users
+ // that are not in the union of of buddy list users + online, and
+ // mark them as offline.
buddies_list = purple_find_buddies(fba->account, NULL);
if (buddies_list != NULL)
{
- g_slist_foreach(buddies_list, (GFunc)set_buddies_offline, online_buddies_list);
+ g_slist_foreach(
+ buddies_list,
+ (GFunc)set_buddies_offline, online_buddies_list);
g_slist_free(buddies_list);
}
g_hash_table_destroy(online_buddies_list);
- if (notifications != NULL && purple_account_get_check_mail(fba->account))
- {
- JsonNode *inboxCount_node = json_object_get_member(notifications, "inboxCount");
- if (inboxCount_node)
- {
- gint inbox_count = json_node_get_int(inboxCount_node);
- if (inbox_count && inbox_count != fba->last_inbox_count)
- {
- fba->last_inbox_count = inbox_count;
- gchar *url = g_strdup("http://www.facebook.com/inbox/");
- purple_notify_emails(fba->pc, inbox_count, FALSE, NULL, NULL, (const char**) &(fba->account->username), (const char**) &(url), NULL, NULL);
- g_free(url);
- }
- }
- }
-
+ // The buddy list also contains notifications data. Process and
+ // display is appropriate.
+ process_notifications(fba, json_node_get_object(
+ json_object_get_member(objnode, "notifications")));
+
g_object_unref(parser);
}
@@ -426,3 +494,24 @@ void fb_blist_set_alias(FacebookAccount
/* In case user removes an alias, we have the server as fallback */
serv_got_alias(fba->pc, id, name);
}
+
+void fb_blist_init(FacebookAccount *fba)
+{
+ fb_friendlist_init(fba);
+
+ fb_get_buddy_list(fba);
+
+ /* periodically check for updates to your buddy list */
+ fba->buddy_list_timer = purple_timeout_add_seconds(60,
+ fb_get_buddy_list, fba);
+
+}
+
+void fb_blist_destroy(FacebookAccount *fba)
+{
+ if (fba->buddy_list_timer) {
+ purple_timeout_remove(fba->buddy_list_timer);
+ }
+
+ fb_friendlist_destroy(fba);
+}
============================================================
--- libpurple/protocols/facebook/fb_blist.h 282d636d6e7f6011bec4f39d5cc9483b1be8b199
+++ libpurple/protocols/facebook/fb_blist.h e77ea2b71a92a022052a1083631d810b540385b4
@@ -29,4 +29,7 @@ void fb_blist_set_alias(FacebookAccount
void fb_blist_set_alias(FacebookAccount *fba, const char *id,
const char *name);
+void fb_blist_init(FacebookAccount *fba);
+void fb_blist_destroy(FacebookAccount *fba);
+
#endif /* FACEBOOK_BLIST_H */
============================================================
--- libpurple/protocols/facebook/fb_conversation.c 259358150129a9c835a26193282d46f2dd284d18
+++ libpurple/protocols/facebook/fb_conversation.c c7a209ce60af9d7660eeceecb1941275fe47bbe1
@@ -49,7 +49,7 @@ void fb_conversation_handle_message(Face
if (fba->uid != atoll(from) || fba->uid == atoll(to)) {
purple_debug_info("facebook",
"displaying received message %lld: %s\n",
- message_time, message_text);
+ (long long int) message_time, message_text);
// TODO/FIXME: cheat here by changing formatting colors.
// Or add an option to just disable history on conv open. TBD.
serv_got_im(fba->pc, from, message_text,
@@ -68,7 +68,7 @@ void fb_conversation_handle_message(Face
{
purple_debug_info("facebook",
"displaying sent message %lld: %s\n",
- message_time, message_text);
+ (long long int) message_time, message_text);
serv_got_im(fba->pc, to, message_text,
log?
@@ -96,7 +96,6 @@ static void fb_history_fetch_cb(Facebook
gsize data_len, gpointer userdata)
{
JsonParser *parser;
- JsonNode *root;
JsonObject *object, *payload;
JsonArray *history;
guint i;
@@ -114,10 +113,9 @@ static void fb_history_fetch_cb(Facebook
min_time = atoll((char *) userdata);
g_free(userdata);
purple_debug_info("facebook", "history fetch with min time of %lld\n",
- min_time);
+ (long long int) min_time);
- root = json_parser_get_root(parser);
- object = json_node_get_object(root);
+ object = fb_get_json_object(parser, NULL);
payload = json_node_get_object(
json_object_get_member(object, "payload"));
history = json_node_get_array(
@@ -159,7 +157,7 @@ static void fb_history_fetch_cb(Facebook
if (message_time > min_time) {
purple_debug_info("facebook",
"displaying history message %lld\n",
- message_time);
+ (long long int) message_time);
fb_conversation_handle_message(
fba, from, to, message_time, message,
min_time != 0);
@@ -188,7 +186,7 @@ void fb_history_fetch(FacebookAccount *f
gchar *url = g_strdup_printf("/ajax/chat/history.php?id=%s", who);
fb_post_or_get(
fba, FB_METHOD_GET, NULL, url, NULL, fb_history_fetch_cb,
- g_strdup_printf("%lld", min_time), FALSE);
+ g_strdup_printf("%lld", (long long int) min_time), FALSE);
g_free(url);
}
@@ -224,7 +222,10 @@ static void fb_conversation_created(Purp
purple_debug_info("facebook", "conversation created with %s\n",
conv->name);
- fb_history_fetch(account->gc->proto_data, conv->name, TRUE);
+ if (purple_account_get_bool(account, "facebook_show_history", TRUE))
+ {
+ fb_history_fetch(account->gc->proto_data, conv->name, TRUE);
+ }
}
gboolean fb_conversation_is_fb(PurpleConversation *conv)
============================================================
--- libpurple/protocols/facebook/fb_info.c 3eb9ceaf6170bc0b2ab8f2ef73d9adec28363839
+++ libpurple/protocols/facebook/fb_info.c b41f1bf46271eaa87317bdaa410b13abde797e7a
@@ -20,6 +20,7 @@
#include "fb_connection.h"
#include "fb_info.h"
+#include "fb_blist.h"
/*
* TODO: Do we really want to do this? Maybe we could just set a
@@ -130,7 +131,7 @@ static void fb_get_info_cb(FacebookAccou
value_tmp2 = g_strndup(value_tmp, strstr(value_tmp, "</title>")-value_tmp);
value_tmp = g_strchomp(purple_markup_strip_html(value_tmp2));
purple_notify_user_info_add_pair(user_info, _("Name"), value_tmp);
- serv_got_alias(fba->pc, uid, value_tmp);
+ fb_blist_set_alias(fba, uid, value_tmp);
g_free(value_tmp);
g_free(value_tmp2);
}
============================================================
--- libpurple/protocols/facebook/fb_managefriends.c 48d9104fae04b40e366b570f78e4b366e0d87a43
+++ libpurple/protocols/facebook/fb_managefriends.c 1d9f2f9e32feef9aa049321c952ab8cb205f1162
@@ -87,6 +87,9 @@ static void fb_check_friend_request_cb(F
FacebookBuddy *buddy;
gchar *search_start = data;
+ g_return_if_fail(data_len > 0);
+ g_return_if_fail(data != NULL);
+
/* loop through the data and look for confirm_friend_add_([0-9]*)" */
while ((search_start = strstr(search_start, uid_pre_text)))
{
@@ -169,10 +172,14 @@ void fb_add_buddy(PurpleConnection *pc,
if (!purple_account_get_bool(
fba->account, "facebook_manage_friends", FALSE)) {
+ /*
+ * We used to pop up dialogs here but if a user renamed a group,
+ * this would spawn message for each person in the buddy list. Bad!
purple_notify_info(fba->pc, _("Friend not added"),
_("Adding Facebook friends via Pidgin is disabled"),
_("Either add a friend via Facebook.com or edit your account preferences"));
- // TODO: Message here
+ */
+ purple_debug_warning("facebook", "attempted to add %s but was blocked\n", buddy->name);
return;
}
@@ -197,24 +204,3 @@ void fb_add_buddy(PurpleConnection *pc,
g_free(url);
}
-#if 0
-/* This code should never be reinstated in it's current form. Period. See
- * issue 185 for why */
-static void fb_remove_buddy(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group)
-{
- gchar *postdata;
- FacebookAccount *fba = pc->proto_data;
-
- if (atoll(buddy->name) == fba->uid)
- {
- purple_account_set_bool(fba->account, "facebook_hide_self", TRUE);
- return;
- }
-
- postdata = g_strdup_printf("uid=%s&post_form_id=%s", buddy->name, fba->post_form_id);
-
- fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/removefriend.php", postdata, NULL, NULL, FALSE);
-
- g_free(postdata);
-}
-#endif
============================================================
--- libpurple/protocols/facebook/fb_messages.c 55cba18f6f06fcf967d93af64fce1cbb06224521
+++ libpurple/protocols/facebook/fb_messages.c 09b6b82775e77886d5aff74654063c9f70e7e7fb
@@ -22,9 +22,8 @@
#include "fb_connection.h"
#include "fb_conversation.h"
#include "fb_blist.h"
+#include "fb_util.h"
-#include <json-glib/json-glib.h>
-
#include "conversation.h"
typedef struct _FacebookOutgoingMessage FacebookOutgoingMessage;
@@ -207,18 +206,14 @@ static void got_new_messages(FacebookAcc
return;
}
- JsonNode *root;
- root = json_parser_get_root(parser);
+ JsonObject *objnode = fb_get_json_object(parser, NULL);
- JsonObject *objnode;
- objnode = json_node_get_object(root);
-
if (json_object_has_member(objnode, "t")) {
const gchar* command = json_node_get_string(json_object_get_member(objnode, "t"));
if (g_str_equal(command, "refresh")) {
- int seq = json_node_get_int(json_object_get_member(objnode, "seq"));
- if (seq) {
- fba->message_fetch_sequence = seq;
+ if (json_object_has_member(objnode, "seq")) {
+ fba->message_fetch_sequence = json_node_get_int(
+ json_object_get_member(objnode, "seq"));
}
/* grab history items for all open conversations */
@@ -297,7 +292,7 @@ static gboolean fb_get_new_messages(Face
fetch_server = g_strdup_printf("%d.channel%s.facebook.com", 0, channel_number);
/* use the current time in the url to get past any transparent proxy caches */
- fetch_url = g_strdup_printf("/x/%lu/%s/p_%" G_GINT64_FORMAT "=%d", time(NULL), (fba->is_idle?"false":"true"), fba->uid, fba->message_fetch_sequence);
+ fetch_url = g_strdup_printf("/x/%lu/%s/p_%" G_GINT64_FORMAT "=%d", (gulong)time(NULL), (fba->is_idle?"false":"true"), fba->uid, fba->message_fetch_sequence);
fb_post_or_get(fba, FB_METHOD_GET, fetch_server, fetch_url, NULL, got_new_messages, fba->pc, TRUE);
fba->last_messages_download_time = now;
@@ -311,29 +306,12 @@ static void fb_send_im_cb(FacebookAccoun
static void fb_send_im_cb(FacebookAccount *fba, gchar *data, gsize data_len, gpointer user_data)
{
FacebookOutgoingMessage *msg = user_data;
- gint error_number;
- const gchar *error_summary;
JsonParser *parser;
- JsonNode *root;
JsonObject *object;
PurpleConversation *conv;
+ gchar *error = NULL;
- /* NULL data crashes on Windows */
- if (data == NULL)
- {
- data = "(null)";
- }
-
purple_debug_misc("facebook", "sent im response: %s\n", data);
- /* for (;;);{"error":1356003,"errorSummary":"Send destination not online",
- "errorDescription":"This person is no longer online.","payload":null,
- "bootload":[{"name":"js\/common.js.pkg.php","type":"js",
- "src":"http:\/\/static.ak.fbcdn.net\/rsrc.php\/pkg\/59\/98936\
- /js\/common.js.pkg.php"}]} */
- /* for (;;);{"error":0,"errorSummary":"","errorDescription":"No error.",
- "payload":[],"bootload":[{"name":"js\/common.js.pkg.php","type":"js",
- "src":"http:\/\/static.ak.fbcdn.net\/rsrc.php\/pkg\/59\/98936\
- /js\/common.js.pkg.php"}]} */
parser = fb_get_parser(data, data_len);
if (!parser) {
@@ -341,15 +319,11 @@ static void fb_send_im_cb(FacebookAccoun
purple_debug_warning("facebook", "bad data while parsing sent IM\n");
return;
}
- root = json_parser_get_root(parser);
- object = json_node_get_object(root);
+ object = fb_get_json_object(parser, &error);
- error_number = json_node_get_int(json_object_get_member(object, "error"));
- error_summary = json_node_get_string(json_object_get_member(object, "errorSummary"));
-
- if (error_number)
+ if (error)
{
- purple_debug_error("facebook", "sent im error: %s\n", error_summary);
+ purple_debug_error("facebook", "sent im error: %s\n", error);
/* there was an error, either report it or retry */
if (msg->retry_count++ < FB_MAX_MSG_RETRY)
{
@@ -362,7 +336,7 @@ static void fb_send_im_cb(FacebookAccoun
{
conv = purple_conversation_new(PURPLE_CONV_TYPE_IM,
fba->account, msg->who);
- purple_conversation_write(conv, NULL, error_summary,
+ purple_conversation_write(conv, NULL, error,
PURPLE_MESSAGE_ERROR, msg->time);
}
@@ -381,7 +355,7 @@ static gboolean fb_send_im_fom(FacebookO
encoded_message = g_strdup(purple_url_encode(msg->message));
postdata = g_strdup_printf("msg_text=%s&msg_id=%d&to=%s&client_time=%lu&post_form_id=%s",
encoded_message, msg->msg_id, msg->who,
- msg->time,
+ (gulong) msg->time,
msg->fba->post_form_id ? msg->fba->post_form_id : "0");
g_free(encoded_message);
@@ -432,7 +406,7 @@ void got_reconnect_json(FacebookAccount
gchar *new_channel_number;
JsonParser *parser;
- JsonNode *root;
+ JsonObject *objnode;
parser = fb_get_parser(data, data_len);
@@ -445,9 +419,7 @@ void got_reconnect_json(FacebookAccount
return;
}
- root = json_parser_get_root(parser);
- JsonObject *objnode;
- objnode = json_node_get_object(root);
+ objnode = fb_get_json_object(parser, NULL);
JsonObject *payload = json_node_get_object(json_object_get_member(objnode, "payload"));
============================================================
--- libpurple/protocols/facebook/fb_util.c 23606c4fef64d4b023b7dca41ac62a8b499a4924
+++ libpurple/protocols/facebook/fb_util.c 094060765df4b0671d66097a7ad6bfc0e1e87650
@@ -24,9 +24,179 @@
* UTILITY CODE *
*****************************************************************************/
+gchar *fb_convert_unicode(const gchar *input)
+{
+ /* \u00e9t\u00e9 should be ?t? */
+
+ gunichar unicode_char;
+ gchar unicode_char_str[6];
+ gint unicode_char_len;
+ gchar *next_pos;
+ gchar *input_string;
+ gchar *output_string;
+
+ if (input == NULL)
+ return NULL;
+
+ next_pos = input_string = g_strdup(input);
+
+ /* purple_debug_info("facebook", "unicode convert: in: %s\n", input); */
+ while ((next_pos = strstr(next_pos, "\\u")))
+ {
+ /* grab the unicode */
+ sscanf(next_pos, "\\u%4x", &unicode_char);
+ /* turn it to a char* */
+ unicode_char_len = g_unichar_to_utf8(unicode_char, unicode_char_str);
+ /* shove it back into the string */
+ g_memmove(next_pos, unicode_char_str, unicode_char_len);
+ /* move all the data after the \u0000 along */
+ g_stpcpy(next_pos + unicode_char_len, next_pos + 6);
+ }
+
+ /* purple_debug_info("facebook", "unicode convert: out: %s\n", input); */
+ output_string = g_strcompress(input_string);
+ g_free(input_string);
+
+ return output_string;
+}
+
+/* Like purple_strdup_withhtml, but escapes htmlentities too */
+gchar *fb_strdup_withhtml(const gchar *src)
+{
+ gulong destsize, i, j;
+ gchar *dest;
+
+ g_return_val_if_fail(src != NULL, NULL);
+
+ /* New length is (length of src) + (number of \n's * 3) + (number of &'s * 5) +
+ (number of <'s * 4) + (number of >'s *4) + (number of "'s * 6) -
+ (number of \r's) + 1 */
+ destsize = 1;
+ for (i = 0; src[i] != '\0'; i++)
+ {
+ if (src[i] == '\n' || src[i] == '<' || src[i] == '>')
+ destsize += 4;
+ else if (src[i] == '&')
+ destsize += 5;
+ else if (src[i] == '"')
+ destsize += 6;
+ else if (src[i] != '\r')
+ destsize++;
+ }
+
+ dest = g_malloc(destsize);
+
+ /* Copy stuff, ignoring \r's, because they are dumb */
+ for (i = 0, j = 0; src[i] != '\0'; i++) {
+ if (src[i] == '\n') {
+ strcpy(&dest[j], "<BR>");
+ j += 4;
+ } else if (src[i] == '<') {
+ strcpy(&dest[j], "<");
+ j += 4;
+ } else if (src[i] == '>') {
+ strcpy(&dest[j], ">");
+ j += 4;
+ } else if (src[i] == '&') {
+ strcpy(&dest[j], "&");
+ j += 5;
+ } else if (src[i] == '"') {
+ strcpy(&dest[j], """);
+ j += 6;
+ } else if (src[i] != '\r')
+ dest[j++] = src[i];
+ }
+
+ dest[destsize-1] = '\0';
+
+ return dest;
+}
+
+gint64 fb_time_kludge(gint initial_time)
+{
+ if (sizeof(gint) >= sizeof(gint64))
+ return initial_time;
+
+ gint64 now_millis = (gint64) time(NULL);
+ now_millis *= 1000;
+ now_millis &= 0xFFFFFFFF00000000LL;
+ gint64 final_time = now_millis | ((guint)initial_time);
+
+ return final_time;
+}
+
+JsonParser *fb_get_parser(const gchar *data, gsize data_len)
+{
+ JsonParser *parser;
+
+ if (data == NULL) {
+ return NULL;
+ }
+
+ data = g_strstr_len(data, data_len, "for (;;);");
+ if (!data) {
+ return NULL;
+ } else {
+ data += strlen("for (;;);");
+ }
+
+ parser = json_parser_new();
+ if (!json_parser_load_from_data(parser, data, -1, NULL)) {
+ g_object_unref(parser);
+ return NULL;
+ }
+
+ return parser;
+}
+
+JsonObject *fb_get_json_object(JsonParser *parser, char **error_message)
+{
+ JsonNode *root;
+ root = json_parser_get_root(parser);
+ JsonObject *objnode;
+ objnode = json_node_get_object(root);
+
+ /* Sample error messages */
+ /* for (;;);{"error":1357001,"errorSummary":"Not Logged In",
+ "errorDescription":"You must be logged in to do that.",
+ "payload":null,"bootload":[{"name":"js\/common.js.pkg.php",
+ "type":"js","src":"http:\/\/static.ak.fbcdn.net\/rsrc.php\/pkg\/59\
+ /98561\/js\/common.js.pkg.php"}]} */
+ if (json_object_has_member(objnode, "error"))
+ {
+ guint32 error_number;
+ const char *summary;
+ const char *description;
+
+ error_number = json_node_get_int(
+ json_object_get_member(objnode, "error"));
+ summary = json_node_get_string(
+ json_object_get_member(objnode, "errorSummary"));
+ description = json_node_get_string(
+ json_object_get_member(objnode, "errorDescription"));
+
+ if (error_number)
+ {
+ purple_debug_error("facebook",
+ "got error from facebook of %s (%s)",
+ summary, description);
+ // Pass error message to calling function if they asked for it.
+ if (error_message) {
+ *error_message = g_strdup(description);
+ }
+ }
+ }
+
+ return objnode;
+}
+
/* Converts *text* into <b>text</b> and _text_ into <i>text</i> */
gchar *fb_replace_styled_text(const gchar *text)
{
+#ifdef __ARM_EABI__
+ return g_strdup(text);
+#else /*__ARM_EABI__*/
+#if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 14
if (glib_check_version(2, 14, 0))
{
return g_strdup(text);
@@ -52,13 +222,27 @@ gchar *fb_replace_styled_text(const gcha
dup_text = g_strdup(text);
midway_string = g_regex_replace(underline_regex, dup_text,
- -1, 0, "<u>\\1</u>", 0, NULL);
+ strlen(dup_text), 0, "<u>\\1</u>", 0, NULL);
+ if (midway_string == NULL)
+ {
+ purple_debug_warning("facebook", "regex failed for underline\n");
+ return dup_text;
+ }
g_free(dup_text);
output_string = g_regex_replace(bold_regex, midway_string,
- -1, 0, "\\1<b>\\2</b>", 0, NULL);
+ strlen(midway_string), 0, "\\1<b>\\2</b>", 0, NULL);
+ if (output_string == NULL)
+ {
+ purple_debug_warning("facebook", "regex failed for bold\n");
+ return midway_string;
+ }
g_free(midway_string);
return output_string;
}
+#else /* GLIB check */
+ return g_strdup(text);
+#endif /* GLIB check */
+#endif /*__ARM_EABI__*/
}
============================================================
--- libpurple/protocols/facebook/fb_util.h 33093b85583658b53d9519de66ab7da32ebd5076
+++ libpurple/protocols/facebook/fb_util.h 53baf5d5d5678ff04dc221e8d629b56d3f3a67f5
@@ -22,8 +22,15 @@
#define FACEBOOK_UTIL_H
#include "libfacebook.h"
+#include <json-glib/json-glib.h>
+JsonParser *fb_get_parser(const gchar *data, gsize data_len);
+JsonObject *fb_get_json_object(JsonParser *parser, char **error_message);
+
gchar *fb_replace_styled_text(const gchar *text);
+gchar *fb_strdup_withhtml(const gchar *src);
+gchar *fb_convert_unicode(const gchar *input);
+gint64 fb_time_kludge(int initial_time);
#endif /* FACEBOOK_UTIL_H */
============================================================
--- libpurple/protocols/facebook/libfacebook.c 4a5dcafa34bf51425459fa4d44852b720bbc3661
+++ libpurple/protocols/facebook/libfacebook.c 83c57c5d42dc61b5fafa9b38bd25fd3e2773b20c
@@ -27,136 +27,12 @@
#include "fb_messages.h"
#include "fb_notifications.h"
#include "fb_search.h"
+#include "fb_friendlist.h"
-/******************************************************************************/
-/* Utility functions */
-/******************************************************************************/
+static void fb_login_cb(FacebookAccount *fba, gchar *response, gsize len,
+ gpointer userdata);
+static void fb_close(PurpleConnection *pc);
-gchar *fb_convert_unicode(const gchar *input)
-{
- /* \u00e9t\u00e9 should be ?t? */
-
- gunichar unicode_char;
- gchar unicode_char_str[6];
- gint unicode_char_len;
- gchar *next_pos;
- gchar *input_string;
- gchar *output_string;
-
- if (input == NULL)
- return NULL;
-
- next_pos = input_string = g_strdup(input);
-
- /* purple_debug_info("facebook", "unicode convert: in: %s\n", input); */
- while ((next_pos = strstr(next_pos, "\\u")))
- {
- /* grab the unicode */
- sscanf(next_pos, "\\u%4x", &unicode_char);
- /* turn it to a char* */
- unicode_char_len = g_unichar_to_utf8(unicode_char, unicode_char_str);
- /* shove it back into the string */
- g_memmove(next_pos, unicode_char_str, unicode_char_len);
- /* move all the data after the \u0000 along */
- g_stpcpy(next_pos + unicode_char_len, next_pos + 6);
- }
-
- /* purple_debug_info("facebook", "unicode convert: out: %s\n", input); */
- output_string = g_strcompress(input_string);
- g_free(input_string);
-
- return output_string;
-}
-
-/* Like purple_strdup_withhtml, but escapes htmlentities too */
-gchar *fb_strdup_withhtml(const gchar *src)
-{
- gulong destsize, i, j;
- gchar *dest;
-
- g_return_val_if_fail(src != NULL, NULL);
-
- /* New length is (length of src) + (number of \n's * 3) + (number of &'s * 5) +
- (number of <'s * 4) + (number of >'s *4) + (number of "'s * 6) -
- (number of \r's) + 1 */
- destsize = 1;
- for (i = 0; src[i] != '\0'; i++)
- {
- if (src[i] == '\n' || src[i] == '<' || src[i] == '>')
- destsize += 4;
- else if (src[i] == '&')
- destsize += 5;
- else if (src[i] == '"')
- destsize += 6;
- else if (src[i] != '\r')
- destsize++;
- }
-
- dest = g_malloc(destsize);
-
- /* Copy stuff, ignoring \r's, because they are dumb */
- for (i = 0, j = 0; src[i] != '\0'; i++) {
- if (src[i] == '\n') {
- strcpy(&dest[j], "<BR>");
- j += 4;
- } else if (src[i] == '<') {
- strcpy(&dest[j], "<");
- j += 4;
- } else if (src[i] == '>') {
- strcpy(&dest[j], ">");
- j += 4;
- } else if (src[i] == '&') {
- strcpy(&dest[j], "&");
- j += 5;
- } else if (src[i] == '"') {
- strcpy(&dest[j], """);
- j += 6;
- } else if (src[i] != '\r')
- dest[j++] = src[i];
- }
-
- dest[destsize-1] = '\0';
-
- return dest;
-}
-
-JsonParser *fb_get_parser(const gchar *data, gsize data_len)
-{
- JsonParser *parser;
-
- if (data == NULL) {
- return NULL;
- }
-
- data = g_strstr_len(data, data_len, "for (;;);");
- if (!data) {
- return NULL;
- } else {
- data += strlen("for (;;);");
- }
-
- parser = json_parser_new();
- if (!json_parser_load_from_data(parser, data, -1, NULL)) {
- g_object_unref(parser);
- return NULL;
- }
-
- return parser;
-}
-
-gint64 fb_time_kludge(gint initial_time)
-{
- if (sizeof(gint) >= sizeof(gint64))
- return initial_time;
-
- gint64 now_millis = (gint64) time(NULL);
- now_millis *= 1000;
- now_millis &= 0xFFFFFFFF00000000LL;
- gint64 final_time = now_millis | initial_time;
-
- return final_time;
-}
-
/******************************************************************************/
/* PRPL functions */
/******************************************************************************/
@@ -242,10 +118,103 @@ static gboolean fb_get_messages_failsafe
return TRUE;
}
+void fb_login_captcha_ok_cb(PurpleConnection *pc, PurpleRequestFields *fields)
+{
+ gint birthday_year, birthday_month, birthday_day;
+ gchar *postdata, *encoded_username, *encoded_password, *encoded_charset_test,
+ *encoded_auth_token, *encoded_persist_data;
+ const gchar* const *languages;
+ const gchar *locale;
+ FacebookAccount *fba = pc->proto_data;
+
+ birthday_year = purple_request_fields_get_integer(fields, "birthday_year");
+ birthday_month = purple_request_fields_get_integer(fields, "birthday_month");
+ birthday_day = purple_request_fields_get_integer(fields, "birthday_day");
+
+ 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_auth_token = g_strdup(purple_url_encode(
+ fba->auth_token));
+ encoded_persist_data = g_strdup(purple_url_encode(
+ fba->persist_data));
+ 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&persistent=1&login=Login&charset_test=%s&version=1.0&return_session=0&t_auth_token=%s&answered_captcha=1&captcha_persist_data=%s&birthday_captcha_day=%d&birthday_captcha_month=%d&birthday_captcha_year=%d",
+ encoded_charset_test, locale, encoded_username, encoded_password, encoded_charset_test, encoded_auth_token, encoded_persist_data, birthday_day, birthday_month, birthday_year);
+ g_free(encoded_username);
+ g_free(encoded_password);
+ g_free(encoded_charset_test);
+ g_free(encoded_auth_token);
+ g_free(encoded_persist_data);
+
+ fb_post_or_get(fba, FB_METHOD_POST | FB_METHOD_SSL, "login.facebook.com",
+ "/login.php?login_attempt=1", postdata, fb_login_cb, NULL, FALSE);
+ g_free(postdata);
+
+ g_free(fba->auth_token);
+ g_free(fba->persist_data);
+ fba->auth_token = NULL;
+ fba->persist_data = NULL;
+}
+
static void fb_login_cb(FacebookAccount *fba, gchar *response, gsize len,
gpointer userdata)
{
gchar *user_cookie;
+
+ if (len && g_strstr_len(response, len, "captcha"))
+ {
+ purple_connection_update_progress(fba->pc, _("Handling Captcha"), 2, 4);
+
+ const gchar *persist_data_start = "<input type=\"hidden\" name=\"captcha_persist_data\" value=\"";
+ gchar *persist_data = g_strstr_len(response, len, persist_data_start);
+ if (persist_data)
+ {
+ persist_data += strlen(persist_data_start);
+ fba->persist_data = g_strndup(persist_data, strchr(persist_data, '"') - persist_data);
+ }
+
+ const gchar *auth_token_start = "<input type=\"hidden\" name=\"t_auth_token\" value=\"";
+ gchar *auth_token = g_strstr_len(response, len, auth_token_start);
+ if (auth_token)
+ {
+ auth_token += strlen(auth_token);
+ fba->auth_token = g_strndup(auth_token, strchr(auth_token, '"') - auth_token);
+ }
+
+ PurpleRequestFields *fields;
+ PurpleRequestFieldGroup *group;
+ PurpleRequestField *field;
+
+ fields = purple_request_fields_new();
+ group = purple_request_field_group_new(NULL);
+ purple_request_fields_add_group(fields, group);
+
+ field = purple_request_field_int_new("birthday_year", _("Year"), 0);
+ purple_request_field_group_add_field(group, field);
+ field = purple_request_field_int_new("birthday_month", _("Month"), 0);
+ purple_request_field_group_add_field(group, field);
+ field = purple_request_field_int_new("birthday_day", _("Day"), 0);
+ purple_request_field_group_add_field(group, field);
+
+ purple_request_fields(fba->pc,
+ _("Facebook Captcha"), _("Facebook Captcha"),
+ _("Facebook thinks you're not you. To prove you are, please enter your date of birth"),
+ fields,
+ _("OK"), G_CALLBACK(fb_login_captcha_ok_cb),
+ _("Logout"), G_CALLBACK(fb_close),
+ fba->account, NULL, NULL, fba->pc
+ );
+
+ return;
+ }
purple_connection_update_progress(fba->pc, _("Authenticating"), 2, 3);
@@ -269,17 +238,12 @@ static void fb_login_cb(FacebookAccount
/* This will kick off our long-poll message retrieval loop */
fb_get_post_form_id(fba);
- fb_get_buddy_list(fba);
fb_check_friend_requests(fba);
/* periodically check for people adding you to their facebook friend list */
fba->friend_request_timer = purple_timeout_add_seconds(60 * 5,
fb_check_friend_requests, fba);
- /* periodically check for updates to your buddy list */
- fba->buddy_list_timer = purple_timeout_add_seconds(60,
- fb_get_buddy_list, fba);
-
/* periodically check for new notifications */
fba->notifications_timer = purple_timeout_add_seconds(60,
(GSourceFunc)fb_get_notifications_feed, fba);
@@ -298,6 +262,9 @@ static void fb_login_cb(FacebookAccount
fba->perpetual_messages_timer = purple_timeout_add_seconds(15,
(GSourceFunc)fb_get_messages_failsafe, fba);
+ /* init blist subsystem */
+ fb_blist_init(fba);
+
/* init conversation subsystem */
fb_conversation_init(fba);
}
@@ -376,6 +343,9 @@ static void fb_close(PurpleConnection *p
purple_debug_info("facebook", "unloading plugin\n");
+ /* destroy blist subsystem */
+ fb_blist_destroy(fba);
+
/* destroy conversation subsystem */
fb_conversation_destroy(fba);
@@ -410,9 +380,6 @@ static void fb_close(PurpleConnection *p
postdata, NULL, NULL, FALSE);
g_free(postdata);
- if (fba->buddy_list_timer) {
- purple_timeout_remove(fba->buddy_list_timer);
- }
if (fba->friend_request_timer) {
purple_timeout_remove(fba->friend_request_timer);
}
@@ -450,6 +417,8 @@ static void fb_close(PurpleConnection *p
g_free(fba->post_form_id);
g_free(fba->channel_number);
g_free(fba->last_status_message);
+ g_free(fba->auth_token);
+ g_free(fba->persist_data);
g_free(fba);
}
@@ -518,7 +487,7 @@ static void fb_set_status_ok_cb(gpointer
postdata = g_strdup_printf("profile_id=%" G_GINT64_FORMAT "&clear=1&post_form_id=%s",
fba->uid, fba->post_form_id);
- fb_post_or_get(fba, FB_METHOD_POST, NULL, "/updatestatus.php",
+ fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/updatestatus.php",
postdata, NULL, NULL, FALSE);
g_free(postdata);
@@ -567,6 +536,7 @@ static void fb_buddy_free(PurpleBuddy *b
}
}
+#if PURPLE_MAJOR_VERSION >= 2 && PURPLE_MINOR_VERSION >= 5
static GHashTable *fb_get_account_text_table(PurpleAccount *account)
{
GHashTable *table;
@@ -577,6 +547,7 @@ static GHashTable *fb_get_account_text_t
return table;
}
+#endif
/******************************************************************************/
/* Plugin functions */
@@ -615,6 +586,17 @@ static void fb_display_plugin_info(Purpl
_("Version"), FACEBOOK_PLUGIN_VERSION);
}
+static void fb_refresh_blist(PurplePluginAction *action)
+{
+ PurpleConnection *pc;
+ FacebookAccount *fba;
+
+ pc = (PurpleConnection *) action->context;
+ fba = pc->proto_data;
+
+ fb_get_buddy_list(fba);
+}
+
static GList *fb_actions(PurplePlugin *plugin, gpointer context)
{
GList *m = NULL;
@@ -632,6 +614,11 @@ static GList *fb_actions(PurplePlugin *p
fb_search_users);
m = g_list_append(m, act);
+ // TODO: remove, this is for testing. REMOVE.
+ act = purple_plugin_action_new(_("Refresh buddy list..."),
+ fb_refresh_blist);
+ m = g_list_append(m, act);
+
return m;
}
@@ -646,8 +633,8 @@ static GList *fb_node_menu(PurpleBlistNo
buddy = (PurpleBuddy *)node;
act = purple_menu_action_new(_("_Poke"),
- PURPLE_CALLBACK(fb_blist_poke_buddy),
- NULL, NULL);
+ PURPLE_CALLBACK(fb_blist_poke_buddy),
+ NULL, NULL);
m = g_list_append(m, act);
}
return m;
@@ -674,17 +661,35 @@ static void plugin_init(PurplePlugin *pl
PurplePluginProtocolInfo *prpl_info = info->extra_info;
/* Add options to the advanced screen in the account settings */
- option = purple_account_option_bool_new(_("Hide myself in the Buddy List"), "facebook_hide_self", TRUE);
- prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
+ option = purple_account_option_bool_new(
+ _("Show history in new conversations"),
+ "facebook_show_history", TRUE);
+ prpl_info->protocol_options = g_list_append(
+ prpl_info->protocol_options, option);
- option = purple_account_option_bool_new(_("Set Facebook status through Pidgin status"), "facebook_set_status_through_pidgin", FALSE);
- prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
+ option = purple_account_option_bool_new(
+ _("Hide myself in the Buddy List"),
+ "facebook_hide_self", TRUE);
+ prpl_info->protocol_options = g_list_append(
+ prpl_info->protocol_options, option);
- option = purple_account_option_bool_new(_("Show Facebook notifications as e-mails in Pidgin"), "facebook_get_notifications", TRUE);
- prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
+ option = purple_account_option_bool_new(
+ _("Set Facebook status through Pidgin status"),
+ "facebook_set_status_through_pidgin", FALSE);
+ prpl_info->protocol_options = g_list_append(
+ prpl_info->protocol_options, option);
- option = purple_account_option_bool_new(_("Edit Facebook friends from Pidgin"), "facebook_manage_friends", FALSE);
- prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
+ option = purple_account_option_bool_new(
+ _("Show Facebook notifications as e-mails in Pidgin"),
+ "facebook_get_notifications", TRUE);
+ prpl_info->protocol_options = g_list_append(
+ prpl_info->protocol_options, option);
+
+ option = purple_account_option_bool_new(
+ _("Edit Facebook friends from Pidgin"),
+ "facebook_manage_friends", FALSE);
+ prpl_info->protocol_options = g_list_append(
+ prpl_info->protocol_options, option);
}
static PurplePluginProtocolInfo prpl_info = {
@@ -714,7 +719,7 @@ static PurplePluginProtocolInfo prpl_inf
NULL, /* change_passwd */
fb_add_buddy, /* add_buddy */
NULL, /* add_buddies */
- NULL, /* remove_buddy */
+ fb_buddy_remove, /* remove_buddy */
NULL, /* remove_buddies */
NULL, /* add_permit */
NULL, /* add_deny */
@@ -733,13 +738,13 @@ static PurplePluginProtocolInfo prpl_inf
NULL, /* get_cb_info */
NULL, /* get_cb_away */
NULL, /* alias_buddy */
- NULL, /* group_buddy */
- NULL, /* rename_group */
+ fb_group_buddy_move, /* group_buddy */
+ fb_group_rename, /* rename_group */
fb_buddy_free, /* buddy_free */
fb_conversation_closed, /* convo_closed */
purple_normalize_nocase,/* normalize */
NULL, /* set_buddy_icon */
- NULL, /* remove_group */
+ fb_group_remove, /* remove_group */
NULL, /* get_cb_real_name */
NULL, /* set_chat_topic */
NULL, /* find_blist_chat */
@@ -756,8 +761,12 @@ static PurplePluginProtocolInfo prpl_inf
NULL, /* unregister_user */
NULL, /* send_attention */
NULL, /* attention_types */
+#if PURPLE_MAJOR_VERSION >= 2 && PURPLE_MINOR_VERSION >= 5
sizeof(PurplePluginProtocolInfo), /* struct_size */
fb_get_account_text_table, /* get_account_text_table */
+#else
+ (gpointer) sizeof(PurplePluginProtocolInfo)
+#endif
};
static PurplePluginInfo info = {
============================================================
--- libpurple/protocols/facebook/libfacebook.h e5edab36948064137e8888d3aa9da077f34e2589
+++ libpurple/protocols/facebook/libfacebook.h dbc2bfd413ba1089196a55882771e37b6da1bc35
@@ -21,7 +21,7 @@
#ifndef LIBFACEBOOK_H
#define LIBFACEBOOK_H
-#define FACEBOOK_PLUGIN_VERSION "1.53"
+#define FACEBOOK_PLUGIN_VERSION "1.60"
#define FACEBOOK_PLUGIN_ID "prpl-bigbrownchunx-facebookim"
#include <glib.h>
@@ -71,9 +71,11 @@
# include <zlib.h>
#endif
-#define FB_MAX_MSG_RETRY 2
+#if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 12
+# define atoll(a) g_ascii_strtoll(a, NULL, 0)
+#endif
-#include <json-glib/json-glib.h>
+#define FB_MAX_MSG_RETRY 2
typedef struct _FacebookAccount FacebookAccount;
typedef struct _FacebookBuddy FacebookBuddy;
@@ -88,11 +90,13 @@ struct _FacebookAccount {
GHashTable *cookie_table;
gchar *post_form_id;
gint64 uid;
- guint buddy_list_timer;
+ guint buddy_list_timer; /* handled by fb_blist */
+ GHashTable *friend_lists; /* handled by fb_friendlist */
+ GHashTable *friend_lists_reverse; /* handled by fb_friendlist */
guint friend_request_timer;
gchar *channel_number;
guint message_fetch_sequence;
- gint64 last_message_time;
+ gint64 last_message_time; /* handled by fb_conversation */
GSList *resending_messages;
GHashTable *auth_buddies;
GHashTable *hostname_ip_cache;
@@ -104,6 +108,8 @@ struct _FacebookAccount {
gboolean is_idle;
GHashTable *sent_messages_hash;
gint last_inbox_count;
+ gchar *auth_token;
+ gchar *persist_data;
};
struct _FacebookBuddy {
@@ -116,10 +122,4 @@ struct _FacebookBuddy {
gchar *thumb_url;
};
-/* TODO: move util functions into a utils file */
-gchar *fb_strdup_withhtml(const gchar *src);
-gchar *fb_convert_unicode(const gchar *input);
-JsonParser *fb_get_parser(const gchar *data, gsize data_len);
-gint64 fb_time_kludge(int initial_time);
-
#endif /* LIBFACEBOOK_H */
More information about the Commits
mailing list