From 2ec2fe72f5754f59363335f9d5578600022661a1 Mon Sep 17 00:00:00 2001 From: watcherhd Date: Thu, 26 Apr 2012 20:02:14 +0000 Subject: FacebookRM: version bump Version 0.0.8.1 ! Fixed getting notifications on login ! Fixed getting unread messages on login ! Getting unread messages on login with right timestamp ! Fixed getting newsfeeds ! Fixed related to deleting contacts from miranda/server + New newsfeed type option "Applications and Games" + Contacts now have MirVer "Facebook" (for Fingerpring plugin) + Getting attachements for unread messages on login ! Fixed avatars in Miranda 0.10.0#3 and newer (thanks borkra) ! Some small fixes (thanks borkra) x Doesn't work notification about friend requests git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@289 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb --- FacebookRM/avatars.cpp | 14 ++- FacebookRM/build.h | 2 +- FacebookRM/client.h | 12 +- FacebookRM/common.h | 4 +- FacebookRM/communication.cpp | 154 ++++++++---------------- FacebookRM/connection.cpp | 11 +- FacebookRM/constants.h | 19 ++- FacebookRM/contacts.cpp | 76 +++++++----- FacebookRM/db.h | 1 + FacebookRM/entities.h | 3 + FacebookRM/events.cpp | 15 +-- FacebookRM/facebook.rc | 4 +- FacebookRM/facebook_10.vcxproj.filters | 12 +- FacebookRM/json.cpp | 98 ++-------------- FacebookRM/json.h | 1 - FacebookRM/messages.cpp | 9 +- FacebookRM/process.cpp | 209 ++++++++++++++++++--------------- FacebookRM/proto.cpp | 16 --- FacebookRM/proto.h | 4 - FacebookRM/utils.cpp | 11 ++ FacebookRM/utils.h | 7 ++ 21 files changed, 298 insertions(+), 384 deletions(-) diff --git a/FacebookRM/avatars.cpp b/FacebookRM/avatars.cpp index c3648ba..bed3f0c 100644 --- a/FacebookRM/avatars.cpp +++ b/FacebookRM/avatars.cpp @@ -180,8 +180,14 @@ int FacebookProto::GetAvatarInfo(WPARAM wParam, LPARAM lParam) if (GetDbAvatarInfo(*AI, NULL)) { - if (_access(AI->filename, 0) || (wParam & GAIF_FORCE)) - { + if (!_access(AI->filename, 0)) + { + LOG("***** Giving AvatarInfo: %s", AI->filename); + return GAIR_SUCCESS; + } + + if (wParam & GAIF_FORCE) + { LOG("***** Starting avatar request thread for %s", AI->filename); ScopedLock s( avatar_lock_ ); @@ -192,12 +198,8 @@ int FacebookProto::GetAvatarInfo(WPARAM wParam, LPARAM lParam) if (is_empty) ForkThread(&FacebookProto::UpdateAvatarWorker, this, NULL); } - return GAIR_WAITFOR; } - - LOG("***** Giving AvatarInfo: %s", AI->filename); - return GAIR_SUCCESS; } return GAIR_NOAVATAR; } diff --git a/FacebookRM/build.h b/FacebookRM/build.h index bcbabbb..eb53310 100644 --- a/FacebookRM/build.h +++ b/FacebookRM/build.h @@ -1 +1 @@ -#define __BUILD 2119 +#define __BUILD 2122 diff --git a/FacebookRM/client.h b/FacebookRM/client.h index 45f4bb3..40555c2 100644 --- a/FacebookRM/client.h +++ b/FacebookRM/client.h @@ -41,7 +41,7 @@ public: msgid_ = error_count_ = last_feeds_update_ = last_notification_time_ = 0; - is_idle_ = invisible_ = is_typing_ = false; + https_ = is_idle_ = invisible_ = is_typing_ = false; buddies_lock_ = send_message_lock_ = NULL; hMsgCon = NULL; @@ -75,6 +75,7 @@ public: bool invisible_; bool is_typing_; bool is_idle_; + bool https_; time_t last_feeds_update_; unsigned __int64 last_notification_time_; int msgid_; @@ -141,7 +142,6 @@ public: HANDLE send_message_lock_; bool buddy_list( ); - bool facepiles( ); bool load_friends( ); bool feeds( ); @@ -164,15 +164,15 @@ public: // HTTP communication - http::response flap( const int request_type, std::string* request_data = NULL ); + http::response flap( const int request_type, std::string* request_data = NULL, std::string* request_get_data = NULL ); bool save_url(const std::string &url,const std::string &filename, HANDLE &nlc); DWORD choose_security_level( int ); int choose_method( int ); std::string choose_proto( int ); - std::string choose_server( int, std::string* data = NULL ); - std::string choose_action( int, std::string* data = NULL ); - std::string choose_request_url( int, std::string* data = NULL ); + std::string choose_server( int, std::string* data = NULL, std::string* get_data = NULL ); + std::string choose_action( int, std::string* data = NULL, std::string* get_data = NULL ); + std::string choose_request_url( int, std::string* data = NULL, std::string* get_data = NULL ); NETLIBHTTPHEADER* get_request_headers( int request_type, int* headers_count ); diff --git a/FacebookRM/common.h b/FacebookRM/common.h index 4fed93e..b1f2d2c 100644 --- a/FacebookRM/common.h +++ b/FacebookRM/common.h @@ -81,8 +81,8 @@ along with this program. If not, see . #include #include -#include "m_updater.h" -#include "m_folders.h" +#include +#include class FacebookProto; diff --git a/FacebookRM/communication.cpp b/FacebookRM/communication.cpp index a7230fc..d17e40e 100644 --- a/FacebookRM/communication.cpp +++ b/FacebookRM/communication.cpp @@ -27,13 +27,13 @@ void facebook_client::client_notify( TCHAR* message ) parent->NotifyEvent( parent->m_tszUserName, message, NULL, FACEBOOK_EVENT_CLIENT ); } -http::response facebook_client::flap( const int request_type, std::string* request_data ) +http::response facebook_client::flap( const int request_type, std::string* request_data, std::string* request_get_data ) { NETLIBHTTPREQUEST nlhr = {sizeof( NETLIBHTTPREQUEST )}; nlhr.requestType = choose_method( request_type ); - std::string url = choose_request_url( request_type, request_data ); + std::string url = choose_request_url( request_type, request_data, request_get_data ); nlhr.szUrl = (char*)url.c_str( ); - nlhr.flags = NLHRF_HTTP11 | /*NLHRF_NODUMP |*/ choose_security_level( request_type ); + nlhr.flags = NLHRF_HTTP11 | NLHRF_NODUMP | choose_security_level( request_type ); nlhr.headers = get_request_headers( request_type, &nlhr.headersCount ); switch (request_type) @@ -57,7 +57,6 @@ http::response facebook_client::flap( const int request_type, std::string* reque switch ( request_type ) { case FACEBOOK_REQUEST_LOGIN: - case FACEBOOK_REQUEST_SETUP_MACHINE: nlhr.nlc = NULL; break; @@ -111,6 +110,9 @@ http::response facebook_client::flap( const int request_type, std::string* reque // is compaired in all communication requests } + if (DBGetContactSettingByte( NULL, parent->m_szModuleName, FACEBOOK_KEY_VALIDATE_RESPONSE, 0 ) == 1) + validate_response(&resp); + return resp; } @@ -122,7 +124,13 @@ bool facebook_client::validate_response( http::response* resp ) return false; } -/* std::string cookie = utils::text::source_get_value(&resp->data, 2, "setCookie(\\\"", ");"); + if (DBGetContactSettingByte( NULL, parent->m_szModuleName, FACEBOOK_KEY_VALIDATE_RESPONSE, 0 ) == 2) { + return true; + } + +/* + // TODO: Is this from jarvis? Or me? Add it? + std::string cookie = utils::text::source_get_value(&resp->data, 2, "setCookie(\\\"", ");"); if (!cookie.empty()) { std::string cookie_name = utils::text::source_get_value(&cookie, 1, "\\\""); std::string cookie_value = utils::text::source_get_value(&cookie, 3, "\\\"", "\\\"", "\\\""); @@ -204,9 +212,10 @@ bool facebook_client::handle_error( std::string method, bool force_disconnect ) DWORD facebook_client::choose_security_level( int request_type ) { - if ( DBGetContactSettingByte( NULL, parent->m_szProtoName, FACEBOOK_KEY_FORCE_HTTPS, DEFAULT_FORCE_HTTPS ) ) { + if (this->https_) + { if ( request_type != FACEBOOK_REQUEST_MESSAGES_RECEIVE - || DBGetContactSettingByte( NULL, parent->m_szProtoName, FACEBOOK_KEY_FORCE_HTTPS_CHANNEL, DEFAULT_FORCE_HTTPS_CHANNEL ) ) + || DBGetContactSettingByte( NULL, parent->m_szModuleName, FACEBOOK_KEY_FORCE_HTTPS_CHANNEL, DEFAULT_FORCE_HTTPS_CHANNEL ) ) return NLHRF_SSL; } @@ -219,7 +228,6 @@ DWORD facebook_client::choose_security_level( int request_type ) // case FACEBOOK_REQUEST_LOGOUT: // case FACEBOOK_REQUEST_HOME: // case FACEBOOK_REQUEST_BUDDY_LIST: -// case FACEBOOK_REQUEST_FACEPILES: // case FACEBOOK_REQUEST_LOAD_FRIENDS: // case FACEBOOK_REQUEST_DELETE_FRIEND: // case FACEBOOK_REQUEST_ADD_FRIEND: @@ -232,7 +240,6 @@ DWORD facebook_client::choose_security_level( int request_type ) // case FACEBOOK_REQUEST_VISIBILITY: // case FACEBOOK_REQUEST_TABS: // case FACEBOOK_REQUEST_ASYNC: -// case FACEBOOK_REQUEST_ASYNC_GET: // case FACEBOOK_REQUEST_TYPING_SEND: default: return ( DWORD )0; @@ -246,7 +253,6 @@ int facebook_client::choose_method( int request_type ) case FACEBOOK_REQUEST_LOGIN: case FACEBOOK_REQUEST_SETUP_MACHINE: case FACEBOOK_REQUEST_BUDDY_LIST: - case FACEBOOK_REQUEST_FACEPILES: case FACEBOOK_REQUEST_STATUS_SET: case FACEBOOK_REQUEST_MESSAGE_SEND: case FACEBOOK_REQUEST_VISIBILITY: @@ -264,7 +270,6 @@ int facebook_client::choose_method( int request_type ) // case FACEBOOK_REQUEST_NOTIFICATIONS: // case FACEBOOK_REQUEST_RECONNECT: // case FACEBOOK_REQUEST_LOAD_FRIENDS: -// case FACEBOOK_REQUEST_ASYNC_GET: default: return REQUEST_GET; } @@ -272,9 +277,9 @@ int facebook_client::choose_method( int request_type ) std::string facebook_client::choose_proto( int request_type ) { - if ( DBGetContactSettingByte( NULL, parent->m_szProtoName, FACEBOOK_KEY_FORCE_HTTPS, DEFAULT_FORCE_HTTPS ) ) { + if (this->https_) { if ( request_type != FACEBOOK_REQUEST_MESSAGES_RECEIVE - || DBGetContactSettingByte( NULL, parent->m_szProtoName, FACEBOOK_KEY_FORCE_HTTPS_CHANNEL, DEFAULT_FORCE_HTTPS_CHANNEL ) ) + || DBGetContactSettingByte( NULL, parent->m_szModuleName, FACEBOOK_KEY_FORCE_HTTPS_CHANNEL, DEFAULT_FORCE_HTTPS_CHANNEL ) ) return HTTP_PROTO_SECURE; } @@ -286,7 +291,6 @@ std::string facebook_client::choose_proto( int request_type ) // case FACEBOOK_REQUEST_NOTIFICATIONS: // case FACEBOOK_REQUEST_RECONNECT: // case FACEBOOK_REQUEST_BUDDY_LIST: -// case FACEBOOK_REQUEST_FACEPILES: // case FACEBOOK_REQUEST_LOAD_FRIENDS: // case FACEBOOK_REQUEST_STATUS_SET: // case FACEBOOK_REQUEST_MESSAGE_SEND: @@ -294,7 +298,6 @@ std::string facebook_client::choose_proto( int request_type ) // case FACEBOOK_REQUEST_VISIBILITY: // case FACEBOOK_REQUEST_TABS: // case FACEBOOK_REQUEST_ASYNC: -// case FACEBOOK_REQUEST_ASYNC_GET: // case FACEBOOK_REQUEST_TYPING_SEND: // case FACEBOOK_REQUEST_DELETE_FRIEND: // case FACEBOOK_REQUEST_ADD_FRIEND: @@ -307,7 +310,7 @@ std::string facebook_client::choose_proto( int request_type ) } } -std::string facebook_client::choose_server( int request_type, std::string* data ) +std::string facebook_client::choose_server( int request_type, std::string* data, std::string* get_data ) { switch ( request_type ) { @@ -328,7 +331,6 @@ std::string facebook_client::choose_server( int request_type, std::string* data // case FACEBOOK_REQUEST_LOGOUT: // case FACEBOOK_REQUEST_HOME: // case FACEBOOK_REQUEST_BUDDY_LIST: -// case FACEBOOK_REQUEST_FACEPILES: // case FACEBOOK_REQUEST_LOAD_FRIENDS: // case FACEBOOK_REQUEST_FEEDS: // case FACEBOOK_REQUEST_NOTIFICATIONS: @@ -338,7 +340,6 @@ std::string facebook_client::choose_server( int request_type, std::string* data // case FACEBOOK_REQUEST_VISIBILITY: // case FACEBOOK_REQUEST_TABS: // case FACEBOOK_REQUEST_ASYNC: -// case FACEBOOK_REQUEST_ASYNC_GET: // case FACEBOOK_REQUEST_TYPING_SEND: // case FACEBOOK_REQUEST_SETUP_MACHINE: // case FACEBOOK_REQUEST_DELETE_FRIEND: @@ -348,7 +349,7 @@ std::string facebook_client::choose_server( int request_type, std::string* data } } -std::string facebook_client::choose_action( int request_type, std::string* data ) +std::string facebook_client::choose_action( int request_type, std::string* data, std::string* get_data ) { switch ( request_type ) { @@ -367,13 +368,10 @@ std::string facebook_client::choose_action( int request_type, std::string* data case FACEBOOK_REQUEST_BUDDY_LIST: return "/ajax/chat/buddy_list.php?__a=1"; - case FACEBOOK_REQUEST_FACEPILES: - return "/ajax/groups/chat/update_facepiles.php?__a=1"; - case FACEBOOK_REQUEST_LOAD_FRIENDS: { - std::string action = "/ajax/chat/user_info_all.php?__a=1&viewer=%s"; - utils::text::replace_first( &action, "%s", self_.user_id ); + std::string action = "/ajax/chat/user_info_all.php?__a=1&viewer=%s&__user=%s"; + utils::text::replace_all( &action, "%s", self_.user_id ); return action; } @@ -391,16 +389,17 @@ std::string facebook_client::choose_action( int request_type, std::string* data { std::string action = "/ajax/intent.php?filter="; action += get_newsfeed_type(); - action += "&request_type=1&__a=1&newest=%s&ignore_self=true"; + action += "&request_type=4&__a=1&newest=%s&ignore_self=true&load_newer=true&__user=%s"; std::string newest = utils::conversion::to_string((void*)&this->last_feeds_update_, UTILS_CONV_TIME_T); utils::text::replace_first( &action, "%s", newest ); + utils::text::replace_first( &action, "%s", self_.user_id ); return action; } case FACEBOOK_REQUEST_NOTIFICATIONS: { - std::string action = "/ajax/notifications/get.php?__a=1&user=%s&time=0&version=2"; - utils::text::replace_first( &action, "%s", self_.user_id ); + std::string action = "/ajax/notifications/get.php?__a=1&user=%s&time=0&version=2&__user=%s"; + utils::text::replace_all( &action, "%s", self_.user_id ); return action; } @@ -409,7 +408,7 @@ std::string facebook_client::choose_action( int request_type, std::string* data std::string action = "/ajax/presence/reconnect.php?__a=1&reason=%s&fb_dtsg=%s&post_form_id=%s&__user=%s"; if (this->chat_reconnect_reason_.empty()) - this->chat_reconnect_reason_ = "0"; // 6? + this->chat_reconnect_reason_ = "6"; utils::text::replace_first( &action, "%s", this->chat_reconnect_reason_ ); utils::text::replace_first( &action, "%s", this->dtsg_ ); @@ -440,18 +439,17 @@ std::string facebook_client::choose_action( int request_type, std::string* data } case FACEBOOK_REQUEST_VISIBILITY: - return "/ajax/chat/visibility.php?__a=1"; + return "/ajax/chat/privacy/visibility.php?__a=1"; case FACEBOOK_REQUEST_TABS: return "/ajax/chat/tabs.php?__a=1"; case FACEBOOK_REQUEST_ASYNC: - return "/ajax/messaging/async.php?__a=1"; - - case FACEBOOK_REQUEST_ASYNC_GET: { - std::string action = "/ajax/messaging/async.php?__a=1&%s"; - utils::text::replace_first( &action, "%s", (*data) ); + std::string action = "/ajax/messaging/async.php?__a=1"; + if (get_data != NULL) { + action += "&" + (*get_data); + } return action; } @@ -463,11 +461,11 @@ std::string facebook_client::choose_action( int request_type, std::string* data } } -std::string facebook_client::choose_request_url( int request_type, std::string* data ) +std::string facebook_client::choose_request_url( int request_type, std::string* data, std::string* get_data ) { std::string url = choose_proto( request_type ); - url.append( choose_server( request_type, data ) ); - url.append( choose_action( request_type, data ) ); + url.append( choose_server( request_type, data, get_data ) ); + url.append( choose_action( request_type, data, get_data ) ); return url; } @@ -478,14 +476,12 @@ NETLIBHTTPHEADER* facebook_client::get_request_headers( int request_type, int* h case FACEBOOK_REQUEST_LOGIN: case FACEBOOK_REQUEST_SETUP_MACHINE: case FACEBOOK_REQUEST_BUDDY_LIST: - case FACEBOOK_REQUEST_FACEPILES: case FACEBOOK_REQUEST_LOAD_FRIENDS: case FACEBOOK_REQUEST_STATUS_SET: case FACEBOOK_REQUEST_MESSAGE_SEND: case FACEBOOK_REQUEST_VISIBILITY: case FACEBOOK_REQUEST_TABS: case FACEBOOK_REQUEST_ASYNC: - case FACEBOOK_REQUEST_ASYNC_GET: case FACEBOOK_REQUEST_TYPING_SEND: case FACEBOOK_REQUEST_DELETE_FRIEND: case FACEBOOK_REQUEST_ADD_FRIEND: @@ -509,14 +505,12 @@ NETLIBHTTPHEADER* facebook_client::get_request_headers( int request_type, int* h case FACEBOOK_REQUEST_LOGIN: case FACEBOOK_REQUEST_SETUP_MACHINE: case FACEBOOK_REQUEST_BUDDY_LIST: - case FACEBOOK_REQUEST_FACEPILES: case FACEBOOK_REQUEST_LOAD_FRIENDS: case FACEBOOK_REQUEST_STATUS_SET: case FACEBOOK_REQUEST_MESSAGE_SEND: case FACEBOOK_REQUEST_VISIBILITY: case FACEBOOK_REQUEST_TABS: case FACEBOOK_REQUEST_ASYNC: - case FACEBOOK_REQUEST_ASYNC_GET: case FACEBOOK_REQUEST_TYPING_SEND: case FACEBOOK_REQUEST_DELETE_FRIEND: case FACEBOOK_REQUEST_ADD_FRIEND: @@ -661,12 +655,13 @@ bool facebook_client::login(const std::string &username,const std::string &passw if ( resp.code == HTTP_CODE_FOUND && resp.headers.find("Location") != resp.headers.end() ) { // Check whether HTTPS connection is required and we don't have enabled it - if ( !DBGetContactSettingByte( NULL, parent->m_szProtoName, FACEBOOK_KEY_FORCE_HTTPS, DEFAULT_FORCE_HTTPS ) ) + if (!this->https_) { if ( resp.headers["Location"].find("https://") != std::string::npos ) { client_notify(TranslateT("Your account requires HTTPS connection. Activating.")); - DBWriteContactSettingByte( NULL, parent->m_szProtoName, FACEBOOK_KEY_FORCE_HTTPS, 1 ); + DBWriteContactSettingByte(NULL, parent->m_szModuleName, FACEBOOK_KEY_FORCE_HTTPS, 1); + this->https_ = true; } } @@ -819,7 +814,7 @@ bool facebook_client::home( ) this->logout_hash_ = utils::text::source_get_value( &resp.data, 2, "Log(" Got self logout hash: %s", this->logout_hash_.c_str()); - + // TODO: DIrectly get that friend requests // Get friend requests count and notify it std::string str_count = utils::text::source_get_value( &resp.data, 2, "", "" ); if ( str_count.length() && str_count != std::string( "0" ) ) @@ -842,8 +837,6 @@ bool facebook_client::home( ) parent->NotifyEvent( parent->m_tszUserName, tmessage, NULL, FACEBOOK_EVENT_OTHER, TEXT(FACEBOOK_URL_MESSAGES) ); mir_free( tmessage ); } - } else { // Parse messages directly for contacts - ForkThread( &FacebookProto::ProcessUnreadMessages, this->parent, NULL ); } str_count = utils::text::source_get_value( &resp.data, 2, "", "" ); @@ -891,13 +884,14 @@ bool facebook_client::chat_state( bool online ) handle_entry( "chat_state" ); std::string data = "visibility="; - data += ( online ) ? "true" : "false"; + data += ( online ) ? "1" : "0"; data += "&window_id=0"; data += "&post_form_id="; data += ( post_form_id_.length( ) ) ? post_form_id_ : "0"; data += "&post_form_id_source=AsyncRequest"; data += "&fb_dtsg=" + this->dtsg_; - data += "&lsd="; + data += "&lsd=&phstamp=0&__user="; + data += self_.user_id; http::response resp = flap( FACEBOOK_REQUEST_VISIBILITY, &data ); return handle_success( "chat_state" ); @@ -986,51 +980,6 @@ bool facebook_client::buddy_list( ) } } -bool facebook_client::facepiles( ) -{ - handle_entry( "facepiles" ); - - int count = (int)CallServiceSync(MS_GC_GETSESSIONCOUNT, 0, (LPARAM)parent->m_szModuleName); - for ( int i = 0; i < count; i++ ) { - GC_INFO gci = {0}; - gci.Flags = BYINDEX | TYPE | ID; - gci.iItem = i; - gci.pszModule = parent->m_szModuleName; - if ( !CallServiceSync( MS_GC_GETINFO, 0, (LPARAM)&gci ) && gci.iType == GCW_CHATROOM ) { - char *id = mir_t2a(gci.pszID); - - // Prepare data - std::string data = "id="; - data += id; - data += "&post_form_id=" + this->post_form_id_ + "&fb_dtsg=" + this->dtsg_ + "&lsd=&post_form_id_source=AsyncRequest&__user=" + this->self_.user_id + "&phstamp=0"; - - // Get facepiles - http::response resp = flap( FACEBOOK_REQUEST_FACEPILES, &data ); - - // Process result data - validate_response(&resp); - - std::string chat_id = id; - mir_free(id); - - switch ( resp.code ) - { - case HTTP_CODE_OK: - ForkThread( &FacebookProto::ProcessFacepiles, this->parent, new send_chat(chat_id, resp.data) ); - break; - - case HTTP_CODE_FAKE_ERROR: - case HTTP_CODE_FAKE_DISCONNECTED: - default: - return handle_error( "facepiles" ); - } - - } - } - - return handle_success( "facepiles" ); -} - bool facebook_client::load_friends( ) { handle_entry( "load_friends" ); @@ -1066,18 +1015,12 @@ bool facebook_client::feeds( ) // Process result data validate_response(&resp); - std::string::size_type pos = 0; switch ( resp.code ) { case HTTP_CODE_OK: - pos = resp.data.find( "\"storyCount\":" ); - if ( pos != std::string::npos ) - { - if (resp.data.substr( pos + 13, 1 ) != "0") - { - std::string* response_data = new std::string( resp.data ); - ForkThread( &FacebookProto::ProcessFeeds, this->parent, ( void* )response_data ); - } + if (resp.data.find("\"num_stories\":0") == std::string::npos) { + std::string* response_data = new std::string( resp.data ); + ForkThread( &FacebookProto::ProcessFeeds, this->parent, ( void* )response_data ); } return handle_success( "feeds" ); @@ -1276,6 +1219,8 @@ void facebook_client::close_chat( std::string message_recipient ) data += "&post_form_id_source=AsyncRequest"; data += "&fb_dtsg="; data += ( this->dtsg_.length( ) ) ? this->dtsg_ : "0"; + data += "&__user="; + data += self_.user_id; http::response resp = flap( FACEBOOK_REQUEST_TABS, &data ); } @@ -1290,7 +1235,8 @@ void facebook_client::chat_mark_read( std::string message_recipient ) data += ( post_form_id_.length( ) ) ? post_form_id_ : "0"; data += "&fb_dtsg="; data += ( this->dtsg_.length( ) ) ? this->dtsg_ : "0"; - data += "&post_form_id_source=AsyncRequest&lsd="; + data += "&post_form_id_source=AsyncRequest&lsd=&__user="; + data += self_.user_id; http::response resp = flap( FACEBOOK_REQUEST_ASYNC, &data ); } @@ -1338,7 +1284,7 @@ bool facebook_client::save_url(const std::string &url,const std::string &filenam NETLIBHTTPREQUEST *resp; req.requestType = REQUEST_GET; req.szUrl = const_cast(url.c_str()); - req.flags = NLHRF_HTTP11 | NLHRF_REDIRECT | NLHRF_PERSISTENT; + req.flags = NLHRF_HTTP11 | NLHRF_REDIRECT | NLHRF_PERSISTENT | NLHRF_NODUMP; req.nlc = nlc; resp = reinterpret_cast(CallService( MS_NETLIB_HTTPTRANSACTION, diff --git a/FacebookRM/connection.cpp b/FacebookRM/connection.cpp index d26b9a3..d60b1ec 100644 --- a/FacebookRM/connection.cpp +++ b/FacebookRM/connection.cpp @@ -91,6 +91,9 @@ void FacebookProto::ChangeStatus(void*) facy.load_friends(); + if (getByte(FACEBOOK_KEY_PARSE_MESSAGES, DEFAULT_PARSE_MESSAGES)) + ForkThread( &FacebookProto::ProcessUnreadMessages, this ); + setDword( "LogonTS", (DWORD)time(NULL) ); ForkThread( &FacebookProto::UpdateLoop, this ); ForkThread( &FacebookProto::MessageLoop, this ); @@ -123,7 +126,6 @@ void FacebookProto::ChangeStatus(void*) facy.chat_state( m_iDesiredStatus != ID_STATUS_INVISIBLE ); facy.buddy_list( ); - facy.facepiles( ); m_iStatus = facy.self_.status_id = m_iDesiredStatus; ProtoBroadcastAck(m_szModuleName, 0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); @@ -175,6 +177,9 @@ bool FacebookProto::NegotiateConnection( ) DBFreeVariant(&dbv); } + // Get info about secured connection + facy.https_ = DBGetContactSettingByte(NULL, m_szModuleName, FACEBOOK_KEY_FORCE_HTTPS, DEFAULT_FORCE_HTTPS ) != 0; + return facy.login( user, pass ); } @@ -189,9 +194,6 @@ void FacebookProto::UpdateLoop(void *) if ( !facy.invisible_ ) if ( !facy.buddy_list( ) ) break; - if ( getByte( FACEBOOK_KEY_ENABLE_GROUPCHATS, DEFAULT_ENABLE_GROUPCHATS) ) - if ( !facy.facepiles( ) ) - break; } if ( i == 2 && getByte( FACEBOOK_KEY_EVENT_FEEDS_ENABLE, DEFAULT_EVENT_FEEDS_ENABLE ) ) if ( !facy.feeds( ) ) @@ -202,6 +204,7 @@ void FacebookProto::UpdateLoop(void *) LOG( "***** FacebookProto::UpdateLoop[%d] waking up...", tim ); } + ResetEvent(update_loop_lock_); LOG( "<<<<< Exiting FacebookProto::UpdateLoop[%d]", tim ); } diff --git a/FacebookRM/constants.h b/FacebookRM/constants.h index f02283b..3e0aaac 100644 --- a/FacebookRM/constants.h +++ b/FacebookRM/constants.h @@ -23,13 +23,12 @@ along with this program. If not, see . #pragma once // Version management -#include "build.h" -#define __VERSION_DWORD PLUGIN_MAKE_VERSION(0, 0, 8, 0) -#define __VERSION_STRING "0.0.8.0" +#define __VERSION_DWORD PLUGIN_MAKE_VERSION(0, 0, 8, 1) +#define __VERSION_STRING "0.0.8.1" // Product management #define FACEBOOK_NAME "Facebook" -#define FACEBOOK_URL_HOMEPAGE "http://www.facebook.com/" +#define FACEBOOK_URL_HOMEPAGE "http://www.facebook.com" #define FACEBOOK_URL_REQUESTS "http://www.facebook.com/n/?reqs.php" #define FACEBOOK_URL_MESSAGES "http://www.facebook.com/n/?inbox" #define FACEBOOK_URL_NOTIFICATIONS "http://www.facebook.com/n/?notifications.php" @@ -94,7 +93,6 @@ along with this program. If not, see . #define FACEBOOK_REQUEST_LOAD_FRIENDS 121 // getting list of all friends #define FACEBOOK_REQUEST_DELETE_FRIEND 122 // deleting friends #define FACEBOOK_REQUEST_ADD_FRIEND 123 // adding friends -#define FACEBOOK_REQUEST_FACEPILES 124 // getting list of contacts in chat #define FACEBOOK_REQUEST_FEEDS 125 // getting feeds #define FACEBOOK_REQUEST_NOTIFICATIONS 126 // getting notifications #define FACEBOOK_REQUEST_RECONNECT 130 // getting __sequence_num__ and __channel_id__ @@ -103,9 +101,8 @@ along with this program. If not, see . #define FACEBOOK_REQUEST_MESSAGES_RECEIVE 301 // receiving messages #define FACEBOOK_REQUEST_TYPING_SEND 304 // sending typing notification #define FACEBOOK_REQUEST_VISIBILITY 305 // setting chat visibility -#define FACEBOOK_REQUEST_TABS 306 // closing message window, setting chat visibility +#define FACEBOOK_REQUEST_TABS 306 // closing message window #define FACEBOOK_REQUEST_ASYNC 307 // marking messages read and getting other things -#define FACEBOOK_REQUEST_ASYNC_GET 308 // GET version of async request #define FACEBOOK_RECV_MESSAGE 1 #define FACEBOOK_SEND_MESSAGE 2 @@ -116,10 +113,10 @@ static const struct const char *name; const char *id; } feed_types[] = { - { "Most Recent", "lf" }, - { "Status Updates", "app_2915120374" }, - { "Top News", "h" }, + { "Most Recent", "lf_" }, //h_chr? + { "Wall Posts", "app_2915120374" }, + { "Top News", "h_nor" }, //h { "Photos", "app_2305272732_2392950137" }, { "Links", "app_2309869772" }, - + { "Apps and Games", "appsandgames" }, }; \ No newline at end of file diff --git a/FacebookRM/contacts.cpp b/FacebookRM/contacts.cpp index 0b50411..2a2cf4b 100644 --- a/FacebookRM/contacts.cpp +++ b/FacebookRM/contacts.cpp @@ -82,11 +82,13 @@ HANDLE FacebookProto::AddToContactList(facebook_user* fbu, bool dont_check, cons { DBWriteContactSettingString(hContact,m_szModuleName,FACEBOOK_KEY_ID,fbu->user_id.c_str()); - std::string homepage = FACEBOOK_URL_PROFILE; - homepage += fbu->user_id; - DBWriteContactSettingString(hContact,m_szModuleName,"Homepage",homepage.c_str()); + std::string homepage = FACEBOOK_URL_PROFILE + fbu->user_id; + DBWriteContactSettingString(hContact, m_szModuleName,"Homepage", homepage.c_str()); + + DBWriteContactSettingString(hContact, m_szModuleName, "MirVer", FACEBOOK_NAME); DBDeleteContactSetting(hContact, "CList", "MyHandle"); + DBVARIANT dbv; if( !DBGetContactSettingTString(NULL,m_szModuleName,FACEBOOK_KEY_DEF_GROUP,&dbv) ) { @@ -135,18 +137,17 @@ void FacebookProto::DeleteContactFromServer(void *data) if ( data == NULL ) return; - std::string *id = (std::string*)data; + std::string id = (*(std::string*)data); + delete data; std::string query = "norefresh=false&post_form_id_source=AsyncRequest&lsd=&fb_dtsg="; query += facy.dtsg_; query += "&post_form_id="; query += facy.post_form_id_; query += "&uid="; - query += *id; + query += id; query += "&__user="; - query += facy.self_.user_id; - - delete data; + query += facy.self_.user_id; // Get unread inbox threads http::response resp = facy.flap( FACEBOOK_REQUEST_DELETE_FRIEND, &query ); @@ -154,12 +155,26 @@ void FacebookProto::DeleteContactFromServer(void *data) // Process result data facy.validate_response(&resp); - if (resp.code != HTTP_CODE_OK) { - facy.handle_error( "DeleteContactFromServer" ); + if (resp.data.find("\"success\":true", 0) != std::string::npos) { + + // TODO: do only when operation is successful + facebook_user* fbu = facy.buddies.find( id ); + if (fbu != NULL) { + fbu->deleted = true; + // TODO: change type of contact in database... + DBWriteContactSettingWord(fbu->handle, m_szModuleName, "Status", ID_STATUS_OFFLINE); // set offline status + + // TODO: if not in actual buddies list, search in database... + DBWriteContactSettingDword(fbu->handle, m_szModuleName, FACEBOOK_KEY_DELETED, ::time(NULL)); // set deleted time + } + + NotifyEvent(TranslateT("Deleting contact"), TranslateT("Contact was sucessfully removed from server."), NULL, FACEBOOK_EVENT_OTHER, NULL); + } else { + facy.client_notify( TranslateT("Error occured when removing contact from server.") ); } - // TODO: better notify - check result code - NotifyEvent(TranslateT("Deleting contact"), TranslateT("Contact was sucessfully removed from server."), NULL, FACEBOOK_EVENT_OTHER, NULL); + if (resp.code != HTTP_CODE_OK) + facy.handle_error( "DeleteContactFromServer" ); } void FacebookProto::AddContactToServer(void *data) @@ -188,11 +203,21 @@ void FacebookProto::AddContactToServer(void *data) // Process result data facy.validate_response(&resp); - if (resp.code != HTTP_CODE_OK || resp.data.find("\"success\":true") == std::string::npos) { - facy.handle_error( "AddContactToServer" ); + if (resp.data.find("\"success\":true", 0) != std::string::npos) { + /*facebook_user* fbu = facy.buddies.find( id ); + if (fbu != NULL) { + // TODO: change type of contact in database... + // TODO: if not in actual buddies list, search in database... + }*/ + + NotifyEvent(TranslateT("Adding contact"), TranslateT("Request for friendship was sent successfully."), NULL, FACEBOOK_EVENT_OTHER, NULL); + } else { + facy.client_notify( TranslateT("Error occured when requesting friendship.") ); } -// RM TODO: better notify... - check result code - NotifyEvent(TranslateT("Adding contact"), TranslateT("Request for friendship was sent successfully."), NULL, FACEBOOK_EVENT_OTHER, NULL); + + if (resp.code != HTTP_CODE_OK) + facy.handle_error( "AddContactToServer" ); + } @@ -213,7 +238,7 @@ int FacebookProto::OnContactDeleted(WPARAM wparam,LPARAM) } else if( !DBGetContactSettingTString(hContact,m_szModuleName,FACEBOOK_KEY_ID,&dbv) ) { mir_sntprintf(text,SIZEOF(text),TranslateT("Do you want to delete contact '%s' from server list?"),dbv.ptszVal); DBFreeVariant(&dbv); - } + } if (MessageBox( 0, text, m_tszUserName, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2 ) == IDYES) { @@ -221,20 +246,17 @@ int FacebookProto::OnContactDeleted(WPARAM wparam,LPARAM) { if (!isOffline()) { // TODO: is this needed? std::string* id = new std::string(dbv.pszVal); + + facebook_user* fbu = facy.buddies.find( (*id) ); + if (fbu != NULL) { + fbu->handle = NULL; + } + ForkThread( &FacebookProto::DeleteContactFromServer, this, ( void* )id ); DBFreeVariant(&dbv); } } - } - - //ScopedLock s(facy.buddies_lock_); - for (List::Item< facebook_user >* i = facy.buddies.begin( ); i != NULL; i = i->next ) - { - if (hContact == i->data->handle) - { - facy.buddies.erase(i->key); - break; - } + } return 0; diff --git a/FacebookRM/db.h b/FacebookRM/db.h index 5efcefe..d928300 100644 --- a/FacebookRM/db.h +++ b/FacebookRM/db.h @@ -67,6 +67,7 @@ along with this program. If not, see . #define FACEBOOK_KEY_POLL_RATE "PollRate" // [HIDDEN] #define FACEBOOK_KEY_TIMEOUTS_LIMIT "TimeoutsLimit" // [HIDDEN] #define FACEBOOK_KEY_DISABLE_LOGOUT "DisableLogout" // [HIDDEN] +#define FACEBOOK_KEY_VALIDATE_RESPONSE "ValidateResponse" // [HIDDEN] - 0 = standard, 1 = always, 2 = never #define FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE "EventNotificationsEnable" #define FACEBOOK_KEY_EVENT_FEEDS_ENABLE "EventFeedsEnable" diff --git a/FacebookRM/entities.h b/FacebookRM/entities.h index e6fea18..dbe32b8 100644 --- a/FacebookRM/entities.h +++ b/FacebookRM/entities.h @@ -34,6 +34,7 @@ struct facebook_user std::string image_url; + bool deleted; facebook_user( ) { @@ -41,6 +42,7 @@ struct facebook_user this->user_id = this->real_name = this->image_url = ""; this->status_id = ID_STATUS_OFFLINE; this->gender = 0; + this->deleted = false; } facebook_user( facebook_user* fu ) @@ -51,6 +53,7 @@ struct facebook_user this->status_id = fu->status_id; this->user_id = fu->user_id; this->gender = fu->gender; + this->deleted = fu->deleted; } }; diff --git a/FacebookRM/events.cpp b/FacebookRM/events.cpp index 967d878..2f93a58 100644 --- a/FacebookRM/events.cpp +++ b/FacebookRM/events.cpp @@ -48,16 +48,11 @@ LRESULT CALLBACK PopupDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa TCHAR* data = (TCHAR*)PUGetPluginData(hwnd); if (data != NULL) { -// char *url = mir_t2a_cp(data,CP_UTF8); - std::string url2 = mir_t2a_cp(data,CP_UTF8); - std::string url = "http://www.facebook.com"; - if ( url2.substr(0,4) != "http" ) - { - url.append(url2); - CallService(MS_UTILS_OPENURL, (WPARAM) 1, (LPARAM) url.c_str() ); - } else { - CallService(MS_UTILS_OPENURL, (WPARAM) 1, (LPARAM) url2.c_str() ); - } + std::string url = mir_t2a_cp(data,CP_UTF8); + if ( url.substr(0,4) != "http" ) + url = FACEBOOK_URL_HOMEPAGE + url; // make absolute url + + CallService(MS_UTILS_OPENURL, (WPARAM) 1, (LPARAM) url.c_str() ); } // After a click, destroy popup diff --git a/FacebookRM/facebook.rc b/FacebookRM/facebook.rc index 4004191..7f66333 100644 --- a/FacebookRM/facebook.rc +++ b/FacebookRM/facebook.rc @@ -255,7 +255,7 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,0,8,0 + FILEVERSION 0,0,8,1 PRODUCTVERSION 0,9,43,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG @@ -272,7 +272,7 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "Facebook protocol plugin for Miranda IM" - VALUE "FileVersion", "0.0.8.0" + VALUE "FileVersion", "0.0.8.1" VALUE "InternalName", "Facebook RM" VALUE "LegalCopyright", "Copyright © 2009-2011 Michal Zelinka, 2011-2012 Robert Pösel" VALUE "OriginalFilename", "facebook.dll" diff --git a/FacebookRM/facebook_10.vcxproj.filters b/FacebookRM/facebook_10.vcxproj.filters index 5239871..df7e784 100644 --- a/FacebookRM/facebook_10.vcxproj.filters +++ b/FacebookRM/facebook_10.vcxproj.filters @@ -83,9 +83,6 @@ Header Files - - Header Files - Header Files @@ -119,15 +116,18 @@ Header Files - - Header Files - Header Files Resource Files + + Header Files + + + Header Files + diff --git a/FacebookRM/json.cpp b/FacebookRM/json.cpp index 93fa30e..4293f33 100644 --- a/FacebookRM/json.cpp +++ b/FacebookRM/json.cpp @@ -140,83 +140,6 @@ int facebook_json_parser::parse_buddy_list( void* data, List::List< facebook_use return EXIT_SUCCESS; } -int facebook_json_parser::parse_facepiles( void* data, std::map< std::string, std::string > *facepiles ) -{ - using namespace json; - - try - { - std::string buddyData = static_cast< std::string* >( data )->substr( 9 ); - std::istringstream sDocument( buddyData ); - Object objDocument; - Reader::Read(objDocument, sDocument); - std::map< std::string, std::string >::iterator it; - - const Object& objRoot = objDocument; -/* const Array& infos = objRoot["payload"]["facepile_click_info"]; - - for ( Array::const_iterator info( infos.Begin() ); - info != infos.End(); ++info) - { - const Object& objMember = *info; - - if (objMember.Find("uid") != objMember.End()) { - const Number& id = objMember["uid"]; - char was_id[32]; - lltoa( id.Value(), was_id, 10 ); - - const String& name = objMember["name"]; - std::string user_name = utils::text::slashu_to_utf8( - utils::text::special_expressions_decode( name.Value() ) ); - - it = facepiles->find( std::string( was_id ) ); - if ( it == facepiles->end() ) { - facepiles->insert( std::make_pair( was_id, user_name ) ); - } - } - } */ - - // Contacts in chat are getting by parsing html response. Don't know if it will work also for many people in chat room. - const String& response_html = objRoot["payload"]["response_html"]; - std::string contacts = utils::text::slashu_to_utf8( utils::text::special_expressions_decode( response_html.Value( ) ) ); - - std::string::size_type pos = 0; - while ((pos = contacts.find("") - pos); - - std::string status = utils::text::source_get_value2( &row, "chat", "\" " ); // "Online" or "Idle" - std::string name = utils::text::source_get_value( &row, 2, "title=\"", "\"" ); - std::string id = utils::text::source_get_value( &row, 3, "href=\"", "/profile.php?id=", "\"" ); - if (id.empty()) - id = utils::text::source_get_value( &row, 3, "href=\"", "facebook.com/", "\"" ); - - it = facepiles->find( id ); - if ( it == facepiles->end() ) { - facepiles->insert( std::make_pair( id, name ) ); - } - - pos++; - } - - } - catch (Reader::ParseException& e) - { - proto->Log( "!!!!! Caught json::ParseException: %s", e.what() ); - proto->Log( " Line/offset: %d/%d", e.m_locTokenBegin.m_nLine + 1, e.m_locTokenBegin.m_nLineOffset + 1 ); - } - catch (const Exception& e) - { - proto->Log( "!!!!! Caught json::Exception: %s", e.what() ); - } - catch (const std::exception& e) - { - proto->Log( "!!!!! Caught std::exception: %s", e.what() ); - } - - return EXIT_SUCCESS; -} - - int facebook_json_parser::parse_friends( void* data, std::map< std::string, facebook_user* >* friends ) { using namespace json; @@ -289,24 +212,27 @@ int facebook_json_parser::parse_notifications( void *data, std::vector< facebook Reader::Read(objDocument, sDocument); const Object& objRoot = objDocument; - const Object& payload = objRoot["payload"]["markup_map"]; + const Object& payload = objRoot["payload"]["notifications"]; for ( Object::const_iterator payload_item( payload.Begin() ); payload_item != payload.End(); ++payload_item) { const Object::Member& member = *payload_item; + + const Object& objMember = member.element; - const String& content = member.element; - + const String& content = objMember["markup"]; + const Number& unread = objMember["unread"]; + + if (unread.Value() == 0) // ignore old notifications + continue; + std::string text = utils::text::slashu_to_utf8( utils::text::special_expressions_decode( content.Value() ) ); - if (text.find("jewelItemNew") == std::string::npos) - continue; // we want only unread notifications - facebook_notification* notification = new facebook_notification( ); notification->text = utils::text::remove_html( utils::text::source_get_value(&text, 1, "link = utils::text::source_get_value(&text, 2, "link = utils::text::source_get_value(&text, 3, "push_back( notification ); } @@ -377,7 +303,7 @@ int facebook_json_parser::parse_messages( void* data, std::vector< facebook_mess facebook_message* message = new facebook_message( ); message->message_text = utils::text::special_expressions_decode( utils::text::slashu_to_utf8( text.Value( ) ) ); - message->time = ::time( NULL ); + message->time = ::time( NULL ); // TODO: use real time from facebook message->user_id = was_id; messages->push_back( message ); @@ -425,7 +351,7 @@ int facebook_json_parser::parse_messages( void* data, std::vector< facebook_mess message->sender_name = utils::text::special_expressions_decode( utils::text::slashu_to_utf8( sender_name.Value( ) ) ); - message->time = ::time( NULL ); + message->time = ::time( NULL ); // TODO: user real time from facebook message->user_id = was_id; // TODO: Check if we have contact with this ID in friendlist and then do something different? if (row.find("uiSplitPic",0) != std::string::npos) { diff --git a/FacebookRM/json.h b/FacebookRM/json.h index e2a55b2..c83e1ef 100644 --- a/FacebookRM/json.h +++ b/FacebookRM/json.h @@ -31,7 +31,6 @@ class facebook_json_parser public: FacebookProto* proto; int parse_buddy_list( void*, List::List< facebook_user >* ); - int parse_facepiles( void*, std::map< std::string, std::string >* ); int parse_friends( void*, std::map< std::string, facebook_user* >* ); int parse_notifications( void*, std::vector< facebook_notification* >* ); int parse_messages( void*, std::vector< facebook_message* >*, std::vector< facebook_notification* >* ); diff --git a/FacebookRM/messages.cpp b/FacebookRM/messages.cpp index b4c6459..d6873d6 100644 --- a/FacebookRM/messages.cpp +++ b/FacebookRM/messages.cpp @@ -131,11 +131,12 @@ void FacebookProto::SendTypingWorker(void *p) data += ( typing->status == PROTOTYPE_SELFTYPING_ON ) ? "1" : "0"; // PROTOTYPE_SELFTYPING_OFF data += "&to="; data += dbv.pszVal; - data += "&source=chat"; + data += "&source=mercury-chat"; data += "&fb_dtsg=" + facy.dtsg_; data += "&post_form_id="; data += ( facy.post_form_id_.length( ) ) ? facy.post_form_id_ : "0"; - data += "&post_form_id_source=AsyncRequest&lsd="; + data += "&post_form_id_source=AsyncRequest&lsd=&phstamp=0&__user="; + data += facy.self_.user_id; http::response resp = facy.flap( FACEBOOK_REQUEST_TYPING_SEND, &data ); @@ -155,8 +156,8 @@ void FacebookProto::MessagingWorker(void *p) if (data->type == FACEBOOK_RECV_MESSAGE) facy.chat_mark_read( data->user_id ); - if ( DBGetContactSettingByte(NULL, m_szModuleName, FACEBOOK_KEY_CLOSE_WINDOWS_ENABLE, DEFAULT_CLOSE_WINDOWS_ENABLE ) ) - facy.close_chat( data->user_id ); +// if ( DBGetContactSettingByte(NULL, m_szModuleName, FACEBOOK_KEY_CLOSE_WINDOWS_ENABLE, DEFAULT_CLOSE_WINDOWS_ENABLE ) ) +// facy.close_chat( data->user_id ); delete data; } diff --git a/FacebookRM/process.cpp b/FacebookRM/process.cpp index 6f1ea0d..4136e1b 100644 --- a/FacebookRM/process.cpp +++ b/FacebookRM/process.cpp @@ -48,11 +48,11 @@ void FacebookProto::ProcessBuddyList( void* data ) facebook_user* fbu; - if ( i->data->status_id == ID_STATUS_OFFLINE ) + if ( i->data->status_id == ID_STATUS_OFFLINE || i->data->deleted ) { fbu = i->data; - if (fbu->handle) + if (fbu->handle && !fbu->deleted) DBWriteContactSettingWord(fbu->handle, m_szModuleName, "Status", ID_STATUS_OFFLINE); std::string to_delete( i->key ); @@ -109,66 +109,6 @@ exit: delete resp; } -void FacebookProto::ProcessFacepiles( void* data ) -{ - if ( data == NULL ) - return; - - send_chat *resp = static_cast(data); - - if ( isOffline() ) - goto exit; - - LOG("***** Starting processing facepiles"); - - CODE_BLOCK_TRY - - std::map< std::string, std::string > facepiles; - - facebook_json_parser* p = new facebook_json_parser( this ); - p->parse_facepiles( &(resp->msg), &facepiles ); - delete p; - - std::map< std::string, std::string >::iterator iter; - - char *chat_users = this->GetChatUsers(resp->chat_id.c_str()); - std::string users = chat_users; - mir_free(chat_users); - - std::vector users_list; - utils::text::explode(users, " ", &users_list); - - for( std::vector::size_type i=0; iRemoveChatContact(resp->chat_id.c_str(), users_list[i].c_str()); - LOG(" Now offline facepile (%s): [%s]", resp->chat_id.c_str(), users_list[i].c_str()); - } else { - facepiles.erase(iter); - } - } - - for ( iter = facepiles.begin( ); iter != facepiles.end(); ++iter ) - { - // These contacts are newly online, add them... - this->AddChatContact(resp->chat_id.c_str(), iter->first.c_str(), iter->second.c_str()); - LOG(" Now online facepile (%s): [%s] %s", resp->chat_id.c_str(), iter->first.c_str(), iter->second.c_str()); - } - - LOG("***** Facepiles processed"); - - CODE_BLOCK_CATCH - - LOG("***** Error processing facepiles: %s", e.what()); - - CODE_BLOCK_END - -exit: - delete resp; -} - - void FacebookProto::ProcessFriendList( void* data ) { if ( data == NULL ) @@ -214,7 +154,16 @@ void FacebookProto::ProcessFriendList( void* data ) // - but what with contacts, that was added after logon? // Update gender if ( DBGetContactSettingByte(hContact, m_szModuleName, "Gender", 0) != fbu->gender ) - DBWriteContactSettingByte(hContact, m_szModuleName, "Gender", fbu->gender ); + DBWriteContactSettingByte(hContact, m_szModuleName, "Gender", fbu->gender); + + // TODO: Remove in next version + if( !DBGetContactSettingString(hContact, m_szModuleName, "MirVer", &dbv) ) { + update_required = strcmp( dbv.pszVal, FACEBOOK_NAME ) != 0; + DBFreeVariant(&dbv); + } + if (update_required) { + DBWriteContactSettingString(hContact, m_szModuleName, "MirVer", FACEBOOK_NAME); + } // Update real name if ( !DBGetContactSettingUTF8String(hContact, m_szModuleName, FACEBOOK_KEY_NAME, &dbv) ) @@ -256,7 +205,7 @@ void FacebookProto::ProcessFriendList( void* data ) // Wasnt we already been notified about this contact? if ( !DBGetContactSettingDword(hContact, m_szModuleName, FACEBOOK_KEY_DELETED, 0) && !DBGetContactSettingByte(hContact, m_szModuleName, FACEBOOK_KEY_CONTACT_TYPE, 0) ) { // And is this contact "on-server" contact? - + DBWriteContactSettingDword(hContact, m_szModuleName, FACEBOOK_KEY_DELETED, ::time(NULL)); std::string contactname = id; @@ -306,13 +255,23 @@ void FacebookProto::ProcessUnreadMessages( void* ) { facy.handle_entry( "messages" ); - std::string data = "sk=inbox&query=is%3Aunread"; + std::string get_data = "sk=inbox&query=is%3Aunread"; + + std::string data = "post_form_id="; + data += ( facy.post_form_id_.length( ) ) ? facy.post_form_id_ : "0"; + data += "&fb_dtsg=" + facy.dtsg_; + data += "&post_form_id_source=AsyncRequest&lsd=&phstamp="; + data += utils::time::mili_timestamp(); + data += "&__user="; + data += facy.self_.user_id; // Get unread inbox threads - http::response resp = facy.flap( FACEBOOK_REQUEST_ASYNC_GET, &data ); + http::response resp = facy.flap( FACEBOOK_REQUEST_ASYNC, &data, &get_data ); + + // sk=inbox, sk=other // Process result data - facy.validate_response(&resp); + facy.validate_response(&resp); if (resp.code != HTTP_CODE_OK) { facy.handle_error( "messages" ); @@ -325,15 +284,16 @@ void FacebookProto::ProcessUnreadMessages( void* ) while ( ( pos = threadlist.find( "
  • ", pos ); std::string thread_content = threadlist.substr( pos, pos2 - pos ); pos = pos2; - data = "sk=inbox&query=is%3Aunread&thread_query=is%3Aunread&action=read&tid="; - data += utils::text::source_get_value( &thread_content, 2, "id=\\\"", "\\\"" ); + get_data = "sk=inbox&query=is%3Aunread&thread_query=is%3Aunread&action=read&tid="; + get_data += utils::text::source_get_value( &thread_content, 2, "id=\\\"", "\\\"" ); - resp = facy.flap( FACEBOOK_REQUEST_ASYNC_GET, &data ); + resp = facy.flap( FACEBOOK_REQUEST_ASYNC, &data, &get_data ); + // TODO: move this to new thread... facy.validate_response(&resp); @@ -342,7 +302,7 @@ void FacebookProto::ProcessUnreadMessages( void* ) continue; } - std::string messageslist = utils::text::slashu_to_utf8(resp.data); + std::string messageslist = utils::text::slashu_to_utf8(resp.data); std::string user_id = utils::text::source_get_value( &messageslist, 2, "single_thread_id\":", "," ); if (user_id.empty()) { @@ -350,38 +310,96 @@ void FacebookProto::ProcessUnreadMessages( void* ) continue; } - messageslist = utils::text::source_get_value( &messageslist, 3, "class=\\\"MessagingMessage", "MessagingMessageUnread", "class=\\\"MessagingComposer" ); - facebook_user fbu; fbu.user_id = user_id; HANDLE hContact = AddToContactList(&fbu); + // TODO: if contact is newly added, get his user info + // TODO: maybe create new "receiveMsg" function and use it for offline and channel messages? - pos2 = 0; - while ( ( pos2 = messageslist.find( "class=\\\"content noh", pos2 ) ) != std::string::npos ) - { - std::string message_text; - message_text = messageslist.substr(pos2, messageslist.find( "<\\/div", pos2) + 6 - pos2); - message_text = utils::text::source_get_value( &message_text, 2, "\\\">", "<\\/div" ); - message_text = utils::text::trim( - utils::text::special_expressions_decode( - utils::text::remove_html( message_text ) ) ); + pos2 = 0; + while ( ( pos2 = messageslist.find( "class=\\\"MessagingMessage ", pos2 ) ) != std::string::npos ) { + pos2 += 8; + std::string strclass = messageslist.substr(pos2, messageslist.find("\\\"", pos2) - pos2); - PROTORECVEVENT recv = {0}; - CCSDATA ccs = {0}; + if (strclass.find("MessagingMessageUnread") == std::string::npos) + continue; // ignoring old messages - recv.flags = PREF_UTF; - recv.szMessage = const_cast(message_text.c_str()); - recv.timestamp = static_cast(::time(NULL)); + //std::string::size_type pos3 = messageslist.find( "/li>", pos2 ); // TODO: ne proti tomuhle li, protože i přílohy mají li... + std::string::size_type pos3 = messageslist.find( "class=\\\"MessagingMessage ", pos2 ); + std::string messagesgroup = messageslist.substr( pos2, pos3 - pos2 ); - ccs.hContact = hContact; - ccs.szProtoService = PSR_MESSAGE; - ccs.lParam = reinterpret_cast(&recv); - CallService(MS_PROTO_CHAINRECV,0,reinterpret_cast(&ccs)); + DWORD timestamp = NULL; + std::string strtime = utils::text::source_get_value( &messagesgroup, 2, "data-utime=\\\"", "\\\"" ); + if (!utils::conversion::from_string(timestamp, strtime, std::dec)) { + timestamp = static_cast(::time(NULL)); + } - pos2++; - } + pos3 = 0; + while ( ( pos3 = messagesgroup.find( "class=\\\"content noh", pos3 ) ) != std::string::npos ) + { + + std::string message_attachments = ""; + std::string::size_type pos4 = 0; + if ((pos4 = messagesgroup.find( "class=\\\"attachments\\\"", pos4)) != std::string::npos) { + std::string attachments = messagesgroup.substr( pos4, messagesgroup.find("<\\/ul", pos4) - pos4 ); + + pos4 = 0; + while ( ( pos4 = attachments.find("", pos4) - pos4 ); + std::string link = utils::text::source_get_value( &attachment, 4, "", "<\\/a>" ); + std::string name = utils::text::trim( + utils::text::special_expressions_decode( + utils::text::remove_html( attachment ) ) ); + + if (link.find("/ajax/messaging/attachments/photo/dialog.php?uri=") != std::string::npos) { + link = link.substr(49); + link = utils::url::decode(link); + } + + message_attachments += "< " + name + " > " + FACEBOOK_URL_HOMEPAGE; + message_attachments += link + "\r\n"; + + pos4++; + } + + } + + std::string message_text = messagesgroup.substr(pos3, messagesgroup.find( "<\\/div", pos3 ) + 6 - pos3); + message_text = utils::text::source_get_value( &message_text, 2, "\\\">", "<\\/div" ); + message_text = utils::text::trim( + utils::text::special_expressions_decode( + utils::text::remove_html( message_text ) ) ); + + if (!message_attachments.empty()) { + if (!message_text.empty()) + message_text += "\r\n\r\n"; + + message_text += Translate("Attachments:"); + message_text += "\r\n" + message_attachments; + } + + PROTORECVEVENT recv = {0}; + CCSDATA ccs = {0}; + + recv.flags = PREF_UTF; + recv.szMessage = const_cast(message_text.c_str()); + recv.timestamp = timestamp; + + ccs.hContact = hContact; + ccs.szProtoService = PSR_MESSAGE; + ccs.lParam = reinterpret_cast(&recv); + CallService(MS_PROTO_CHAINRECV,0,reinterpret_cast(&ccs)); + + pos3++; + } + + } } @@ -418,6 +436,9 @@ void FacebookProto::ProcessMessages( void* data ) HANDLE hContact = AddToContactList(&fbu, false, messages[i]->sender_name.c_str()); + // TODO: if contact is newly added, get his user info + // TODO: maybe create new "receiveMsg" function and use it for offline and channel messages? + PROTORECVEVENT recv = {0}; CCSDATA ccs = {0}; diff --git a/FacebookRM/proto.cpp b/FacebookRM/proto.cpp index 12dfd27..692de07 100644 --- a/FacebookRM/proto.cpp +++ b/FacebookRM/proto.cpp @@ -226,16 +226,6 @@ void FacebookProto::SetAwayMsgWorker(void *) ////////////////////////////////////////////////////////////////////////////// // SERVICES -int FacebookProto::GetStatus( WPARAM wParam, LPARAM lParam ) -{ - return m_iStatus; -} - -int FacebookProto::SetStatus( WPARAM wParam, LPARAM lParam ) -{ - return SetStatus( (int)wParam ); -} - int FacebookProto::GetMyAwayMsg( WPARAM wParam, LPARAM lParam ) { DBVARIANT dbv = { DBVT_TCHAR }; @@ -296,12 +286,6 @@ int FacebookProto::OnEvent(PROTOEVENTTYPE event,WPARAM wParam,LPARAM lParam) ////////////////////////////////////////////////////////////////////////////// // EVENTS -int FacebookProto::GetName( WPARAM wParam, LPARAM lParam ) -{ - lstrcpynA(reinterpret_cast(lParam),m_szProtoName,wParam); - return 0; -} - int FacebookProto::SvcCreateAccMgrUI(WPARAM wParam,LPARAM lParam) { return (int)CreateDialogParam(g_hInstance,MAKEINTRESOURCE(IDD_FACEBOOKACCOUNT), diff --git a/FacebookRM/proto.h b/FacebookRM/proto.h index 037643a..db236b8 100644 --- a/FacebookRM/proto.h +++ b/FacebookRM/proto.h @@ -109,9 +109,6 @@ public: //////////////////////// // Services - int __cdecl GetName( WPARAM, LPARAM ); - int __cdecl GetStatus( WPARAM, LPARAM ); - int __cdecl SetStatus( WPARAM, LPARAM ); int __cdecl GetMyAwayMsg( WPARAM, LPARAM ); int __cdecl SetMyAwayMsg( WPARAM, LPARAM ); int __cdecl SvcCreateAccMgrUI( WPARAM, LPARAM ); @@ -143,7 +140,6 @@ public: // Processing threads void __cdecl ProcessBuddyList(void*); - void __cdecl ProcessFacepiles(void*); void __cdecl ProcessFriendList(void*); void __cdecl ProcessMessages(void*); void __cdecl ProcessUnreadMessages(void*); diff --git a/FacebookRM/utils.cpp b/FacebookRM/utils.cpp index 02a7662..5440757 100644 --- a/FacebookRM/utils.cpp +++ b/FacebookRM/utils.cpp @@ -32,6 +32,17 @@ std::string utils::url::encode(const std::string &s) return ret; } +std::string utils::url::decode(std::string data) +{ + // TODO: Better and universal method? + utils::text::replace_all( &data, "%2F", "/" ); + utils::text::replace_all( &data, "%3F", "?" ); + utils::text::replace_all( &data, "%3D", "=" ); + utils::text::replace_all( &data, "%26", "&" ); + + return data; +} + std::string utils::time::unix_timestamp( ) { time_t in = ::time( NULL ); diff --git a/FacebookRM/utils.h b/FacebookRM/utils.h index 6d9acb5..868aeb8 100644 --- a/FacebookRM/utils.h +++ b/FacebookRM/utils.h @@ -65,6 +65,7 @@ namespace utils namespace url { std::string encode(const std::string &s); + std::string decode(std::string data); }; namespace time @@ -96,6 +97,12 @@ namespace utils namespace conversion { std::string to_string( void*, WORD type ); + + template + bool from_string(T& t, const std::string& s, std::ios_base& (*f)(std::ios_base&)) { + std::istringstream iss(s); + return !(iss >> f >> t).fail(); + } }; namespace debug -- cgit v1.2.3