static void fb_auth_reject_cb(gpointer data) { FacebookBuddy *fbuddy = data; FacebookAccount *fba = fbuddy->fba; gchar *buddy_uid; gchar *postdata; g_return_if_fail(fba != NULL); g_return_if_fail(fba->post_form_id != NULL); g_return_if_fail(fbuddy->uid != 0); buddy_uid = g_strdup_printf("%" G_GINT64_FORMAT, fbuddy->uid); postdata = g_strdup_printf( "type=friend_connect&id=%s&action=reject&" "post_form_id=%s&fb_dtsg=%s&" "post_form_id_source=AsyncRequest&__a=1", buddy_uid, fba->post_form_id, fba->dtsg); fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/reqs.php", postdata, NULL, NULL, FALSE); g_hash_table_remove(fba->auth_buddies, buddy_uid); g_free(postdata); g_free(fbuddy); g_free(buddy_uid); }
void fb_blist_poke_buddy(PurpleBlistNode *node, gpointer data) { PurpleBuddy *buddy; FacebookBuddy *fbuddy; FacebookAccount *fba; gchar *postdata; if(!PURPLE_BLIST_NODE_IS_BUDDY(node)) return; buddy = (PurpleBuddy *) node; if (!buddy) return; fbuddy = buddy->proto_data; if (!fbuddy) return; fba = fbuddy->fba; if (!fba) return; postdata = g_strdup_printf("uid=%d&pokeback=0&post_form_id=%s", fbuddy->uid, fba->post_form_id); fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/poke.php", postdata, NULL, NULL, FALSE); g_free(postdata); }
void fb_buddy_delete(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group) { FacebookAccount *fba = pc->proto_data; gchar *buddy_tmp, *postdata; //This function removes a buddy from our friends list on facebook //and shouldn't really be used if (!purple_account_get_bool(fba->account, "facebook_manage_friends", FALSE)) { purple_debug_warning("facebook", "attempted to add %s but was blocked\n", buddy->name); return; } buddy_tmp = g_strdup(purple_url_encode(buddy->name)); postdata = g_strdup_printf( "uid=%s&post_form_id=%s&fb_dtsg=%s&" "post_form_id_source=AsyncRequest&__a=1", buddy_tmp, fba->post_form_id, fba->dtsg); g_free(buddy_tmp); fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/profile/removefriend.php", postdata, NULL, NULL, FALSE); g_free(postdata); }
static void fb_login(PurpleAccount *account) { FacebookAccount *fba; gchar *postdata, *encoded_username, *encoded_password, *encoded_charset_test; const gchar* const *languages; const gchar *locale; /* Create account and initialize state */ fba = g_new0(FacebookAccount, 1); fba->account = account; fba->pc = purple_account_get_connection(account); fba->uid = -1; fba->last_messages_download_time = time(NULL) - 60; /* 60 secs is a safe buffer */ fba->cookie_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); fba->hostname_ip_cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); fba->sent_messages_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); fba->auth_buddies = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); g_hash_table_replace(fba->cookie_table, g_strdup("test_cookie"), g_strdup("1")); 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("€,´,€,´,水,Д,Є")); 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); }
static unsigned int fb_send_typing(PurpleConnection *pc, const gchar *name, PurpleTypingState state) { int typing_state; gchar *postdata; FacebookAccount *fba = pc->proto_data; gchar *encoded_name; g_return_val_if_fail(fba != NULL, 0); g_return_val_if_fail(fba->post_form_id != NULL, 0); typing_state = (state == PURPLE_TYPING) ? 1 : 0; /* Don't send typing notifications to self */ if (atoll(name) != fba->uid) { encoded_name = g_strdup(purple_url_encode(name)); postdata = g_strdup_printf("typ=%d&to=%s&post_form_id=%s", typing_state, encoded_name, fba->post_form_id); g_free(encoded_name); fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/chat/typ.php", postdata, NULL, NULL, FALSE); g_free(postdata); } else { serv_got_typing(pc, name, 10, state); } /* 7 is the number of seconds before sending the new typing state. It * corresponds with the default value that Facebook waits. */ return 7; }
gboolean fb_reconnect(FacebookAccount *fba) { gchar *url = g_strdup_printf("/ajax/presence/reconnect.php?__a=1&reason=7&post_form_id=%s&__a=1", fba->post_form_id); fb_post_or_get(fba, FB_METHOD_GET, NULL, url, NULL, got_reconnect_json, NULL, FALSE); g_free(url); return FALSE; }
void fb_login_captcha_ok_cb(PurpleConnection *pc, PurpleRequestFields *fields) { const gchar *captcha_response; gchar *postdata, *encoded_username, *encoded_password, *encoded_charset_test, *encoded_persist_data, *encoded_response, *encoded_extra_challenge, *encoded_session; FacebookAccount *fba = pc->proto_data; captcha_response = purple_request_fields_get_string(fields, "captcha_response"); encoded_response = g_strdup(purple_url_encode(captcha_response)); 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_extra_challenge = g_strdup(purple_url_encode( fba->extra_challenge)); encoded_persist_data = g_strdup(purple_url_encode( fba->persist_data)); encoded_session = g_strdup(purple_url_encode( fba->captcha_session)); encoded_charset_test = g_strdup(purple_url_encode("€,´,€,´,水,Д,Є")); postdata = g_strdup_printf("charset_test=%s&" "version=1.0&" "return_session=0&" "charset_test=%s&" "answered_captcha=1&" "captcha_persist_data=%s&" "captcha_session=%s&" "extra_challenge_params=%s&" "captcha_response=%s&" "email=%s&pass=%s&" "persistent=1", encoded_charset_test, encoded_charset_test, encoded_persist_data, encoded_session, encoded_extra_challenge, encoded_response, encoded_username, encoded_password); g_free(encoded_username); g_free(encoded_password); g_free(encoded_charset_test); g_free(encoded_extra_challenge); g_free(encoded_persist_data); g_free(encoded_response); g_free(encoded_session); 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); g_free(fba->extra_challenge); g_free(fba->persist_data); g_free(fba->captcha_session); fba->extra_challenge = NULL; fba->persist_data = NULL; fba->captcha_session = NULL; }
gboolean fb_check_friend_requests(gpointer data) { FacebookAccount *fba; fba = data; if (purple_account_get_bool( fba->account, "facebook_manage_friends", FALSE)) { fb_post_or_get(fba, FB_METHOD_GET, NULL, "/reqs.php", NULL, fb_check_friend_request_cb, NULL, FALSE); } return TRUE; }
gboolean fb_get_buddy_list(gpointer data) { FacebookAccount *fba; gchar *postdata; fba = data; postdata = g_strdup_printf( "user=%d&popped_out=false&force_render=true&buddy_list=1", fba->uid); fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/presence/update.php", postdata, got_buddy_list_cb, NULL, FALSE); g_free(postdata); return TRUE; }
static void handle_move_request(FacebookAccount *fba, MoveRequest *request) { const gchar *old_list_id; const gchar *new_list_id; gchar *postdata; gboolean remove_flist, no_original_list; const gchar *command; purple_debug_info("facebook", "handling movement of %s from %s to %s\n", request->who, request->old_group, request->new_group); old_list_id = fb_get_list_id(fba, request->old_group); new_list_id = fb_get_list_id(fba, request->new_group); remove_flist = !new_list_id || g_str_equal(new_list_id, "-1"); no_original_list = !old_list_id || g_str_equal(old_list_id, "-1"); if (remove_flist) { command = "&remove_fl=true"; } else if (no_original_list) { command = "&add_fl=true"; } else { command = "&move_fl=true"; } postdata = g_strdup_printf( "post_form_id=%s&drag_uid=%s&user=%" G_GINT64_FORMAT "&new_flid=%s&old_flid=%s%s", fba->post_form_id, request->who, fba->uid, remove_flist ? "" : new_list_id, no_original_list ? "" : old_list_id, command); fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/chat/buddy_list_settings.php", postdata, NULL, NULL, FALSE); g_free(postdata); g_free(request->who); g_free(request->old_group); g_free(request->new_group); g_free(request); }
/* 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 (atoi(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); }
/* Message fetch loop. An invariant here is that get_new_messages() * is the only function which can create a new timer for * new_messages_check_timer. The timer always calls got_new_messages(), * and got_new_messages always calls get_new_messages (either directly * or indirectly). To start the loops off, get_new_messages should be * called ONCE and only ONCE. After that the timers will take care of * themselves until final cleanup. */ gboolean fb_get_new_messages(FacebookAccount *fba) { time_t now; gchar *fetch_url; gchar *fetch_server; const gchar *channel_number; fba->new_messages_check_timer = 0; now = time(NULL); if (fba->last_messages_download_time > now - 3) { /* * Wait a bit before fetching more messages, to make sure we * never hammer their servers. * * TODO: This could be smarter. Like, allow 3 requests per * 10 seconds or something. */ fba->new_messages_check_timer = purple_timeout_add_seconds( 3 - (now - fba->last_messages_download_time), (GSourceFunc)fb_get_new_messages, fba); return FALSE; } if (fba->channel_number == NULL) { return FALSE; } else { channel_number = fba->channel_number; } purple_debug_info("facebook", "getting new messages\n"); fetch_server = g_strdup_printf("%d.%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", (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; g_free(fetch_url); g_free(fetch_server); return FALSE; }
gboolean fb_get_notifications_feed(FacebookAccount *fba) { const gchar *feed_url; if (purple_account_get_bool(fba->account, "facebook_get_notifications", TRUE)) { feed_url = purple_account_get_string(fba->account, "notifications_feed_url", NULL); if (!feed_url) { purple_debug_info("facebook", "no notifications feed url available, searching for it\n"); fb_find_feed_url(fba); return TRUE; } fb_post_or_get(fba, FB_METHOD_GET, NULL, feed_url, NULL, fb_got_notifications_cb, NULL, FALSE); } return TRUE; }
static void fb_login_captcha_cb(FacebookAccount *fba, gchar *response, gsize len, gpointer userdata) { const gchar *challenge_start = "challenge : '"; gchar *challenge; gchar *image_url; challenge = g_strstr_len(response, len, challenge_start); if (challenge) { challenge += strlen(challenge_start); challenge = g_strndup(challenge, strchr(challenge, '\'') - challenge); image_url = g_strdup_printf("/image?c=%s", challenge); fb_post_or_get(fba, FB_METHOD_GET | FB_METHOD_SSL, "api-secure.recaptcha.net", image_url, NULL, fb_login_captcha_image_cb, NULL, FALSE); } }
static gboolean fb_send_im_fom(FacebookOutgoingMessage *msg) { gchar *encoded_message; gchar *postdata; gchar *jstime; jstime = g_strdup_printf("%ld%ld", msg->time.tv_sec, (msg->time.tv_usec/1000)); encoded_message = g_strdup(purple_url_encode(msg->message)); postdata = g_strdup_printf("msg_text=%s&msg_id=%d&to=%s&client_time=%s&post_form_id=%s&fb_dtsg=%s", encoded_message, msg->msg_id, msg->who, jstime, msg->fba->post_form_id ? msg->fba->post_form_id : "0",msg->fba->dtsg?msg->fba->dtsg:"(null)"); g_free(encoded_message); g_free(jstime); fb_post_or_get(msg->fba, FB_METHOD_POST, NULL, "/ajax/chat/send.php?__a=1", postdata, fb_send_im_cb, msg, FALSE); g_free(postdata); return FALSE; }
PurpleConversation * fb_find_chat(FacebookAccount *fba, const gchar *group) { PurpleConversation *conv; gchar *postdata; conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, group, fba->account); if (conv == NULL) { conv = serv_got_joined_chat(fba->pc, atoi(group), group); postdata = g_strdup_printf("gid=%s&post_form_id=%s&fb_dtsg=%s&lsd=", group, fba->post_form_id, fba->dtsg); fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/groups/chat/update_facepiles.php?__a=1", postdata, fb_got_facepile, g_strdup(group), FALSE); g_free(postdata); } return conv; }
static void fb_auth_reject_cb(gpointer data) { FacebookBuddy *fbuddy = data; FacebookAccount *fba = fbuddy->fba; gchar *postdata; g_return_if_fail(fba != NULL); g_return_if_fail(fba->post_form_id != NULL); g_return_if_fail(fbuddy->uid != 0); postdata = g_strdup_printf( "type=friend_add&id=%d&action=reject&post_form_id=%s", fbuddy->uid, fba->post_form_id); fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/reqs.php", postdata, NULL, NULL, FALSE); g_free(postdata); fba->auth_buddies = g_slist_remove(fba->auth_buddies, GINT_TO_POINTER(fbuddy->uid)); g_free(fbuddy); }
void fb_add_buddy(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group) { gchar *postdata; FacebookAccount *fba = pc->proto_data; gchar *buddy_tmp; 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")); */ purple_debug_warning("facebook", "attempted to add %s but was blocked\n", buddy->name); return; } if (atoll(buddy->name) == fba->uid) { purple_account_set_bool(fba->account, "facebook_hide_self", FALSE); return; } buddy_tmp = g_strdup(purple_url_encode(buddy->name)); postdata = g_strdup_printf( "user=%" G_GINT64_FORMAT "&profile_id=%s&message=&" "source=&submit=1&post_form_id=%s&fb_dtsg=%s&" "post_form_id_source=AsyncRequest&__a=1", fba->uid, buddy_tmp, fba->post_form_id, fba->dtsg); g_free(buddy_tmp); fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/profile/connect.php", postdata, NULL, NULL, FALSE); g_free(postdata); }
static void fb_set_status_ok_cb(gpointer data, const gchar *status_text) { PurpleConnection *pc = data; FacebookAccount *fba = pc->proto_data; gchar *postdata; gchar *status_tmp; gchar *status_text_new; g_return_if_fail(fba->post_form_id != NULL); status_text_new = g_strstrip(g_strdup(status_text)); /* don't set the status if it's idential to what we've already set */ if (fba->last_status_message && g_str_equal(fba->last_status_message, status_text_new)) { g_free(status_text_new); return; } g_free(fba->last_status_message); fba->last_status_message = status_text_new; if (*status_text_new != '\0') { status_tmp = g_strdup(purple_url_encode(status_text_new)); postdata = g_strdup_printf("profile_id=%" G_GINT64_FORMAT "&status=%s&post_form_id=%s", fba->uid, status_tmp, fba->post_form_id); g_free(status_tmp); } else postdata = g_strdup_printf("profile_id=%" G_GINT64_FORMAT "&clear=1&post_form_id=%s", fba->uid, fba->post_form_id); fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/updatestatus.php", postdata, NULL, NULL, FALSE); g_free(postdata); }
static void create_friend_list(FacebookAccount *fba, const gchar *new_group, MoveRequest *request) { gchar *postdata; gchar *new_group_escaped; purple_debug_info("facebook", "creating friend list %s\n", new_group); new_group_escaped = fb_strdup_withhtml(new_group); postdata = g_strdup_printf( "post_form_id=%s&create=%s&user=%" G_GINT64_FORMAT, fba->post_form_id, new_group_escaped, fba->uid); fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/chat/buddy_list_settings.php", postdata, create_list_cb, request, FALSE); g_free(postdata); g_free(new_group_escaped); }
void fb_add_buddy(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group) { gchar *postdata; gchar *url; FacebookAccount *fba = pc->proto_data; gchar *buddy_tmp; if (!purple_account_get_bool( fba->account, "facebook_manage_friends", FALSE)) { 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 return; } if (atoi(buddy->name) == fba->uid) { purple_account_set_bool(fba->account, "facebook_hide_self", FALSE); return; } buddy_tmp = g_strdup(purple_url_encode(buddy->name)); postdata = g_strdup_printf( "confirmed=1&add=Add+Friend&action=follow_up&uid=%s&flids=&flid_name=&source=search&is_from_whitelist=0&message=&failed_captcha=0&post_form_id=%s", buddy_tmp, fba->post_form_id); url = g_strdup_printf("/ajax/addfriend.php?id=%s", buddy_tmp); g_free(buddy_tmp); fb_post_or_get(fba, FB_METHOD_POST, NULL, url, postdata, NULL, NULL, FALSE); g_free(postdata); g_free(url); }
static void fb_login_cb(FacebookAccount *fba, gchar *response, gsize len, gpointer userdata) { gchar *user_cookie; const gchar *persist_data_start; gchar *persist_data; const gchar *session_start; gchar *session; gchar *captcha_url; const gchar *extra_challenge_params; gchar *extra_challenge; if (len && g_strstr_len(response, len, "captcha")) { purple_debug_info("facebook", "captcha page: %s\n", response); purple_connection_update_progress(fba->pc, _("Handling Captcha"), 2, 4); persist_data_start = "<input type=\"hidden\" id=\"captcha_persist_data\" name=\"captcha_persist_data\" value=\""; 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); } session_start = "<input type=\"hidden\" id=\"captcha_session\" name=\"captcha_session\" value=\""; session = g_strstr_len(response, len, session_start); if (session) { session += strlen(session_start); fba->captcha_session = g_strndup(session, strchr(session, '"') - session); } extra_challenge_params = "<input type=\"hidden\" id=\"extra_challenge_params\" name=\"extra_challenge_params\" value=\""; extra_challenge = g_strstr_len(response, len, extra_challenge_params); if (extra_challenge) { extra_challenge += strlen(extra_challenge_params); fba->extra_challenge = g_strndup(extra_challenge, strchr(extra_challenge, '"') - extra_challenge); extra_challenge = purple_unescape_html(fba->extra_challenge); g_free(fba->extra_challenge); fba->extra_challenge = extra_challenge; } if (!fba->extra_challenge || !fba->persist_data || !fba->captcha_session) { purple_debug_info("facebook", "captcha response: %s\n", response); g_free(fba->extra_challenge); g_free(fba->persist_data); g_free(fba->captcha_session); fba->extra_challenge = NULL; fba->persist_data = NULL; fba->captcha_session = NULL; purple_connection_error_reason(fba->pc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, "Could not authenticate captcha. Logging into the Facebook website may fix this."); return; } captcha_url = g_strdup_printf("/challenge?k=" FACEBOOK_CAPTCHA_SITE "&%s", fba->extra_challenge?fba->extra_challenge:""); fb_post_or_get(fba, FB_METHOD_GET | FB_METHOD_SSL, "api-secure.recaptcha.net", captcha_url, NULL, fb_login_captcha_cb, NULL, FALSE); g_free(captcha_url); return; } 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); /* ok, we're logged in now! */ 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_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 new notifications */ fba->notifications_timer = purple_timeout_add_seconds(60, (GSourceFunc)fb_get_notifications_feed, fba); /* Periodically check for new messages. NOTE: This MUST exist, * regardless of other other mechanisms for checking messages. This * is because the code needs a failsafe checker in case other one of * the other retrieval mechanisms dies due to a bad request, etc. * Without such a failsafe, a user will receive no messages, which is * one of hardest bugs to debug and get reports about. Hence, the * importance of this loop. * That said, there is room for tweaking this loop and possibly even * setting it such that it is the primary or only message checker. * The key is that the method must NEVER die until logout. */ 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); }
void fb_get_groups(FacebookAccount *fba) { fb_post_or_get(fba, FB_METHOD_GET, NULL, "/ajax/home/groups.php?__a=1", NULL, fb_got_groups, NULL, FALSE); }
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, callback, FALSE); return FALSE; }
static void fb_find_feed_url(FacebookAccount *fba) { fb_post_or_get(fba, FB_METHOD_GET, NULL, "/notifications.php", NULL, find_feed_url_cb, NULL, FALSE); }
static void fb_close(PurpleConnection *pc) { FacebookAccount *fba; gchar *postdata; GSList *buddies; purple_debug_info("facebook", "disconnecting account\n"); g_return_if_fail(pc != NULL); g_return_if_fail(pc->proto_data != NULL); fba = pc->proto_data; if ( fba == NULL ) //VOXOX - JRT - 2009.10.12 - Prevent crash when network is lost or resuming from hibernation. return; purple_debug_info("facebook", "unloading plugin\n"); /* destroy blist subsystem */ fb_blist_destroy(fba); /* destroy conversation subsystem */ fb_conversation_destroy(fba); buddies = purple_find_buddies(fba->account, NULL); while(buddies) { PurpleBuddy *b = buddies->data; fb_buddy_free(b); buddies = g_slist_delete_link(buddies, buddies); } /* Tell Facebook that we've logged out. */ /* * TODO * This doesn't actually work because the request is non-blocking * and we're in the process of logging out. So we start making a * connection but then libpurple immediately cancels the attempt * and frees everything. * * There are two ways to fix this: * 1. We could make this request, but not pass in fba or reference * any other data. The request could complete normally even * after this account has logged out, since it really doesn't * need access to the PurpleConnection or the FacebookAccount. * * 2. The close prpl callback could be changed in libpurple so that * protocol plugins can have a chance to make network requests * and do other long cleanup operations. So the call to * prpl->close() would become asynchronous. It tells the * protocol plugin to begin the shutdown sequence, and the * protocol plugin tells the core when it's finished. */ if (fba->post_form_id) postdata = g_strdup_printf( "visibility=false&post_form_id=%s&" "fb_dtsg=%s&post_form_id_source=AsyncRequest&" "__a=1", fba->post_form_id, fba->dtsg); else postdata = g_strdup("visibility=false"); fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/chat/settings.php", postdata, NULL, NULL, FALSE); g_free(postdata); if (fba->friend_request_timer) { purple_timeout_remove(fba->friend_request_timer); } if (fba->notifications_timer) { purple_timeout_remove(fba->notifications_timer); } if (fba->new_messages_check_timer) { purple_timeout_remove(fba->new_messages_check_timer); } if (fba->perpetual_messages_timer) { purple_timeout_remove(fba->perpetual_messages_timer); } purple_debug_info("facebook", "destroying %d incomplete connections\n", g_slist_length(fba->conns)); while (fba->conns != NULL) fb_connection_destroy(fba->conns->data); while (fba->dns_queries != NULL) { PurpleDnsQueryData *dns_query = fba->dns_queries->data; purple_debug_info("facebook", "canceling dns query for %s\n", purple_dnsquery_get_host(dns_query)); fba->dns_queries = g_slist_remove(fba->dns_queries, dns_query); purple_dnsquery_destroy(dns_query); } if (fba->resending_messages != NULL) { fb_cancel_resending_messages(fba); } //VOXOX - JRT - 2009.10.13 - I know we are deleting fba anyway, but since other threads may also be accessing this, // it helps reduce crashes due to freed memory ptrs. (There is no thread syncing to control this better). g_hash_table_destroy(fba->cookie_table); g_hash_table_destroy(fba->hostname_ip_cache); g_hash_table_destroy(fba->auth_buddies); g_free(fba->post_form_id); g_free(fba->dtsg); g_free(fba->channel_number); g_free(fba->last_status_message); g_free(fba->extra_challenge); g_free(fba->captcha_session); g_free(fba->persist_data); g_free(fba); }
static void got_buddy_list_cb(FacebookAccount *fba, gchar *data, gsize data_len, gpointer userdata) { GSList *buddies_list; GSList *online_buddies_list = NULL; PurpleBuddy *buddy; FacebookBuddy *fbuddy; gchar *uid; gchar *name; gchar *status_text; gchar *status_time_text; gchar *buddy_icon_url; gboolean idle; guint32 error_number; gchar *search_start; gchar *search_tmp; gchar *tmp; gchar *largest_buddy_search_point = NULL; PurpleGroup *fb_group = NULL; gboolean current_buddy_online = FALSE; purple_debug_info("facebook", "parsing buddy list\n"); purple_debug_misc("facebook", "buddy list\n%s\n", data); if (fba == NULL) return; if (data == NULL) { purple_connection_error_reason(fba->pc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Could not retrieve buddy list")); return; } /* 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"}]} */ tmp = g_strstr_len(data, data_len, "\"error\":"); if (tmp != NULL) { tmp += 9; tmp = g_strndup(tmp, strchr(tmp, ',')-tmp); error_number = atoi(tmp); g_free(tmp); if (error_number) { /* error :( */ tmp = g_strstr_len(data, data_len, "\"errorDescription\":"); tmp += 20; tmp = g_strndup(tmp, strchr(tmp, '"')-tmp); /* TODO: Use purple_connection_error_reason() */ purple_connection_error(fba->pc, tmp); g_free(tmp); return; } } /* look for "userInfos":{ ... }, */ search_start = strstr(data, "\"userInfos\":{"); if (search_start == NULL) return; search_start += 13; while (*search_start != '}' && (search_start - data < data_len)) { tmp = strchr(search_start, ':'); uid = g_strndup(search_start+1, tmp-search_start-2); /* purple_debug_misc("facebook", "uid: %s\n", uid); */ search_start += strlen(uid) + 2; search_tmp = strstr(search_start, "\"name\":") + 8; if (search_tmp > largest_buddy_search_point) largest_buddy_search_point = search_tmp; search_tmp = g_strndup(search_tmp, strchr(search_tmp, '"')-search_tmp); name = fb_convert_unicode(search_tmp); g_free(search_tmp); /* purple_debug_misc("facebook", "name: %s\n", name); */ /* try updating the alias, just in case it was removed locally */ serv_got_alias(fba->pc, uid, name); /* look for "uid":{"i":_____} */ tmp = g_strdup_printf("\"%s\":{\"i\":", uid); search_tmp = g_strstr_len(data, data_len, tmp); if (search_tmp != NULL) { search_tmp += strlen(tmp); if (search_tmp > largest_buddy_search_point) largest_buddy_search_point = search_tmp; search_tmp = g_strndup(search_tmp, strchr(search_tmp, '}')-search_tmp); /* purple_debug_misc("facebook", "buddy idle: %s\n", search_tmp); */ buddy = purple_find_buddy(fba->account, uid); idle = g_str_equal(search_tmp, "true"); g_free(search_tmp); 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; } g_free(tmp); /* Set the buddy status text and time */ search_tmp = strstr(search_start, "\"status\":"); if (search_tmp != NULL && *(search_tmp + 9) == '"') { search_tmp += 10; if (search_tmp > largest_buddy_search_point) largest_buddy_search_point = strstr(search_tmp, ",\"statusTime"); search_tmp = g_strndup(search_tmp, strstr(search_tmp, ",\"statusTime")-1-search_tmp); status_text = fb_convert_unicode(search_tmp); g_free(search_tmp); } else { status_text = NULL; } /* is this us? */ if (atoi(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); g_free(uid); /* Move pointer to the end of the buddy entry */ search_start = strchr(largest_buddy_search_point, '}') + 1; while (*search_start == ',' && (search_start - data < data_len)) search_start++; /* 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); } serv_got_alias(fba->pc, uid, name); 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 = atoi(uid); fbuddy->name = g_strdup(name); /* load the old buddy icon from the account settings */ tmp = g_strdup_printf("buddy_icon_%d_cache", fbuddy->uid); fbuddy->thumb_url = g_strdup(purple_account_get_string(fba->account, tmp, "")); g_free(tmp); buddy->proto_data = fbuddy; } else { fbuddy = buddy->proto_data; } g_free(uid); g_free(name); if (status_text != NULL) { tmp = fb_strdup_withhtml(status_text); g_free(status_text); status_text = tmp; /* purple_debug_misc("facebook", "status: %s\n", status_text); */ search_tmp = strstr(search_start, "\"statusTimeRel\":") + 17; if (search_tmp > largest_buddy_search_point) largest_buddy_search_point = strchr(search_tmp, '"'); search_tmp = g_strndup(search_tmp, strchr(search_tmp, '"')-search_tmp); status_time_text = fb_convert_unicode(search_tmp); g_free(search_tmp); if (g_str_equal(status_time_text, "ull,")) { 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); /* purple_debug_misc("facebook", "status time: %s\n", fbuddy->status_rel_time); */ } 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) */ search_tmp = strstr(search_start, "\"thumbSrc\":") + 12; if (search_tmp > largest_buddy_search_point) largest_buddy_search_point = search_tmp; buddy_icon_url = g_strndup(search_tmp, strchr(search_tmp, '"')-search_tmp); if (fbuddy->thumb_url == NULL || !g_str_equal(fbuddy->thumb_url, buddy_icon_url)) { g_free(fbuddy->thumb_url); fbuddy->thumb_url = g_strdup(buddy_icon_url); /* Save the buddy icon so that they don't all need to be reloaded at startup */ tmp = g_strdup_printf("buddy_icon_%d_cache", fbuddy->uid); purple_account_set_string(fba->account, tmp, buddy_icon_url); g_free(tmp); /* Turn the \/ into / */ tmp = g_strcompress(buddy_icon_url); /* small icon at http://profile.ak.facebook.com/profile6/1845/74/q800753867_2878.jpg */ /* bigger icon at http://profile.ak.facebook.com/profile6/1845/74/n800753867_2878.jpg */ search_tmp = strstr(tmp, "/q"); if (search_tmp) *(search_tmp + 1) = 'n'; if (g_str_equal(tmp, "http://static.ak.fbcdn.net/pics/q_silhouette.gif")) /* User has no icon */ purple_buddy_icons_set_for_user(fba->account, purple_buddy_get_name(buddy), NULL, 0, NULL); else /* Fetch their icon */ fb_post_or_get(fba, FB_METHOD_GET, "profile.ak.facebook.com", tmp + strlen("http://profile.ak.facebook.com"), NULL, buddy_icon_cb, g_strdup(purple_buddy_get_name(buddy)), FALSE); g_free(tmp); } g_free(buddy_icon_url); if (current_buddy_online) { /* Add buddy to the list of online buddies */ online_buddies_list = g_slist_append(online_buddies_list, 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); } /* Move pointer after any user configurable data */ search_start = search_tmp; /* Move pointer to the end of the buddy entry */ search_start = strchr(largest_buddy_search_point, '}') + 1; while (*search_start == ',' && (search_start - data < data_len)) search_start++; } 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_free(buddies_list); } g_slist_free(online_buddies_list); }