summaryrefslogtreecommitdiff
path: root/protocols
diff options
context:
space:
mode:
authorRobert Pösel <robyer@seznam.cz>2016-09-04 14:04:49 +0000
committerRobert Pösel <robyer@seznam.cz>2016-09-04 14:04:49 +0000
commit8234832e06e873df035270f162d7d151fbf6e7eb (patch)
tree200613059ddb4bc61c73fa946ca735836ee92163 /protocols
parent2f492f0c3af53dada6b909d1c31dc665c33dfde5 (diff)
Facebook: Massive rewrite of all communication requests
Note it doesn't use persistent connection yet. git-svn-id: http://svn.miranda-ng.org/main/trunk@17246 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'protocols')
-rw-r--r--protocols/FacebookRM/facebook.vcxproj12
-rw-r--r--protocols/FacebookRM/facebook.vcxproj.filters38
-rw-r--r--protocols/FacebookRM/src/client.h16
-rw-r--r--protocols/FacebookRM/src/communication.cpp712
-rw-r--r--protocols/FacebookRM/src/constants.h45
-rw-r--r--protocols/FacebookRM/src/contacts.cpp133
-rw-r--r--protocols/FacebookRM/src/http_request.h8
-rw-r--r--protocols/FacebookRM/src/messages.cpp46
-rw-r--r--protocols/FacebookRM/src/process.cpp173
-rw-r--r--protocols/FacebookRM/src/proto.cpp8
-rw-r--r--protocols/FacebookRM/src/requests/channel.h101
-rw-r--r--protocols/FacebookRM/src/requests/contacts.h191
-rw-r--r--protocols/FacebookRM/src/requests/feeds.h60
-rw-r--r--protocols/FacebookRM/src/requests/history.h167
-rw-r--r--protocols/FacebookRM/src/requests/login.h116
-rw-r--r--protocols/FacebookRM/src/requests/messages.h161
-rw-r--r--protocols/FacebookRM/src/requests/notifications.h75
-rw-r--r--protocols/FacebookRM/src/requests/profile.h83
-rw-r--r--protocols/FacebookRM/src/requests/search.h46
-rw-r--r--protocols/FacebookRM/src/requests/status.h74
-rw-r--r--protocols/FacebookRM/src/requests/utils.h195
-rw-r--r--protocols/FacebookRM/src/stdafx.h19
22 files changed, 1558 insertions, 921 deletions
diff --git a/protocols/FacebookRM/facebook.vcxproj b/protocols/FacebookRM/facebook.vcxproj
index 6d62bbe82f..8d14219953 100644
--- a/protocols/FacebookRM/facebook.vcxproj
+++ b/protocols/FacebookRM/facebook.vcxproj
@@ -29,7 +29,17 @@
<ClCompile Include="..\..\utils\std_string_utils.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
- <ClInclude Include="src\requests\*.h" />
+ <ClInclude Include="src\requests\channel.h" />
+ <ClInclude Include="src\requests\contacts.h" />
+ <ClInclude Include="src\requests\feeds.h" />
+ <ClInclude Include="src\requests\history.h" />
+ <ClInclude Include="src\requests\login.h" />
+ <ClInclude Include="src\requests\messages.h" />
+ <ClInclude Include="src\requests\search.h" />
+ <ClInclude Include="src\requests\status.h" />
+ <ClInclude Include="src\requests\profile.h" />
+ <ClInclude Include="src\requests\notifications.h" />
+ <ClInclude Include="src\requests\utils.h" />
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
diff --git a/protocols/FacebookRM/facebook.vcxproj.filters b/protocols/FacebookRM/facebook.vcxproj.filters
index aaf0565537..54b30eff0c 100644
--- a/protocols/FacebookRM/facebook.vcxproj.filters
+++ b/protocols/FacebookRM/facebook.vcxproj.filters
@@ -9,4 +9,42 @@
<Filter>Header Files\requests</Filter>
</ClInclude>
</ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\requests\channel.h">
+ <Filter>Header Files\requests</Filter>
+ </ClInclude>
+ <ClInclude Include="src\requests\chat.h">
+ <Filter>Header Files\requests</Filter>
+ </ClInclude>
+ <ClInclude Include="src\requests\contacts.h">
+ <Filter>Header Files\requests</Filter>
+ </ClInclude>
+ <ClInclude Include="src\requests\feeds.h">
+ <Filter>Header Files\requests</Filter>
+ </ClInclude>
+ <ClInclude Include="src\requests\history.h">
+ <Filter>Header Files\requests</Filter>
+ </ClInclude>
+ <ClInclude Include="src\requests\login.h">
+ <Filter>Header Files\requests</Filter>
+ </ClInclude>
+ <ClInclude Include="src\requests\messages.h">
+ <Filter>Header Files\requests</Filter>
+ </ClInclude>
+ <ClInclude Include="src\requests\notifications.h">
+ <Filter>Header Files\requests</Filter>
+ </ClInclude>
+ <ClInclude Include="src\requests\profile.h">
+ <Filter>Header Files\requests</Filter>
+ </ClInclude>
+ <ClInclude Include="src\requests\search.h">
+ <Filter>Header Files\requests</Filter>
+ </ClInclude>
+ <ClInclude Include="src\requests\status.h">
+ <Filter>Header Files\requests</Filter>
+ </ClInclude>
+ <ClInclude Include="src\requests\utils.h">
+ <Filter>Header Files\requests</Filter>
+ </ClInclude>
+ </ItemGroup>
</Project> \ No newline at end of file
diff --git a/protocols/FacebookRM/src/client.h b/protocols/FacebookRM/src/client.h
index 22297ebf26..14af119921 100644
--- a/protocols/FacebookRM/src/client.h
+++ b/protocols/FacebookRM/src/client.h
@@ -146,18 +146,18 @@ public:
// Helpers for data
- std::string __inline __dyn() {
+ __inline const char *__dyn() {
return ""; // FIXME: What's this value and where it come from? Looks like it is the same through all requests.
}
- std::string __inline __req() {
+ __inline const char *__req() {
// Increment request number and convert it to string with radix 36 (whole numbers + whole alphabet)
char buffer[10];
itoa(InterlockedIncrement(&this->chat_req_), buffer, 36);
- return std::string(buffer);
+ return ptrA(mir_strdup(buffer));
}
- std::string __inline __rev() {
+ __inline const char *__rev() {
return "2509236"; // FIXME: Some version of communication protocol? This version is from 17.8.2016
}
@@ -208,15 +208,9 @@ public:
// HTTP communication
- http::response flap(RequestType request_type, std::string *post_data = NULL, std::string *get_data = NULL);
+ http::response sendRequest(HttpRequest *request);
bool save_url(const std::string &url,const std::wstring &filename, HANDLE &nlc);
- bool notify_errors(RequestType);
- std::string choose_server(RequestType);
- std::string choose_action(RequestType, std::string *get_data = NULL);
-
- NETLIBHTTPHEADER *get_request_headers(int request_type, int *headers_count);
-
////////////////////////////////////////////////////////////
// Netlib handle
diff --git a/protocols/FacebookRM/src/communication.cpp b/protocols/FacebookRM/src/communication.cpp
index a7002d41e1..452a6fe24a 100644
--- a/protocols/FacebookRM/src/communication.cpp
+++ b/protocols/FacebookRM/src/communication.cpp
@@ -27,7 +27,7 @@ void facebook_client::client_notify(wchar_t* message)
parent->NotifyEvent(parent->m_tszUserName, message, NULL, EVENT_CLIENT);
}
-http::response facebook_client::flap(RequestType request_type, std::string *post_data, std::string *get_data)
+http::response facebook_client::sendRequest(HttpRequest *request)
{
http::response resp;
@@ -36,80 +36,56 @@ http::response facebook_client::flap(RequestType request_type, std::string *post
return resp;
}
- // Prepare the request
- NETLIBHTTPREQUEST nlhr = { sizeof(NETLIBHTTPREQUEST) };
-
- std::string server = choose_server(request_type);
-
- // Set request URL
- std::string url = HTTP_PROTO_SECURE + server + choose_action(request_type, get_data);
if (!parent->m_locale.empty())
- url += "&locale=" + parent->m_locale;
-
- nlhr.szUrl = (char*)url.c_str();
-
- // Set timeout (bigger for channel request)
- switch (request_type) {
- case REQUEST_MESSAGES_RECEIVE:
- nlhr.timeout = 1000 * 65;
- break;
-
- default:
- nlhr.timeout = 1000 * 20;
- break;
- }
-
- // Set request type (GET/POST) and eventually also POST data
- if (post_data != NULL) {
- nlhr.requestType = REQUEST_POST;
- nlhr.pData = (char*)(*post_data).c_str();
- nlhr.dataLength = (int)post_data->length();
- } else {
- nlhr.requestType = REQUEST_GET;
- }
-
- // Set headers - it depends on requestType so it must be after setting that
- nlhr.headers = get_request_headers(nlhr.requestType, &nlhr.headersCount);
+ request->Url << CHAR_VALUE("locale", parent->m_locale.c_str());
- // Set flags
- nlhr.flags = NLHRF_HTTP11 | NLHRF_SSL;
+ request->Headers
+ << CHAR_VALUE("Accept-Language", "en,en-US;q=0.9")
+ << CHAR_VALUE("Accept", "*/*")
+ << CHAR_VALUE("User-Agent", g_strUserAgent.c_str())
+ << CHAR_VALUE("Cookie", ptrA(load_cookies())); // FIXME: Rework load_cookies to not do strdup
- if (server == FACEBOOK_SERVER_MBASIC || server == FACEBOOK_SERVER_MOBILE) {
- nlhr.flags |= NLHRF_REDIRECT;
+ if (request->requestType == REQUEST_POST) {
+ request->Headers
+ << CHAR_VALUE("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
}
+ // TODO: rather change http_request than doing this ifdef magic here?
#ifdef _DEBUG
- nlhr.flags |= NLHRF_DUMPASTEXT;
+ request->flags &= ~NLHRF_NODUMP;
+ request->flags |= NLHRF_DUMPASTEXT;
#else
- nlhr.flags |= NLHRF_NODUMP;
+ request->flags &= ~NLHRF_DUMPASTEXT;
+ request->flags |= NLHRF_NODUMP;
#endif
+ // FIXME: Support persistent connection for various requests
+ /*
// Set persistent connection (or not)
switch (request_type) {
case REQUEST_LOGIN:
- nlhr.nlc = NULL;
+ request->nlc = NULL;
break;
case REQUEST_MESSAGES_RECEIVE:
- nlhr.nlc = hMsgCon;
- nlhr.flags |= NLHRF_PERSISTENT;
+ request->nlc = hMsgCon;
+ request->flags |= NLHRF_PERSISTENT;
break;
default:
WaitForSingleObject(fcb_conn_lock_, INFINITE);
- nlhr.nlc = hFcbCon;
- nlhr.flags |= NLHRF_PERSISTENT;
+ request->nlc = hFcbCon;
+ request->flags |= NLHRF_PERSISTENT;
break;
}
-
- parent->debugLogA("@@@ Sending request to '%s'", nlhr.szUrl);
+ */
+ parent->debugLogA("@@@ Sending request to '%s'", request->szUrl);
// Send the request
- NETLIBHTTPREQUEST *pnlhr = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)handle_, (LPARAM)&nlhr);
-
- mir_free(nlhr.headers[3].szValue);
- mir_free(nlhr.headers);
+ NETLIBHTTPREQUEST *pnlhr = request->Send(handle_);
+ // FIXME: Support persistent connection for various requests
+ /*
// Remember the persistent connection handle (or not)
switch (request_type) {
case REQUEST_LOGIN:
@@ -125,6 +101,7 @@ http::response facebook_client::flap(RequestType request_type, std::string *post
hFcbCon = pnlhr ? pnlhr->nlc : NULL;
break;
}
+ */
// Check and copy response data
if (pnlhr != NULL) {
@@ -134,12 +111,16 @@ http::response facebook_client::flap(RequestType request_type, std::string *post
resp.data = pnlhr->pData ? pnlhr->pData : "";
CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)pnlhr);
- } else {
+ }
+ else {
parent->debugLogA("!!! No response from server (time-out)");
resp.code = HTTP_CODE_FAKE_DISCONNECTED;
// Better to have something set explicitely as this value is compaired in all communication requests
}
+ // Delete the request object
+ delete request;
+
// Get Facebook's error message
if (resp.code == HTTP_CODE_OK) {
std::string::size_type pos = resp.data.find("\"error\":");
@@ -180,7 +161,7 @@ http::response facebook_client::flap(RequestType request_type, std::string *post
resp.code = HTTP_CODE_FAKE_ERROR;
parent->debugLogA("!!! Received Facebook error: %d -- %s", error_num, error.c_str());
- if (notify_errors(request_type) && !silent)
+ if (request->NotifyErrors && !silent)
client_notify(_A2T(error.c_str()));
}
}
@@ -223,359 +204,6 @@ bool facebook_client::handle_error(const std::string &method, int action)
//////////////////////////////////////////////////////////////////////////////
-std::string facebook_client::choose_server(RequestType request_type)
-{
- switch (request_type)
- {
- case REQUEST_LOGIN:
- return FACEBOOK_SERVER_LOGIN;
-
- case REQUEST_MESSAGES_RECEIVE:
- case REQUEST_ACTIVE_PING:
- {
- std::string server = FACEBOOK_SERVER_CHAT;
- utils::text::replace_first(&server, "%s", this->chat_conn_num_.empty() ? "0" : this->chat_conn_num_);
- utils::text::replace_first(&server, "%s", this->chat_channel_host_);
- return server;
- }
-
- case REQUEST_HOME:
- case REQUEST_DTSG:
- return FACEBOOK_SERVER_MOBILE;
-
- case REQUEST_LOAD_FRIENDSHIPS:
- case REQUEST_SEARCH:
- case REQUEST_USER_INFO_MOBILE:
- case REQUEST_PROFILE_PICTURE:
- return this->mbasicWorks ? FACEBOOK_SERVER_MBASIC : FACEBOOK_SERVER_MOBILE;
-
- // case REQUEST_LOGOUT:
- // case REQUEST_USER_INFO:
- // case REQUEST_USER_INFO_ALL:
- // case REQUEST_FEEDS:
- // case REQUEST_PAGES:
- // case REQUEST_NOTIFICATIONS:
- // case REQUEST_RECONNECT:
- // case REQUEST_POST_STATUS:
- // case REQUEST_IDENTITY_SWITCH:
- // case REQUEST_CAPTCHA_REFRESH:
- // case REQUEST_LINK_SCRAPER:
- // case REQUEST_MESSAGES_SEND:
- // case REQUEST_THREAD_INFO:
- // case REQUEST_THREAD_SYNC:
- // case REQUEST_VISIBILITY:
- // case REQUEST_POKE:
- // case REQUEST_MARK_READ:
- // case REQUEST_NOTIFICATIONS_READ:
- // case REQUEST_TYPING_SEND:
- // case REQUEST_SETUP_MACHINE:
- // case REQUEST_DELETE_FRIEND:
- // case REQUEST_ADD_FRIEND:
- // case REQUEST_CANCEL_FRIENDSHIP:
- // case REQUEST_FRIENDSHIP:
- // case REQUEST_UNREAD_THREADS:
- // case REQUEST_ON_THIS_DAY:
- // case REQUEST_LOGIN_SMS:
- default:
- return FACEBOOK_SERVER_REGULAR;
- }
-}
-
-std::string facebook_client::choose_action(RequestType request_type, std::string *get_data)
-{
- // NOTE: Parameter "client" used in some requests's POST data could be "jewel" (top bar?), "mercury" (chat window, source=source:chat:web) or "web_messenger" (whole chat messages page, source=source:titan:web)
-
- switch (request_type)
- {
- case REQUEST_LOGIN:
- {
- std::string action = "/login.php?login_attempt=1";
- if (get_data != NULL) {
- action += *get_data;
- }
- return action;
- }
-
- case REQUEST_SETUP_MACHINE:
- return "/checkpoint/?next";
-
- case REQUEST_LOGOUT:
- return "/logout.php?";
-
- case REQUEST_HOME:
- return "/profile.php?v=info";
-
- case REQUEST_DTSG:
- return "/editprofile.php?edit=current_city&type=basic";
-
- case REQUEST_USER_INFO: // ok, 17.8.2016
- return "/chat/user_info/?dpr=1";
-
- case REQUEST_USER_INFO_ALL: // ok, 17.8.2016
- return "/chat/user_info_all/?dpr=1&viewer=" + self_.user_id;
-
- case REQUEST_USER_INFO_MOBILE:
- {
- std::string action = "/%sv=info";
- if (get_data != NULL) {
- utils::text::replace_all(&action, "%s", *get_data);
- }
- return action;
- }
-
- case REQUEST_LOAD_FRIENDSHIPS:
- {
- return "/friends/center/requests/?";
- }
-
- case REQUEST_SEARCH:
- {
- std::string action = "/search/?search=people&query=";
- if (get_data != NULL) {
- action += *get_data;
- }
- return action;
- }
-
- case REQUEST_UNREAD_THREADS: // ok, 17.8.2016
- {
- return "/ajax/mercury/unread_threads.php?dpr=1";
- }
-
- case REQUEST_DELETE_FRIEND:
- {
- std::string action = "/ajax/profile/removefriendconfirm.php?__a=1";
- if (get_data != NULL) {
- action += *get_data;
- }
- return action;
- }
-
- case REQUEST_ADD_FRIEND:
- {
- return "/ajax/add_friend/action.php?__a=1";
- }
-
- case REQUEST_CANCEL_FRIENDSHIP:
- {
- return "/ajax/friends/requests/cancel.php?__a=1";
- }
-
- case REQUEST_FRIENDSHIP:
- {
- return "/requests/friends/ajax/?__a=1";
- }
-
- case REQUEST_FEEDS:
- {
- std::string action = "/ajax/home/generic.php?" + get_newsfeed_type();
- action += "&__user=" + self_.user_id + "&__a=1";
-
- /*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 REQUEST_PAGES:
- {
- return "/bookmarks/pages?";
- }
-
- case REQUEST_NOTIFICATIONS: // ok, 17.8.2016
- {
- return "/ajax/notifications/client/get.php?dpr=1";
- }
-
- case REQUEST_RECONNECT: // ok, 17.8.2016
- {
- std::string action = "/ajax/presence/reconnect.php?__a=1&reason=%s&fb_dtsg=%s&__user=%s";
-
- if (this->chat_reconnect_reason_.empty())
- this->chat_reconnect_reason_ = "6";
-
- utils::text::replace_first(&action, "%s", this->chat_reconnect_reason_);
- utils::text::replace_first(&action, "%s", this->dtsg_);
- utils::text::replace_first(&action, "%s", this->self_.user_id);
-
- action += "&__dyn=" + __dyn();
- action += "&__req=" + __req();
- action += "&__rev=" + __rev();
- action += "&__pc=PHASED:DEFAULT&__be=-1&__a=1";
-
- return action;
- }
-
- case REQUEST_POST_STATUS:
- return "/ajax/updatestatus.php?__a=1";
-
- case REQUEST_IDENTITY_SWITCH:
- return "/identity_switch.php?__a=1";
-
- case REQUEST_CAPTCHA_REFRESH:
- {
- std::string action = "/captcha/refresh_ajax.php?__a=1";
- if (get_data != NULL) {
- action += "&" + (*get_data);
- }
- return action;
- }
-
- case REQUEST_LINK_SCRAPER:
- {
- std::string action = "/ajax/composerx/attachment/link/scraper/?__a=1&composerurihash=2&scrape_url=";
- if (get_data != NULL) {
- action += utils::url::encode(*get_data);
- }
- return action;
- }
-
- case REQUEST_MESSAGES_SEND:
- return "/messaging/send/?dpr=1";
-
- case REQUEST_THREAD_INFO: // ok, 17.8.2016
- return "/ajax/mercury/thread_info.php?dpr=1";
-
- case REQUEST_THREAD_SYNC: // TODO: This doesn't work anymore
- return "/ajax/mercury/thread_sync.php?__a=1";
-
- case REQUEST_MESSAGES_RECEIVE:
- case REQUEST_ACTIVE_PING:
- {
- bool isPing = (request_type == REQUEST_ACTIVE_PING);
-
- std::string action = (isPing ? "/active_ping" : "/pull");
- action += "?channel=" + (this->chat_channel_.empty() ? "p_" + self_.user_id : this->chat_channel_);
- if (!isPing)
- action += "&seq=" + (this->chat_sequence_num_.empty() ? "0" : this->chat_sequence_num_);
- action += "&partition=" + (this->chat_channel_partition_.empty() ? "0" : this->chat_channel_partition_);
- action += "&clientid=" + this->chat_clientid_;
- action += "&cb=" + utils::text::rand_string(4, "0123456789abcdefghijklmnopqrstuvwxyz", &this->random_);
-
- /*
- original cb = return (1048576 * Math.random() | 0).toString(36);
- char buffer[10];
- itoa(((int)(1048576 * (((double)rand()) / (RAND_MAX + 1))) | 0), buffer, 36);
- action += "&cb=" + buffer;
- */
-
- int idleSeconds = parent->IdleSeconds();
- if (idleSeconds > 0 && !parent->isInvisible())
- action += "&idle=" + utils::conversion::to_string(&idleSeconds, UTILS_CONV_UNSIGNED_NUMBER);
-
- if (!isPing) {
- action += "&qp=y"; // TODO: what's this item?
- action += "&pws=fresh"; // TODO: what's this item?
- action += "&isq=487632"; // TODO: what's this item?
- action += "&msgs_recv=" + utils::conversion::to_string(&this->chat_msgs_recv_, UTILS_CONV_UNSIGNED_NUMBER);
- // TODO: sometimes there is &tur=1711 and &qpmade=<some actual timestamp> and &isq=487632
- // action += "&request_batch=1"; // it somehow batches up more responses to one - then response has special "t=batched" type and "batches" array with the data
- // action += "&msgr_region=LLA"; // it was here only for first pull, same as request_batch
- }
-
- action += "&cap=8"; // TODO: what's this item? Sometimes it's 0, sometimes 8
- action += "&uid=" + self_.user_id;
- action += "&viewer_uid=" + self_.user_id;
-
- if (!this->chat_sticky_num_.empty() && !this->chat_sticky_pool_.empty()) {
- action += "&sticky_token=" + this->chat_sticky_num_;
- action += "&sticky_pool=" + this->chat_sticky_pool_;
- }
-
- if (!isPing && !this->chat_traceid_.empty())
- action += "&traceid=" + this->chat_traceid_;
-
- if (parent->isInvisible())
- action += "&state=offline";
- else if (isPing || idleSeconds < 60)
- action += "&state=active";
-
- return action;
- }
-
- case REQUEST_VISIBILITY:
- return "/ajax/chat/privacy/visibility.php?dpr=1"; // ok, 17.8.2016
-
- case REQUEST_POKE:
- return "/pokes/dialog/?__a=1";
-
- case REQUEST_MARK_READ:
- return "/ajax/mercury/change_read_status.php?__a=1";
-
- case REQUEST_NOTIFICATIONS_READ:
- {
- std::string action = "/ajax/notifications/mark_read.php?__a=1";
- if (get_data != NULL) {
- action += "&" + (*get_data);
- }
- return action;
- }
-
- case REQUEST_TYPING_SEND:
- return "/ajax/messaging/typ.php?dpr=1"; // ok, 17.8.2016
-
- case REQUEST_ON_THIS_DAY:
- {
- std::string action = "/onthisday/story/query/?__a=1";
- if (get_data != NULL) {
- action += "&" + (*get_data);
- }
- return action;
- }
-
- case REQUEST_LOGIN_SMS:
- {
- return "/ajax/login/approvals/send_sms?dpr=1";
- }
-
- case REQUEST_PROFILE_PICTURE:
- {
- return "/profile/picture/view/?profile_id=" + self_.user_id;
- }
-
- default:
- return "/?_fb_noscript=1";
- }
-}
-
-bool facebook_client::notify_errors(RequestType request_type)
-{
- switch (request_type)
- {
- case REQUEST_MESSAGES_SEND:
- return false;
-
- default:
- return true;
- }
-}
-
-NETLIBHTTPHEADER *facebook_client::get_request_headers(int request_type, int *headers_count)
-{
- if (request_type == REQUEST_POST)
- *headers_count = 5;
- else
- *headers_count = 4;
-
- NETLIBHTTPHEADER *headers = (NETLIBHTTPHEADER*)mir_calloc(sizeof(NETLIBHTTPHEADER)*(*headers_count));
-
- if (request_type == REQUEST_POST) {
- headers[4].szName = "Content-Type";
- headers[4].szValue = "application/x-www-form-urlencoded; charset=utf-8";
- }
-
- headers[3].szName = "Cookie";
- headers[3].szValue = load_cookies();
- headers[2].szName = "User-Agent";
- headers[2].szValue = (char *)g_strUserAgent.c_str();
- headers[1].szName = "Accept";
- headers[1].szValue = "*/*";
- headers[0].szName = "Accept-Language";
- headers[0].szValue = "en,en-US;q=0.9";
-
- return headers;
-}
-
std::string facebook_client::get_newsfeed_type()
{
BYTE feed_type = parent->getByte(FACEBOOK_KEY_FEED_TYPE, 0);
@@ -803,12 +431,8 @@ bool facebook_client::login(const char *username, const char *password)
username_ = username;
password_ = password;
- // Prepare login data
- std::string data = "persistent=1";
- data += "&email=" + utils::url::encode(username);
- data += "&pass=" + utils::url::encode(password);
-
- std::string get_data = "";
+ std::string postData;
+ std::string getData;
if (cookies.empty()) {
// Set device ID
@@ -817,7 +441,8 @@ bool facebook_client::login(const char *username, const char *password)
cookies["datr"] = device;
// Get initial cookies
- http::response resp = flap(REQUEST_LOGIN);
+ LoginRequest *request = new LoginRequest();
+ http::response resp = sendRequest(request);
// Also parse cookies set by JavaScript (more variant exists in time, so check all known now)
parseJsCookies("[\"DeferredCookie\",\"addToQueue\",[],[\"", resp.data, cookies);
@@ -827,14 +452,13 @@ bool facebook_client::login(const char *username, const char *password)
std::string form = utils::text::source_get_value(&resp.data, 2, "<form", "</form>");
utils::text::replace_all(&form, "\\\"", "\"");
- data += "&" + utils::text::source_get_form_data(&form, true);
- get_data += "&" + utils::text::source_get_value(&form, 2, "login.php?login_attempt=1&amp;", "\"");
+ postData = utils::text::source_get_form_data(&form, true);
+ getData = utils::text::source_get_value(&form, 2, "login.php?login_attempt=1&amp;", "\"");
}
- data += "&lgndim=eyJ3IjoxOTIwLCJoIjoxMDgwLCJhdyI6MTgzNCwiYWgiOjEwODAsImMiOjMyfQ=="; // means base64 encoded: {"w":1920,"h":1080,"aw":1834,"ah":1080,"c":32}
-
// Send validation
- http::response resp = flap(REQUEST_LOGIN, &data, &get_data);
+ HttpRequest *request = new LoginRequest(username, password, getData.c_str(), postData.c_str());
+ http::response resp = sendRequest(request);
// Save Device ID
if (!cookies["datr"].empty())
@@ -853,7 +477,8 @@ bool facebook_client::login(const char *username, const char *password)
// Check whether login checks are required
if (location.find("/checkpoint/") != std::string::npos) {
- resp = flap(REQUEST_SETUP_MACHINE, NULL, NULL);
+ request = new SetupMachineRequest();
+ resp = sendRequest(request);
if (resp.data.find("login_approvals_no_phones") != std::string::npos) {
// Code approval - but no phones in account
@@ -862,29 +487,26 @@ bool facebook_client::login(const char *username, const char *password)
}
if (resp.data.find("name=\"submit[Continue]\"") != std::string::npos) {
- std::string inner_data;
-
int attempt = 0;
// Check if we need to put approval code (aka "two-factor auth")
while (resp.data.find("id=\"approvals_code\"") != std::string::npos) {
parent->debugLogA(" Login info: Approval code required.");
- std::string fb_dtsg = utils::url::encode(utils::text::source_get_value(&resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\""));
+ const char *fb_dtsg = utils::url::encode(utils::text::source_get_value(&resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\"")).c_str();
+ const char *nh = utils::text::source_get_value(&resp.data, 3, "name=\"nh\"", "value=\"", "\"").c_str();
- CFacebookGuardDialog guardDialog(parent, fb_dtsg.c_str());
+ CFacebookGuardDialog guardDialog(parent, fb_dtsg);
if (guardDialog.DoModal() != DIALOG_RESULT_OK) {
parent->SetStatus(ID_STATUS_OFFLINE);
return false;
}
// We need verification code from user (he can get it via Facebook application on phone or by requesting code via SMS)
- std::string givenCode = guardDialog.GetCode();
+ const char *givenCode = guardDialog.GetCode();
- inner_data = "submit[Continue]=Continue";
- inner_data += "&nh=" + utils::text::source_get_value(&resp.data, 3, "name=\"nh\"", "value=\"", "\"");
- inner_data += "&fb_dtsg=" + fb_dtsg;
- inner_data += "&approvals_code=" + givenCode;
- resp = flap(REQUEST_SETUP_MACHINE, &inner_data);
+ request = new SetupMachineRequest(fb_dtsg, nh, "Continue");
+ request->Body << CHAR_VALUE("approvals_code", givenCode);
+ resp = sendRequest(request);
if (resp.data.find("id=\"approvals_code\"") != std::string::npos) {
// We get no error message if we put wrong code. Facebook just shows same form again.
@@ -898,7 +520,7 @@ bool facebook_client::login(const char *username, const char *password)
}
}
else {
- // After successfull verification is showed different page - classic form to save device (as handled at the bottom)
+ // After successful verification is showed different page - classic form to save device (as handled at the bottom)
break;
}
}
@@ -907,10 +529,11 @@ bool facebook_client::login(const char *username, const char *password)
// 1) Continue (it might have been sent with approval code above already)
if (resp.data.find("name=\"submit[Continue]\"") != std::string::npos) {
- inner_data = "submit[Continue]=Continue";
- inner_data += "&nh=" + utils::text::source_get_value(&resp.data, 3, "name=\"nh\"", "value=\"", "\"");
- inner_data += "&fb_dtsg=" + utils::url::encode(utils::text::source_get_value(&resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\""));
- resp = flap(REQUEST_SETUP_MACHINE, &inner_data);
+ const char *fb_dtsg = utils::url::encode(utils::text::source_get_value(&resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\"")).c_str();
+ const char *nh = utils::text::source_get_value(&resp.data, 3, "name=\"nh\"", "value=\"", "\"").c_str();
+
+ request = new SetupMachineRequest(fb_dtsg, nh, "Continue");
+ resp = sendRequest(request);
}
// In this step might be needed identity confirmation
@@ -933,36 +556,35 @@ bool facebook_client::login(const char *username, const char *password)
tszMessage.AppendFormat(L"\n\n%s", ptrW(mir_utf8decodeW(activity.c_str())));
}
- if (MessageBox(0, tszMessage, tszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON1) == IDYES) {
- // Recognized activity, will continue with login
- inner_data = "submit[This was me]=This was me";
- } else {
- // Don't recognize - this will force to change account password
- inner_data = "submit[This wasn't me]=This wasn't me";
-
- // We won't continue with this and rather cancel connecting right away, because we don't want to handle password changing via Miranda
+ if (MessageBox(0, tszMessage, tszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON1) != IDYES) {
+ // We will cancel connecting right away, because we don't want to handle password changing via Miranda
client_notify(TranslateT("Login error: You need to confirm last unknown login or revoke it from web browser."));
return handle_error("login", FORCE_QUIT);
}
- inner_data += "&nh=" + utils::text::source_get_value(&resp.data, 3, "name=\"nh\"", "value=\"", "\"");
- inner_data += "&fb_dtsg=" + utils::url::encode(utils::text::source_get_value(&resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\""));
- resp = flap(REQUEST_SETUP_MACHINE, &inner_data);
+
+ const char *fb_dtsg = utils::url::encode(utils::text::source_get_value(&resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\"")).c_str();
+ const char *nh = utils::text::source_get_value(&resp.data, 3, "name=\"nh\"", "value=\"", "\"").c_str();
+
+ request = new SetupMachineRequest(fb_dtsg, nh, "This was me"); // Recognize device (or "This wasn't me" - this will force to change account password)
+ resp = sendRequest(request);
// 3) Save last device
- inner_data = "submit[Continue]=Continue";
- inner_data += "&nh=" + utils::text::source_get_value(&resp.data, 3, "name=\"nh\"", "value=\"", "\"");
- inner_data += "&fb_dtsg=" + utils::url::encode(utils::text::source_get_value(&resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\""));
- inner_data += "&name_action_selected=save_device"; // Save device - or "dont_save"
- resp = flap(REQUEST_SETUP_MACHINE, &inner_data);
+ fb_dtsg = utils::url::encode(utils::text::source_get_value(&resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\"")).c_str();
+ nh = utils::text::source_get_value(&resp.data, 3, "name=\"nh\"", "value=\"", "\"").c_str();
+
+ request = new SetupMachineRequest(fb_dtsg, nh, "Continue");
+ request->Body << "&name_action_selected=save_device"; // Save device - or "dont_save"
+ resp = sendRequest(request);
}
// Save this actual device
if (resp.data.find("name=\"submit[Continue]\"") != std::string::npos) {
- inner_data = "submit[Continue]=Continue";
- inner_data += "&nh=" + utils::text::source_get_value(&resp.data, 3, "name=\"nh\"", "value=\"", "\"");
- inner_data += "&fb_dtsg=" + utils::url::encode(utils::text::source_get_value(&resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\""));
- inner_data += "&name_action_selected=save_device"; // Save device - or "dont_save"
- resp = flap(REQUEST_SETUP_MACHINE, &inner_data);
+ const char *fb_dtsg = utils::url::encode(utils::text::source_get_value(&resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\"")).c_str();
+ const char *nh = utils::text::source_get_value(&resp.data, 3, "name=\"nh\"", "value=\"", "\"").c_str();
+
+ request = new SetupMachineRequest(fb_dtsg, nh, "Continue");
+ request->Body << "&name_action_selected=save_device"; // Save device - or "dont_save"
+ resp = sendRequest(request);
}
}
else if (resp.data.find("name=\"submit[Get Started]\"") != std::string::npos) {
@@ -1056,10 +678,8 @@ bool facebook_client::logout()
{
handle_entry("logout");
- std::string data = "fb_dtsg=" + this->dtsg_;
- data += "&ref=mb&h=" + this->logout_hash_;
-
- http::response resp = flap(REQUEST_LOGOUT, &data);
+ LogoutRequest *request = new LogoutRequest(this->dtsg_.c_str(), this->logout_hash_.c_str());
+ http::response resp = sendRequest(request);
this->username_.clear();
this->password_.clear();
@@ -1081,7 +701,7 @@ bool facebook_client::home()
handle_entry("home");
// get fb_dtsg
- http::response resp = flap(REQUEST_DTSG);
+ http::response resp = sendRequest(new DtsgRequest());
this->dtsg_ = utils::url::encode(utils::text::source_get_value(&resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\""));
{
@@ -1101,7 +721,7 @@ bool facebook_client::home()
parent->debugLogA(" Got self dtsg");
}
- resp = flap(REQUEST_HOME);
+ resp = sendRequest(new HomeRequest());
switch (resp.code)
{
@@ -1163,7 +783,8 @@ bool facebook_client::home()
// Final attempt to get avatar as on some pages is only link to photo page and not link to image itself
if (this->self_.image_url.empty()) {
- http::response resp2 = flap(REQUEST_PROFILE_PICTURE);
+ HttpRequest *request = new ProfilePictureRequest(this->mbasicWorks, self_.user_id.c_str());
+ http::response resp2 = sendRequest(request);
// Get avatar (from mbasic version of photo page)
this->self_.image_url = utils::text::html_entities_decode(utils::text::source_get_value(&resp2.data, 3, "id=\"root", "<img src=\"", "\""));
@@ -1209,16 +830,8 @@ bool facebook_client::chat_state(bool online)
{
handle_entry("chat_state");
- std::string data = (online ? "visibility=1" : "visibility=0");
- data += "&window_id=0";
- data += "&fb_dtsg=" + dtsg_;
- data += "&__user=" + self_.user_id;
- data += "&__dyn=" + __dyn();
- data += "&__req=" + __req();
- data += "&ttstamp=" + ttstamp_;
- data += "&__rev=" + __rev();
- data += "&__a=1&__pc=PHASED:DEFAULT&__be=-1";
- http::response resp = flap(REQUEST_VISIBILITY, &data); // NOTE: Request revised 17.8.2016
+ HttpRequest *request = new SetVisibilityRequest(this, online);
+ http::response resp = sendRequest(request);
if (!resp.error_title.empty())
return handle_error("chat_state");
@@ -1231,7 +844,7 @@ bool facebook_client::reconnect()
handle_entry("reconnect");
// Request reconnect
- http::response resp = flap(REQUEST_RECONNECT);
+ http::response resp = sendRequest(new ReconnectRequest(this));
switch (resp.code)
{
@@ -1276,8 +889,9 @@ bool facebook_client::channel()
{
handle_entry("channel");
- // Get update
- http::response resp = flap(REQUEST_MESSAGES_RECEIVE);
+ // Get updates
+ ChannelRequest *request = new ChannelRequest(this, ChannelRequest::PULL);
+ http::response resp = sendRequest(request);
if (resp.data.empty()) {
// Something went wrong
@@ -1385,7 +999,8 @@ bool facebook_client::activity_ping()
handle_entry("activity_ping");
- http::response resp = flap(REQUEST_ACTIVE_PING);
+ ChannelRequest *request = new ChannelRequest(this, ChannelRequest::PING);
+ http::response resp = sendRequest(request);
// Remember this last ping time
parent->m_pingTS = ::time(NULL);
@@ -1402,16 +1017,7 @@ int facebook_client::send_message(int seqid, MCONTACT hContact, const std::strin
{
handle_entry("send_message");
- http::response resp;
- std::string data;
-
- if (!captcha.empty()) {
- data += "&captcha_persist_data=" + captcha_persist_data;
- data += "&recaptcha_challenge_field=";
- data += "&captcha_response=" + captcha;
- }
-
- boolean isChatRoom = parent->isChatRoom(hContact);
+ bool isChatRoom = parent->isChatRoom(hContact);
ptrA userId( parent->getStringA(hContact, FACEBOOK_KEY_ID));
ptrA threadId( parent->getStringA(hContact, FACEBOOK_KEY_TID));
@@ -1426,59 +1032,15 @@ int facebook_client::send_message(int seqid, MCONTACT hContact, const std::strin
return SEND_MESSAGE_ERROR;
}
- data += "&client=mercury"; // or "web_messenger" (whole messages page)
- data += "&action_type=ma-type:user-generated-message";
-
- // Experimental sticker sending support
- if (message_text.substr(0, 10) == "[[sticker:" && message_text.substr(message_text.length() - 2) == "]]") {
- data += "&body=";
- data += "&sticker_id=" + utils::url::encode(message_text.substr(10, message_text.length() - 10 - 2));
- data += "&has_attachment=true";
- // TODO: For sending GIF images instead of "sticker_id=" there is "image_ids[0]=", otherwise it's same
- }
- else {
- data += "&body=" + utils::url::encode(message_text);
- data += "&has_attachment=false";
- }
-
- data += "&ephemeral_ttl_mode=0";
- // data += "&force_sms=true" // TODO: This is present always when sending via "web_messenger"
-
// Probably we can generate any random messageID, it just have to be numeric and don't start with "0". We will receive it in response as "client_message_id".
std::string messageId = utils::text::rand_string(10, "123456789", &this->random_);
- data += "&message_id=" + messageId;
- data += "&offline_threading_id=" + messageId; // Same as message ID
-
- if (isChatRoom) {
- // NOTE: Remove "id." prefix as here we need to give threadFbId and not threadId
- std::string thread_fbid = threadId;
- if (thread_fbid.substr(0, 3) == "id.")
- thread_fbid = thread_fbid.substr(3);
-
- data += "&thread_fbid=" + thread_fbid;
- } else {
- data += "&other_user_fbid=" + std::string(userId);
- data += "&specific_to_list[0]=fbid:" + std::string(userId);
- data += "&specific_to_list[1]=fbid:" + this->self_.user_id;
- }
- data += "&signature_id="; // TODO: How to generate signature ID? It is present only when sending via "mercury"
- data += "&source=source:chat:web"; // or "source:titan:web" for web_messenger
- data += "&timestamp=" + utils::time::mili_timestamp();
- data += "&ui_push_phase=V3";
- data += "&__user=" + this->self_.user_id;
- data += "&__a=1";
- data += "&__dyn=" + __dyn();
- data += "&__req=" + __req();
- data += "&__be=-1";
- data += "&__pc=PHASED:DEFAULT";
- data += "&fb_dtsg=" + this->dtsg_;
- data += "&ttstamp=" + ttstamp_;
- data += "&__rev=" + __rev();
+ http::response resp;
{
- ScopedLock s(send_message_lock_);
- resp = flap(REQUEST_MESSAGES_SEND, &data); // NOTE: Request revised 17.8.2016
+ HttpRequest *request = new SendMessageRequest(this, userId, threadId, messageId.c_str(), message_text.c_str(), isChatRoom, captcha.c_str(), captcha_persist_data.c_str());
+ ScopedLock s(send_message_lock_);
+ resp = sendRequest(request);
*error_text = resp.error_text;
@@ -1532,12 +1094,8 @@ int facebook_client::send_message(int seqid, MCONTACT hContact, const std::strin
parent->debugLogA(" Got imageUrl (first): %s", imageUrl.c_str());
parent->debugLogA(" Got captchaPersistData (first): %s", captchaPersistData.c_str());
- std::string capStr = "new_captcha_type=TFBCaptcha&skipped_captcha_data=" + captchaPersistData;
- capStr += "&__dyn=" + __dyn();
- capStr += "&__req=" + __req();
- capStr += "&__rev=" + __rev();
- capStr += "&__user=" + this->self_.user_id;
- http::response capResp = flap(REQUEST_CAPTCHA_REFRESH, NULL, &capStr);
+ HttpRequest *request = new RefreshCaptchaRequest(this, captchaPersistData.c_str());
+ http::response capResp = sendRequest(request);
if (capResp.code == HTTP_CODE_OK) {
imageUrl = utils::text::html_entities_decode(utils::text::slashu_to_utf8(utils::text::source_get_value(&capResp.data, 3, "img class=\\\"img\\\"", "src=\\\"", "\\\"")));
@@ -1587,63 +1145,38 @@ bool facebook_client::post_status(status_data *status)
handle_entry("post_status");
if (status->isPage) {
- std::string data = "fb_dtsg=" + this->dtsg_;
- data += "&user_id=" + status->user_id;
- data += "&url=" + std::string(FACEBOOK_URL_HOMEPAGE);
- flap(REQUEST_IDENTITY_SWITCH, &data);
+ // Switch to page identity by which name we will share this post
+ HttpRequest *request = new SwitchIdentityRequest(this->dtsg_.c_str(), status->user_id.c_str());
+ sendRequest(request);
}
- std::string data;
+ std::string linkData;
if (!status->url.empty()) {
- data = "fb_dtsg=" + this->dtsg_;
- data += "&targetid=" + (status->user_id.empty() ? this->self_.user_id : status->user_id);
- data += "&xhpc_targetid=" + (status->user_id.empty() ? this->self_.user_id : status->user_id);
- data += "&istimeline=1&composercontext=composer&onecolumn=1&nctr[_mod]=pagelet_timeline_recent&__a=1&ttstamp=" + ttstamp_;
- data += "&__user=" + (status->isPage && !status->user_id.empty() ? status->user_id : this->self_.user_id);
- data += "&loaded_components[0]=maininput&loaded_components[1]=backdateicon&loaded_components[2]=withtaggericon&loaded_components[3]=cameraicon&loaded_components[4]=placetaggericon&loaded_components[5]=mainprivacywidget&loaded_components[6]=withtaggericon&loaded_components[7]=backdateicon&loaded_components[8]=placetaggericon&loaded_components[9]=cameraicon&loaded_components[10]=mainprivacywidget&loaded_components[11]=maininput&loaded_components[12]=explicitplaceinput&loaded_components[13]=hiddenplaceinput&loaded_components[14]=placenameinput&loaded_components[15]=hiddensessionid&loaded_components[16]=withtagger&loaded_components[17]=backdatepicker&loaded_components[18]=placetagger&loaded_components[19]=citysharericon";
- http::response resp = flap(REQUEST_LINK_SCRAPER, &data, &status->url);
- std::string temp = utils::text::html_entities_decode(utils::text::slashu_to_utf8(resp.data));
+ HttpRequest *request = new LinkScraperRequest(this, status);
+ http::response resp = sendRequest(request);
- data = "&xhpc_context=profile&xhpc_ismeta=1&xhpc_timeline=1&xhpc_composerid=u_jsonp_2_0&is_explicit_place=&composertags_place=&composer_session_id=&composertags_city=&disable_location_sharing=false&composer_predicted_city=&nctr[_mod]=pagelet_composer&__a=1&__dyn=&__req=1f&ttstamp=" + ttstamp_;
+ std::string temp = utils::text::html_entities_decode(utils::text::slashu_to_utf8(resp.data));
std::string form = utils::text::source_get_value(&temp, 2, "<form", "</form>");
utils::text::replace_all(&form, "\\\"", "\"");
- data += "&" + utils::text::source_get_form_data(&form) + "&";
- //data += "&no_picture=0";
+ linkData += utils::text::source_get_form_data(&form);
+ // FIXME: Rework to some "scraped_link" structure to simplify working with it?
}
- std::string text = utils::url::encode(status->text);
-
- data += "fb_dtsg=" + this->dtsg_;
- data += "&xhpc_targetid=" + (status->user_id.empty() ? this->self_.user_id : status->user_id);
- data += "&__user=" + (status->isPage && !status->user_id.empty() ? status->user_id : this->self_.user_id);
- data += "&xhpc_message=" + text;
- data += "&xhpc_message_text=" + text;
- if (!status->isPage)
- data += "&audience[0][value]=" + get_privacy_type();
- if (!status->place.empty()) {
- data += "&composertags_place_name=";
- data += utils::url::encode(status->place);
+ HttpRequest *request = new SharePostRequest(this, status, linkData.c_str());
+ http::response resp = sendRequest(request);
+
+ if (status->isPage) {
+ // Switch back to our identity
+ HttpRequest *request = new SwitchIdentityRequest(this->dtsg_.c_str(), this->self_.user_id.c_str());
+ sendRequest(request);
}
+
+ // cleanup status elements (delete users)
for (std::vector<facebook_user*>::size_type i = 0; i < status->users.size(); i++) {
- data += "&composertags_with[" + utils::conversion::to_string(&i, UTILS_CONV_UNSIGNED_NUMBER);
- data += "]=" + status->users[i]->user_id;
- data += "&text_composertags_with[" + utils::conversion::to_string(&i, UTILS_CONV_UNSIGNED_NUMBER);
- data += "]=" + status->users[i]->real_name;
delete status->users[i];
}
status->users.clear();
- data += "&xhpc_context=profile&xhpc_ismeta=1&xhpc_timeline=1&xhpc_composerid=u_0_2y&is_explicit_place=&composertags_place=&composertags_city=";
-
- http::response resp = flap(REQUEST_POST_STATUS, &data);
-
- if (status->isPage) {
- std::string query = "fb_dtsg=" + this->dtsg_;
- query += "&user_id=" + this->self_.user_id;
- query += "&url=" + std::string(FACEBOOK_URL_HOMEPAGE);
- flap(REQUEST_IDENTITY_SWITCH, &query);
- }
-
if (resp.isValid()) {
parent->NotifyEvent(parent->m_tszUserName, TranslateT("Status update was successful."), NULL, EVENT_OTHER);
return handle_success("post_status");
@@ -1697,18 +1230,7 @@ bool facebook_client::save_url(const std::string &url, const std::wstring &filen
bool facebook_client::sms_code(const char *fb_dtsg)
{
- std::string inner_data = "method_requested=sms_requested";
- inner_data += "&current_time=" + (utils::time::unix_timestamp() + ".000");
- inner_data += "&__a=1";
- inner_data += "&__user=0";
- inner_data += "&__dyn=" + __dyn();
- inner_data += "&__req=" + __req();
- inner_data += "&__be=0";
- inner_data += "&__pc=EXP1:DEFAULT";
- inner_data += "&fb_dtsg=" + std::string(fb_dtsg);
- inner_data += "&ttstamp=" + ttstamp_;
- inner_data += "&__rev=" + __rev();
- http::response resp = flap(REQUEST_LOGIN_SMS, &inner_data);
+ http::response resp = sendRequest(new LoginSmsRequest(this, fb_dtsg));
if (resp.data.find("\"is_valid\":true", 0) == std::string::npos) {
// Code wasn't send
diff --git a/protocols/FacebookRM/src/constants.h b/protocols/FacebookRM/src/constants.h
index 058d0defec..5bcc095479 100644
--- a/protocols/FacebookRM/src/constants.h
+++ b/protocols/FacebookRM/src/constants.h
@@ -113,51 +113,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Event types
#define FACEBOOK_EVENTTYPE_CALL 10010
-// Facebook request types // TODO: Provide MS_ and release in FB plugin API?
-enum RequestType {
- REQUEST_LOGIN, // connecting physically
- REQUEST_LOGOUT, // disconnecting physically
- REQUEST_SETUP_MACHINE, // setting machine name
- REQUEST_HOME, // getting own name, avatar, ...
- REQUEST_DTSG, // getting __fb_dtsg__
- REQUEST_RECONNECT, // getting __sequence_num__ and __channel_id__
- REQUEST_VISIBILITY, // setting chat visibility
- REQUEST_IDENTITY_SWITCH, // changing identity to post status for pages
- REQUEST_CAPTCHA_REFRESH, // refreshing captcha dialog (changing captcha type)
- REQUEST_LOGIN_SMS, // request to receive login code via SMS
- REQUEST_PROFILE_PICTURE, // request mobile page containing profile picture
-
- REQUEST_FEEDS, // getting feeds
- REQUEST_NOTIFICATIONS, // getting notifications
- REQUEST_LOAD_FRIENDSHIPS, // getting friendship requests
- REQUEST_PAGES, // getting pages list
- REQUEST_ON_THIS_DAY, // getting on this day posts
-
- REQUEST_POST_STATUS, // posting status to our or friends's wall
- REQUEST_LINK_SCRAPER, // getting data for some url link
- REQUEST_SEARCH, // searching
- REQUEST_POKE, // sending pokes
- REQUEST_NOTIFICATIONS_READ, // marking notifications read
-
- REQUEST_USER_INFO, // getting info about particular friend
- REQUEST_USER_INFO_ALL, // getting info about all friends
- REQUEST_USER_INFO_MOBILE, // getting info about particular user (from mobile website)
- REQUEST_ADD_FRIEND, // requesting friendships
- REQUEST_DELETE_FRIEND, // deleting friendships
- REQUEST_CANCEL_FRIENDSHIP, // canceling (our) friendship request
- REQUEST_FRIENDSHIP, // approving or ignoring friendship requests
-
- REQUEST_MESSAGES_SEND, // sending messages
- REQUEST_MESSAGES_RECEIVE, // receiving messages and other realtime actions
- REQUEST_ACTIVE_PING, // sending activity ping
- REQUEST_TYPING_SEND, // sending typing notification
-
- REQUEST_THREAD_INFO, // getting thread info
- REQUEST_THREAD_SYNC, // getting thread sync (changes since something)
- REQUEST_UNREAD_THREADS, // getting unread threads
- REQUEST_MARK_READ // marking messages read
-};
-
enum ContactType {
CONTACT_FRIEND = 1, // contact that IS on our server list
CONTACT_NONE = 2, // contact that ISN'T on our server list
diff --git a/protocols/FacebookRM/src/contacts.cpp b/protocols/FacebookRM/src/contacts.cpp
index 771198c361..3a51a2bb86 100644
--- a/protocols/FacebookRM/src/contacts.cpp
+++ b/protocols/FacebookRM/src/contacts.cpp
@@ -183,20 +183,11 @@ std::string FacebookProto::ThreadIDToContactID(const std::string &thread_id)
// We don't have any contact with this thread_id cached, we must ask server
if (isOffline())
return "";
-
- std::string data = "client=mercury";
- data += "&__user=" + facy.self_.user_id;
- data += "&__dyn=" + facy.__dyn();
- data += "&__req=" + facy.__req();
- data += "&fb_dtsg=" + facy.dtsg_;
- data += "&ttstamp=" + facy.ttstamp_;
- data += "&__rev=" + facy.__rev();
- data += "&__pc=PHASED:DEFAULT&__be=-1&__a=1";
-
- data += "&threads[thread_ids][0]=" + utils::url::encode(thread_id);
-
+
+ HttpRequest *request = new ThreadInfoRequest(&facy, true, thread_id.c_str());
+ http::response resp = facy.sendRequest(request);
+
std::string user_id;
- http::response resp = facy.flap(REQUEST_THREAD_INFO, &data); // NOTE: Request revised 17.8.2016
if (resp.code == HTTP_CODE_OK) {
try {
@@ -222,18 +213,14 @@ void FacebookProto::LoadContactInfo(facebook_user* fbu)
if (isOffline())
return;
- // TODO: support for more friends at once
- std::string data = "ids[0]=" + utils::url::encode(fbu->user_id);
+ LIST<char> userIds(1);
+ userIds.insert(mir_strdup(fbu->user_id.c_str()));
- data += "&__user=" + facy.self_.user_id;
- data += "&__dyn=" + facy.__dyn();
- data += "&__req=" + facy.__req();
- data += "&fb_dtsg=" + facy.dtsg_;
- data += "&ttstamp=" + facy.ttstamp_;
- data += "&__rev=" + facy.__rev();
- data += "&__pc=PHASED:DEFAULT&__be=-1&__a=1";
+ HttpRequest *request = new UserInfoRequest(&facy, userIds);
+ http::response resp = facy.sendRequest(request);
- http::response resp = facy.flap(REQUEST_USER_INFO, &data); // NOTE: Request revised 17.8.2016
+ FreeList(userIds);
+ userIds.destroy();
if (resp.code == HTTP_CODE_OK) {
try {
@@ -294,21 +281,16 @@ void FacebookProto::LoadParticipantsNames(facebook_chatroom *fbc)
if (!namelessIds.empty()) {
// we have some contacts without name, let's load them all from the server
- std::string data = "&__user=" + facy.self_.user_id;
- data += "&__dyn=" + facy.__dyn();
- data += "&__req=" + facy.__req();
- data += "&fb_dtsg=" + facy.dtsg_;
- data += "&ttstamp=" + facy.ttstamp_;
- data += "&__rev=" + facy.__rev();
- data += "&__pc=PHASED:DEFAULT&__be=-1&__a=1";
-
+ LIST<char> userIds(1);
for (std::string::size_type i = 0; i < namelessIds.size(); i++) {
- std::string pos = utils::conversion::to_string(&i, UTILS_CONV_UNSIGNED_NUMBER);
- std::string id = utils::url::encode(namelessIds.at(i));
- data += "&ids[" + pos + "]=" + id;
+ userIds.insert(mir_strdup(namelessIds.at(i).c_str()));
}
- http::response resp = facy.flap(REQUEST_USER_INFO, &data); // NOTE: Request revised 17.8.2016
+ HttpRequest *request = new UserInfoRequest(&facy, userIds);
+ http::response resp = facy.sendRequest(request);
+
+ FreeList(userIds);
+ userIds.destroy();
if (resp.code == HTTP_CODE_OK) {
try {
@@ -345,26 +327,9 @@ void FacebookProto::LoadChatInfo(facebook_chatroom *fbc)
if (isOffline())
return;
- std::string data = "client=mercury";
- data += "&__user=" + facy.self_.user_id;
- data += "&__dyn=" + facy.__dyn();
- data += "&__req=" + facy.__req();
- data += "&fb_dtsg=" + facy.dtsg_;
- data += "&ttstamp=" + facy.ttstamp_;
- data += "&__rev=" + facy.__rev();
- data += "&__pc=PHASED:DEFAULT&__be=-1&__a=1";
-
- std::string thread_id = utils::url::encode(fbc->thread_id);
-
- // request info about thread
- data += "&threads[thread_ids][0]=" + thread_id;
-
- // TODO: ABILITY TO DEFINE TIMESTAMP! (way to load history since specific moment? probably as replacement for removed sync_threads request?)
- /* messages[user_ids][<<userid>>][offset]=11
- messages[user_ids][<<userid>>][timestamp]=1446369866009 // most recent message has this timestamp (included)
- messages[user_ids][<<userid>>][limit]=20 */
-
- http::response resp = facy.flap(REQUEST_THREAD_INFO, &data); // NOTE: Request revised 17.8.2016
+ // request info about chat thread
+ HttpRequest *request = new ThreadInfoRequest(&facy, true, fbc->thread_id.c_str());
+ http::response resp = facy.sendRequest(request);
if (resp.code != HTTP_CODE_OK) {
facy.handle_error("LoadChatInfo");
@@ -505,16 +470,9 @@ void FacebookProto::DeleteContactFromServer(void *data)
if (isOffline())
return;
- std::string query = "norefresh=true&unref=button_dropdown&confirmed=1&__a=1";
- query += "&fb_dtsg=" + facy.dtsg_;
- query += "&uid=" + id;
- query += "&__user=" + facy.self_.user_id;
- query += "&ttstamp=" + facy.ttstamp_;
-
- std::string get_query = "norefresh=true&unref=button_dropdown&uid=" + id;
-
- // Get unread inbox threads
- http::response resp = facy.flap(REQUEST_DELETE_FRIEND, &query, &get_query);
+ // Delete contact from server
+ HttpRequest *request = new DeleteFriendRequest(&facy, id.c_str());
+ http::response resp = facy.sendRequest(request);
if (resp.data.find("\"payload\":null", 0) != std::string::npos)
{
@@ -555,13 +513,9 @@ void FacebookProto::AddContactToServer(void *data)
if (isOffline())
return;
- std::string query = "action=add_friend&how_found=profile_button&ref_param=ts&outgoing_id=&unwanted=&logging_location=&no_flyout_on_click=false&ego_log_data=&lsd=";
- query += "&fb_dtsg=" + facy.dtsg_;
- query += "&to_friend=" + id;
- query += "&__user=" + facy.self_.user_id;
-
- // Get unread inbox threads
- http::response resp = facy.flap(REQUEST_ADD_FRIEND, &query);
+ // Request friendship
+ HttpRequest *request = new AddFriendRequest(&facy, id.c_str());
+ http::response resp = facy.sendRequest(request);
if (resp.data.find("\"success\":true", 0) != std::string::npos) {
MCONTACT hContact = ContactIDToHContact(id);
@@ -595,13 +549,9 @@ void FacebookProto::ApproveContactToServer(void *data)
if (!id)
return;
- std::string query = "action=confirm";
- query += "&id=" + std::string(id);
- query += "&__user=" + facy.self_.user_id;
- query += "&fb_dtsg=" + facy.dtsg_;
-
- // Ignore friendship request
- http::response resp = facy.flap(REQUEST_FRIENDSHIP, &query);
+ // Confirm friendship request
+ HttpRequest *request = new AnswerFriendshipRequest(&facy, id, AnswerFriendshipRequest::CONFIRM);
+ http::response resp = facy.sendRequest(request);
if (resp.data.find("\"success\":true") != std::string::npos)
{
@@ -631,13 +581,9 @@ void FacebookProto::CancelFriendsRequest(void *data)
if (!id)
return;
- std::string query = "confirmed=1";
- query += "&fb_dtsg=" + facy.dtsg_;
- query += "&__user=" + facy.self_.user_id;
- query += "&friend=" + std::string(id);
-
// Cancel (our) friendship request
- http::response resp = facy.flap(REQUEST_CANCEL_FRIENDSHIP, &query);
+ HttpRequest *request = new CancelFriendshipRequest(&facy, id);
+ http::response resp = facy.sendRequest(request);
if (resp.data.find("\"payload\":null", 0) != std::string::npos)
{
@@ -667,13 +613,9 @@ void FacebookProto::IgnoreFriendshipRequest(void *data)
if (!id)
return;
- std::string query = "action=reject";
- query += "&id=" + std::string(id);
- query += "&__user=" + facy.self_.user_id;
- query += "&fb_dtsg=" + facy.dtsg_;
-
// Ignore friendship request
- http::response resp = facy.flap(REQUEST_FRIENDSHIP, &query);
+ HttpRequest *request = new AnswerFriendshipRequest(&facy, id, AnswerFriendshipRequest::REJECT);
+ http::response resp = facy.sendRequest(request);
if (resp.data.find("\"success\":true") != std::string::npos)
{
@@ -704,14 +646,9 @@ void FacebookProto::SendPokeWorker(void *p)
return;
}
- std::string data = "poke_target=" + *id;
- data += "&do_confirm=0";
- data += "&fb_dtsg=" + facy.dtsg_;
- data += "&__user=" + facy.self_.user_id;
- data += "&ttstamp=" + facy.ttstamp_;
-
// Send poke
- http::response resp = facy.flap(REQUEST_POKE, &data);
+ HttpRequest *request = new SendPokeRequest(&facy, id->c_str());
+ http::response resp = facy.sendRequest(request);
if (resp.data.find("\"payload\":null", 0) != std::string::npos) {
resp.data = utils::text::slashu_to_utf8(
diff --git a/protocols/FacebookRM/src/http_request.h b/protocols/FacebookRM/src/http_request.h
index ec5c424b57..86a23cb5c8 100644
--- a/protocols/FacebookRM/src/http_request.h
+++ b/protocols/FacebookRM/src/http_request.h
@@ -233,6 +233,8 @@ public:
HttpRequestUrl Url;
HttpRequestHeaders Headers;
HttpRequestBody Body;
+
+ bool NotifyErrors;
HttpRequest(int type, LPCSTR url)
: Url(*this, url), Headers(*this)
@@ -241,6 +243,9 @@ public:
flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_DUMPASTEXT;
requestType = type;
pData = NULL;
+ timeout = 20 * 1000;
+
+ NotifyErrors = true;
}
HttpRequest(int type, HttpRequestUrlFormat, LPCSTR urlFormat, ...)
@@ -251,6 +256,9 @@ public:
requestType = type;
va_end(formatArgs);
pData = NULL;
+ timeout = 20 * 1000;
+
+ NotifyErrors = true;
}
virtual ~HttpRequest()
diff --git a/protocols/FacebookRM/src/messages.cpp b/protocols/FacebookRM/src/messages.cpp
index 83fc2c410a..6a1ceb129a 100644
--- a/protocols/FacebookRM/src/messages.cpp
+++ b/protocols/FacebookRM/src/messages.cpp
@@ -89,17 +89,9 @@ void FacebookProto::SendChatMsgWorker(void *p)
tid = tid_;
}
else {
- std::string post_data = "client=mercury";
- post_data += "&__user=" + facy.self_.user_id;
- post_data += "&__dyn=" + facy.__dyn();
- post_data += "&__req=" + facy.__req();
- post_data += "&fb_dtsg=" + facy.dtsg_;
- post_data += "&ttstamp=" + facy.ttstamp_;
- post_data += "&__rev=" + facy.__rev();
- post_data += "&threads[thread_ids][0]=" + utils::url::encode(data->chat_id);
- post_data += "&__pc=PHASED:DEFAULT&__be=-1&__a=1";
-
- http::response resp = facy.flap(REQUEST_THREAD_INFO, &post_data); // NOTE: Request revised 17.8.2016
+ // request info about chat thread
+ HttpRequest *request = new ThreadInfoRequest(&facy, true, data->chat_id.c_str());
+ http::response resp = facy.sendRequest(request);
tid = utils::text::source_get_value(&resp.data, 2, "\"thread_id\":\"", "\"");
if (!tid.empty() && tid.compare("null"))
@@ -154,22 +146,8 @@ void FacebookProto::SendTypingWorker(void *p)
ptrA id(getStringA(typing->hContact, value));
if (id != NULL) {
bool isChat = isChatRoom(typing->hContact);
- std::string idEncoded = utils::url::encode(std::string(id));
-
- std::string data = (typing->status == PROTOTYPE_SELFTYPING_ON ? "typ=1" : "typ=0");
- data += "&to=" + (isChat ? "" : idEncoded);
- data += "&source=mercury-chat";
- data += "&thread=" + idEncoded;
- data += "&__user=" + facy.self_.user_id;
- data += "&__dyn=" + facy.__dyn();
- data += "&__req=" + facy.__req();
-
- data += "&fb_dtsg=" + facy.dtsg_;
- data += "&ttstamp=" + facy.ttstamp_;
- data += "&__rev=" + facy.__rev();
- data += "&__pc=PHASED:DEFAULT&__be=-1&__a=1";
-
- http::response resp = facy.flap(REQUEST_TYPING_SEND, &data); // NOTE: Request revised 17.8.2016
+ HttpRequest *request = new SendTypingRequest(&facy, id, isChat, typing->status == PROTOTYPE_SELFTYPING_ON);
+ http::response resp = facy.sendRequest(request);
}
delete typing;
@@ -190,10 +168,7 @@ void FacebookProto::ReadMessageWorker(void *p)
return;
}
- std::string data = "fb_dtsg=" + facy.dtsg_;
- data += "&__user=" + facy.self_.user_id;
- data += "&__a=1&__dyn=&__req=&ttstamp=" + facy.ttstamp_;
-
+ LIST<char> ids(1);
for (std::set<MCONTACT>::iterator it = hContacts->begin(); it != hContacts->end(); ++it) {
MCONTACT hContact = *it;
@@ -206,12 +181,17 @@ void FacebookProto::ReadMessageWorker(void *p)
if (id == NULL)
continue;
- data += "&ids[" + utils::url::encode(std::string(id)) + "]=true";
+ ids.insert(mir_strdup(id));
}
+
hContacts->clear();
delete hContacts;
- facy.flap(REQUEST_MARK_READ, &data);
+ HttpRequest *request = new MarkMessageReadRequest(&facy, ids);
+ facy.sendRequest(request);
+
+ FreeList(ids);
+ ids.destroy();
}
void FacebookProto::StickerAsSmiley(std::string sticker, const std::string &url, MCONTACT hContact)
diff --git a/protocols/FacebookRM/src/process.cpp b/protocols/FacebookRM/src/process.cpp
index 08a8a17750..6e678e6ca7 100644
--- a/protocols/FacebookRM/src/process.cpp
+++ b/protocols/FacebookRM/src/process.cpp
@@ -46,15 +46,8 @@ void FacebookProto::ProcessFriendList(void*)
facy.handle_entry("load_friends");
// Get friends list
- std::string data = "__user=" + facy.self_.user_id;
- data += "&__dyn=" + facy.__dyn();
- data += "&__req=" + facy.__req();
- data += "&fb_dtsg=" + facy.dtsg_;
- data += "&ttstamp=" + facy.ttstamp_;
- data += "&__rev=" + facy.__rev();
- data += "&__pc=PHASED:DEFAULT&__be=-1&__a=1";
-
- http::response resp = facy.flap(REQUEST_USER_INFO_ALL, &data); // NOTE: Request revised 17.8.2016
+ HttpRequest *request = new UserInfoAllRequest(&facy);
+ http::response resp = facy.sendRequest(request);
if (resp.code != HTTP_CODE_OK) {
facy.handle_error("load_friends");
@@ -189,15 +182,8 @@ void FacebookProto::ProcessUnreadMessages(void*)
facy.handle_entry("ProcessUnreadMessages");
- std::string data = "folders[0]=inbox&folders[1]=other"; // TODO: "other" is probably unused, and there is now "pending" instead
- data += "&client=mercury";
- data += "&__user=" + facy.self_.user_id;
- data += "&fb_dtsg=" + facy.dtsg_;
- data += "&__a=1&__dyn=&__req=&ttstamp=" + facy.ttstamp_;
- data += "&__rev=" + facy.__rev();
- data += "&__pc=PHASED:DEFAULT&__be=-1";
-
- http::response resp = facy.flap(REQUEST_UNREAD_THREADS, &data);
+ HttpRequest *request = new UnreadThreadsRequest(&facy);
+ http::response resp = facy.sendRequest(request);
if (resp.code != HTTP_CODE_OK) {
facy.handle_error("ProcessUnreadMessages");
@@ -241,33 +227,22 @@ void FacebookProto::ProcessUnreadMessage(void *pParam)
http::response resp;
+ // FIXME: Rework this whole request as offset doesn't work anyway, and allow to load all the unread messages for each thread (IMHO could be done in 2 single requests = 1) get number of messages for all threads 2) load the counts of messages for all threads)
+
// TODO: First load info about amount of unread messages, then load exactly this amount for each thread
while (!threads->empty()) {
- std::string data = "client=mercury";
- data += "&__user=" + facy.self_.user_id;
- data += "&__dyn=" + facy.__dyn();
- data += "&__req=" + facy.__req();
- data += "&fb_dtsg=" + facy.dtsg_;
- data += "&ttstamp=" + facy.ttstamp_;
- data += "&__rev=" + facy.__rev();
- data += "&__pc=PHASED:DEFAULT&__be=-1&__a=1";
-
+
+ LIST<char> ids(1);
for (std::vector<std::string>::size_type i = 0; i < threads->size(); i++) {
- std::string thread_id = utils::url::encode(threads->at(i));
-
- // request messages from thread
- data += "&messages[thread_ids][" + thread_id;
- data += "][offset]=" + utils::conversion::to_string(&offset, UTILS_CONV_SIGNED_NUMBER);
- data += "&messages[thread_ids][" + thread_id;
- data += "][limit]=" + utils::conversion::to_string(&limit, UTILS_CONV_SIGNED_NUMBER);
-
- // request info about thread
- data += "&threads[thread_ids][" + utils::conversion::to_string(&i, UTILS_CONV_UNSIGNED_NUMBER);
- data += "]=" + thread_id;
+ ids.insert(mir_strdup(threads->at(i).c_str()));
}
- resp = facy.flap(REQUEST_THREAD_INFO, &data); // NOTE: Request revised 17.8.2016
+ HttpRequest *request = new ThreadInfoRequest(&facy, ids, offset, limit);
+ http::response resp = facy.sendRequest(request);
+
+ FreeList(ids);
+ ids.destroy();
if (resp.code == HTTP_CODE_OK) {
try {
@@ -345,15 +320,6 @@ void FacebookProto::LoadLastMessages(void *pParam)
if (!isOnline())
return;
- std::string data = "client=mercury";
- data += "&__user=" + facy.self_.user_id;
- data += "&__dyn=" + facy.__dyn();
- data += "&__req=" + facy.__req();
- data += "&fb_dtsg=" + facy.dtsg_;
- data += "&ttstamp=" + facy.ttstamp_;
- data += "&__rev=" + facy.__rev();
- data += "&__pc=PHASED:DEFAULT&__be=-1&__a=1";
-
bool isChat = isChatRoom(hContact);
if (isChat && (!m_enableChat || IsSpecialChatRoom(hContact))) // disabled chats or special chatroom (e.g. nofitications)
@@ -365,21 +331,10 @@ void FacebookProto::LoadLastMessages(void *pParam)
return;
}
- std::string id = utils::url::encode(std::string(item_id));
- std::string type = isChat ? "thread_ids" : "user_ids";
- int count = getByte(FACEBOOK_KEY_MESSAGES_ON_OPEN_COUNT, DEFAULT_MESSAGES_ON_OPEN_COUNT);
- count = min(count, FACEBOOK_MESSAGES_ON_OPEN_LIMIT);
-
- // request messages from thread
- data += "&messages[" + type + "][" + id;
- data += "][offset]=0";
- data += "&messages[" + type + "][" + id;
- data += "][limit]=" + utils::conversion::to_string(&count, UTILS_CONV_UNSIGNED_NUMBER);
-
- // request info about thread
- data += "&threads[" + type + "][0]=" + id;
+ int count = min(FACEBOOK_MESSAGES_ON_OPEN_LIMIT, getByte(FACEBOOK_KEY_MESSAGES_ON_OPEN_COUNT, DEFAULT_MESSAGES_ON_OPEN_COUNT));
- http::response resp = facy.flap(REQUEST_THREAD_INFO, &data); // NOTE: Request revised 17.8.2016
+ HttpRequest *request = new ThreadInfoRequest(&facy, isChat, item_id, count);
+ http::response resp = facy.sendRequest(request);
if (resp.code != HTTP_CODE_OK || resp.data.empty()) {
facy.handle_error("LoadLastMessages");
@@ -455,15 +410,6 @@ void FacebookProto::LoadHistory(void *pParam)
facy.handle_entry("LoadHistory");
- std::string data = "client=mercury";
- data += "&__user=" + facy.self_.user_id;
- data += "&__dyn=" + facy.__dyn();
- data += "&__req=" + facy.__req();
- data += "&fb_dtsg=" + facy.dtsg_;
- data += "&ttstamp=" + facy.ttstamp_;
- data += "&__rev=" + facy.__rev();
- data += "&__pc=PHASED:DEFAULT&__be=-1&__a=1";
-
bool isChat = isChatRoom(hContact);
if (isChat) // TODO: Support chats?
return;
@@ -476,15 +422,10 @@ void FacebookProto::LoadHistory(void *pParam)
return;
}
- std::string id = utils::url::encode(std::string(item_id));
- std::string type = isChat ? "thread_ids" : "user_ids";
-
// first get info about this thread and how many messages is there
+ HttpRequest *request = new ThreadInfoRequest(&facy, isChat, item_id);
+ http::response resp = facy.sendRequest(request);
- // request info about thread
- data += "&threads[" + type + "][0]=" + id;
-
- http::response resp = facy.flap(REQUEST_THREAD_INFO, &data); // NOTE: Request revised 17.8.2016
if (resp.code != HTTP_CODE_OK || resp.data.empty()) {
facy.handle_error("LoadHistory");
return;
@@ -525,26 +466,10 @@ void FacebookProto::LoadHistory(void *pParam)
if (!isOnline())
break;
- // Request batch of messages from thread
- std::string szQuery = "client=mercury";
- szQuery += "&__user=" + facy.self_.user_id;
- szQuery += "&__dyn=" + facy.__dyn();
- szQuery += "&__req=" + facy.__req();
- szQuery += "&fb_dtsg=" + facy.dtsg_;
- szQuery += "&ttstamp=" + facy.ttstamp_;
- szQuery += "&__rev=" + facy.__rev();
- szQuery += "&__pc=PHASED:DEFAULT&__be=-1&__a=1";
-
- // Grrr, offset doesn't work at all, we need to use timestamps to get back in history...
- // And we don't know, what's timestamp of first message, so we need to get from latest to oldest
- szQuery += "&messages[" + type + "][" + id;
- szQuery += "][offset]=" + utils::conversion::to_string(&batch, UTILS_CONV_UNSIGNED_NUMBER);
- szQuery += "&messages[" + type + "][" + id;
- szQuery += "][timestamp]=" + firstTimestamp;
- szQuery += "&messages[" + type + "][" + id;
- szQuery += "][limit]=" + utils::conversion::to_string(&messagesPerBatch, UTILS_CONV_UNSIGNED_NUMBER);
-
- resp = facy.flap(REQUEST_THREAD_INFO, &szQuery); // NOTE: Request revised 17.8.2016
+ // Load batch of messages
+ HttpRequest *request = new ThreadInfoRequest(&facy, isChat, item_id, batch, firstTimestamp.c_str(), messagesPerBatch);
+ resp = facy.sendRequest(request);
+
if (resp.code != HTTP_CODE_OK || resp.data.empty()) {
facy.handle_error("LoadHistory");
break;
@@ -811,13 +736,8 @@ void FacebookProto::ProcessMemories(void*)
facy.handle_entry(__FUNCTION__);
- time_t timestamp = ::time(NULL);
-
- std::string get_data = "&start_index=0&num_stories=20&last_section_header=0";
- get_data += "&timestamp=" + utils::conversion::to_string((void*)&timestamp, UTILS_CONV_TIME_T);
- get_data += "&__dyn=&__req=&__rev=&__user=" + facy.self_.user_id;
-
- http::response resp = facy.flap(REQUEST_ON_THIS_DAY, NULL, &get_data);
+ HttpRequest *request = new MemoriesRequest(&facy);
+ http::response resp = facy.sendRequest(request);
if (resp.code != HTTP_CODE_OK) {
facy.handle_error(__FUNCTION__);
@@ -1146,21 +1066,9 @@ void FacebookProto::ProcessNotifications(void*)
facy.handle_entry("notifications");
- int count = FACEBOOK_NOTIFICATIONS_LOAD_COUNT;
-
- std::string data = "__user=" + facy.self_.user_id;
- data += "&fb_dtsg=" + facy.dtsg_;
- data += "&cursor="; // when loading more
- data += "&length=" + utils::conversion::to_string(&count, UTILS_CONV_UNSIGNED_NUMBER); // number of items to load
- data += "&businessID="; // probably for pages?
- data += "&ttstamp=" + facy.ttstamp_;
- data += "&__dyn=" + facy.__dyn();
- data += "&__req=" + facy.__req();
- data += "&__rev=" + facy.__rev();
- data += "&__pc=PHASED:DEFAULT&__be=-1&__a=1";
-
// Get notifications
- http::response resp = facy.flap(REQUEST_NOTIFICATIONS, &data); // NOTE: Request revised 17.8.2016
+ HttpRequest *request = new GetNotificationsRequest(&facy, FACEBOOK_NOTIFICATIONS_LOAD_COUNT);
+ http::response resp = facy.sendRequest(request);
if (resp.code != HTTP_CODE_OK) {
facy.handle_error("notifications");
@@ -1191,14 +1099,14 @@ void FacebookProto::ProcessFriendRequests(void*)
facy.handle_entry("friendRequests");
- // Get notifications
- http::response resp = facy.flap(REQUEST_LOAD_FRIENDSHIPS);
+ // Get load friendships
+ http::response resp = facy.sendRequest(new GetFriendshipsRequest(facy.mbasicWorks));
// Workaround not working "mbasic." website for some people
if (!resp.isValid()) {
- // Remember it didn't worked and try it again (internally it will try "m." this time)
+ // Remember it didn't worked and try it again (internally it will use "m." this time)
facy.mbasicWorks = false;
- resp = facy.flap(REQUEST_LOAD_FRIENDSHIPS);
+ resp = facy.sendRequest(new GetFriendshipsRequest(facy.mbasicWorks));
}
if (resp.code != HTTP_CODE_OK) {
@@ -1281,7 +1189,8 @@ void FacebookProto::ProcessFeeds(void*)
facy.handle_entry("feeds");
// Get feeds
- http::response resp = facy.flap(REQUEST_FEEDS);
+ HttpRequest *request = new NewsfeedRequest(&facy);
+ http::response resp = facy.sendRequest(request);
if (resp.code != HTTP_CODE_OK || resp.data.empty()) {
facy.handle_error("feeds");
@@ -1323,7 +1232,7 @@ void FacebookProto::ProcessPages(void*)
facy.handle_entry("load_pages");
// Get feeds
- http::response resp = facy.flap(REQUEST_PAGES);
+ http::response resp = facy.sendRequest(new GetPagesRequest());
if (resp.code != HTTP_CODE_OK) {
facy.handle_error("load_pages");
@@ -1373,11 +1282,8 @@ void FacebookProto::SearchAckThread(void *targ)
while (count < 50 && !isOffline())
{
- std::string get_data = search + "&s=" + utils::conversion::to_string(&count, UTILS_CONV_UNSIGNED_NUMBER);
- if (!ssid.empty())
- get_data += "&ssid=" + ssid;
-
- http::response resp = facy.flap(REQUEST_SEARCH, NULL, &get_data);
+ SearchRequest *request = new SearchRequest(facy.mbasicWorks, search.c_str(), count, ssid.c_str());
+ http::response resp = facy.sendRequest(request);
if (resp.code == HTTP_CODE_OK)
{
@@ -1451,11 +1357,14 @@ void FacebookProto::SearchIdAckThread(void *targ)
if (!isOffline())
{
- http::response resp = facy.flap(REQUEST_USER_INFO_MOBILE, NULL, &search);
+ HttpRequest *request = new ProfileRequest(facy.mbasicWorks, search.c_str());
+ http::response resp = facy.sendRequest(request);
if (resp.code == HTTP_CODE_FOUND && resp.headers.find("Location") != resp.headers.end()) {
search = utils::text::source_get_value(&resp.headers["Location"], 2, FACEBOOK_SERVER_MBASIC"/", "_rdr", true);
- resp = facy.flap(REQUEST_USER_INFO_MOBILE, NULL, &search);
+
+ HttpRequest *request = new ProfileRequest(facy.mbasicWorks, search.c_str());
+ http::response resp = facy.sendRequest(request);
}
if (resp.code == HTTP_CODE_OK)
diff --git a/protocols/FacebookRM/src/proto.cpp b/protocols/FacebookRM/src/proto.cpp
index 5cb8089e0c..02bd8e8d3d 100644
--- a/protocols/FacebookRM/src/proto.cpp
+++ b/protocols/FacebookRM/src/proto.cpp
@@ -975,12 +975,8 @@ void FacebookProto::ReadNotificationWorker(void *p)
return;
}
- std::string data = "seen=0&asyncSignal=&__dyn=&__rev=&__req=&alert_ids%5B0%5D=" + utils::url::encode(*id);
- data += "&fb_dtsg=" + facy.dtsg_;
- data += "&__user=" + facy.self_.user_id;
- data += "&ttstamp=" + facy.ttstamp_;
-
- facy.flap(REQUEST_NOTIFICATIONS_READ, NULL, &data); // NOTE: Request revised 11.2.2016 (we're not using the main website request, as it doesn't work, but still the old one with GET parameters)
+ HttpRequest *request = new MarkNotificationReadRequest(&facy, id->c_str());
+ facy.sendRequest(request);
delete id;
}
diff --git a/protocols/FacebookRM/src/requests/channel.h b/protocols/FacebookRM/src/requests/channel.h
new file mode 100644
index 0000000000..03f36241df
--- /dev/null
+++ b/protocols/FacebookRM/src/requests/channel.h
@@ -0,0 +1,101 @@
+/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2011-16 Robert Pösel
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _FACEBOOK_REQUEST_CHANNEL_H_
+#define _FACEBOOK_REQUEST_CHANNEL_H_
+
+// receiving updates, sending activity ping
+class ChannelRequest : public HttpRequest
+{
+public:
+ enum Type { PULL, PING };
+
+ ChannelRequest(facebook_client *fc, Type type) :
+ HttpRequest(REQUEST_POST, FORMAT,
+ type == PULL ? FACEBOOK_SERVER_CHAT "/pull" : FACEBOOK_SERVER_CHAT "/active_ping",
+ fc->chat_conn_num_.empty() ? "0" : fc->chat_conn_num_.c_str(),
+ fc->chat_channel_host_.c_str())
+ {
+ if (type == PULL) {
+ timeout = 65 * 1000;
+ }
+
+ bool isPing = (type == PING);
+
+ Url << CHAR_VALUE("channel", fc->chat_channel_.empty() ? ("p_" + fc->self_.user_id).c_str() : fc->chat_channel_.c_str());
+ if (!isPing)
+ Url << CHAR_VALUE("seq", fc->chat_sequence_num_.empty() ? "0" : fc->chat_sequence_num_.c_str());
+
+ Url
+ << CHAR_VALUE("partition", fc->chat_channel_partition_.empty() ? "0" : fc->chat_channel_partition_.c_str())
+ << CHAR_VALUE("clientid", fc->chat_clientid_.c_str())
+ << CHAR_VALUE("cb", utils::text::rand_string(4, "0123456789abcdefghijklmnopqrstuvwxyz", &fc->random_).c_str());
+
+ /*
+ original cb = return (1048576 * Math.random() | 0).toString(36);
+ char buffer[10];
+ itoa(((int)(1048576 * (((double)rand()) / (RAND_MAX + 1))) | 0), buffer, 36);
+ Url << CHAR_VALUE("cb", buffer);
+ */
+
+ int idleSeconds = fc->parent->IdleSeconds();
+ if (idleSeconds > 0 && !fc->parent->isInvisible())
+ Url << INT_VALUE("idle", idleSeconds);
+
+ if (!isPing) {
+ Url << "qp=y"; // TODO: what's this item?
+ Url << "pws=fresh"; // TODO: what's this item?
+ Url << "isq=487632"; // TODO: what's this item?
+ Url << INT_VALUE("msgs_recv", fc->chat_msgs_recv_);
+ // TODO: sometimes there is &tur=1711 and &qpmade=<some actual timestamp> and &isq=487632
+ // Url << "request_batch=1"; // it somehow batches up more responses to one - then response has special "t=batched" type and "batches" array with the data
+ // Url << "msgr_region=LLA"; // it was here only for first pull, same as request_batch
+ }
+
+ Url << "cap=8" // TODO: what's this item? Sometimes it's 0, sometimes 8
+ << CHAR_VALUE("uid", fc->self_.user_id.c_str())
+ << CHAR_VALUE("viewer_uid", fc->self_.user_id.c_str());
+
+ if (!fc->chat_sticky_num_.empty() && !fc->chat_sticky_pool_.empty()) {
+ Url << CHAR_VALUE("sticky_token", fc->chat_sticky_num_.c_str());
+ Url << CHAR_VALUE("sticky_pool", fc->chat_sticky_pool_.c_str());
+ }
+
+ if (!isPing && !fc->chat_traceid_.empty())
+ Url << CHAR_VALUE("traceid", fc->chat_traceid_.c_str());
+
+ if (fc->parent->isInvisible())
+ Url << "state=offline";
+ else if (isPing || idleSeconds < 60)
+ Url << "state=active";
+
+ /*
+ Body
+ << "persistent=1"
+ << CHAR_VALUE("email", ptrA(mir_urlEncode(username)))
+ << CHAR_VALUE("pass", ptrA(mir_urlEncode(password)))
+ << CHAR_VALUE("lgndim", "eyJ3IjoxOTIwLCJoIjoxMDgwLCJhdyI6MTgzNCwiYWgiOjEwODAsImMiOjMyfQ==") // means base64 encoded: {"w":1920,"h":1080,"aw":1834,"ah":1080,"c":32}
+ << bodyData; // additional data parsed from form*/
+ }
+};
+
+#endif //_FACEBOOK_REQUEST_CHANNEL_H_
diff --git a/protocols/FacebookRM/src/requests/contacts.h b/protocols/FacebookRM/src/requests/contacts.h
new file mode 100644
index 0000000000..823ebaf2b4
--- /dev/null
+++ b/protocols/FacebookRM/src/requests/contacts.h
@@ -0,0 +1,191 @@
+/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2011-16 Robert Pösel
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _FACEBOOK_REQUEST_CONTACTS_H_
+#define _FACEBOOK_REQUEST_CONTACTS_H_
+
+// getting frienship requests (using mobile website)
+class GetFriendshipsRequest : public HttpRequest
+{
+public:
+ GetFriendshipsRequest(bool mobileBasicWorks) :
+ HttpRequest(REQUEST_GET, FORMAT, "%s/friends/center/requests/", mobileBasicWorks ? FACEBOOK_SERVER_MBASIC : FACEBOOK_SERVER_MOBILE)
+ {
+ flags |= NLHRF_REDIRECT;
+ }
+};
+
+
+// getting info about particular friend
+// revised 17.8.2016
+class UserInfoRequest : public HttpRequest
+{
+public:
+ UserInfoRequest(facebook_client *fc, const LIST<char> &userIds) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/chat/user_info/")
+ {
+ Url
+ << "dpr=1";
+
+ for (int i = 0; i < userIds.getCount(); i++) {
+ CMStringA id(::FORMAT, "ids[%i]", i);
+ Body << CHAR_VALUE(id, ptrA(mir_urlEncode(userIds[i])));
+ }
+
+ Body
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << CHAR_VALUE("ttstamp", fc->ttstamp_.c_str())
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str())
+ << CHAR_VALUE("__dyn", fc->__dyn())
+ << CHAR_VALUE("__req", fc->__req())
+ << CHAR_VALUE("__rev", fc->__rev())
+ << "__a=1"
+ << "__pc=PHASED:DEFAULT"
+ << "__be=-1";
+ }
+};
+
+// getting info about all friends
+// revised 17.8.2016
+class UserInfoAllRequest : public HttpRequest
+{
+public:
+ UserInfoAllRequest(facebook_client *fc) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/chat/user_info_all/")
+ {
+ Url
+ << "dpr=1"
+ << CHAR_VALUE("viewer", fc->self_.user_id.c_str());
+
+ Body
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << CHAR_VALUE("ttstamp", fc->ttstamp_.c_str())
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str())
+ << CHAR_VALUE("__dyn", fc->__dyn())
+ << CHAR_VALUE("__req", fc->__req())
+ << CHAR_VALUE("__rev", fc->__rev())
+ << "__a=1"
+ << "__pc=PHASED:DEFAULT"
+ << "__be=-1";
+ }
+};
+
+// requesting friendships
+class AddFriendRequest : public HttpRequest
+{
+public:
+ AddFriendRequest(facebook_client *fc, const char *userId) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/add_friend/action.php")
+ {
+ Url
+ << "__a=1";
+
+ Body
+ << CHAR_VALUE("to_friend", userId)
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str())
+ << "action=add_friend"
+ << "how_found=profile_button"
+ << "ref_param=ts"
+ << "outgoing_id="
+ << "unwanted="
+ << "logging_location="
+ << "no_flyout_on_click=false"
+ << "ego_log_data="
+ << "lsd=";
+ }
+};
+
+// deleting friendships
+class DeleteFriendRequest : public HttpRequest
+{
+public:
+ DeleteFriendRequest(facebook_client *fc, const char *userId) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/profile/removefriendconfirm.php")
+ {
+ Url
+ << "__a=1"
+ << "norefresh=true"
+ << "unref=button_dropdown"
+ << CHAR_VALUE("uid", userId);
+
+ Body
+ << CHAR_VALUE("uid", userId)
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str())
+ << CHAR_VALUE("ttstamp", fc->ttstamp_.c_str())
+ << "norefresh=true"
+ << "unref=button_dropdown"
+ << "confirmed=1"
+ << "__a=1";
+ }
+};
+
+// canceling (our) friendship request
+class CancelFriendshipRequest : public HttpRequest
+{
+public:
+ CancelFriendshipRequest(facebook_client *fc, const char *userId) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/friends/requests/cancel.php")
+ {
+ Url
+ << "__a=1";
+
+ Body
+ << "confirmed=1"
+ << CHAR_VALUE("friend", userId)
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str());
+ }
+};
+
+// approving or ignoring friendship requests
+class AnswerFriendshipRequest : public HttpRequest
+{
+public:
+ enum Answer { CONFIRM, REJECT };
+
+ AnswerFriendshipRequest(facebook_client *fc, const char *userId, Answer answer) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/requests/friends/ajax/")
+ {
+ Url
+ << "__a=1";
+
+ const char *action = "";
+ switch (answer) {
+ case CONFIRM:
+ action = "confirm";
+ break;
+ case REJECT:
+ action = "reject";
+ break;
+ }
+
+ Body
+ << CHAR_VALUE("action", action)
+ << CHAR_VALUE("id", userId)
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str());
+ }
+};
+
+#endif //_FACEBOOK_REQUEST_CONTACTS_H_
diff --git a/protocols/FacebookRM/src/requests/feeds.h b/protocols/FacebookRM/src/requests/feeds.h
new file mode 100644
index 0000000000..70e590d959
--- /dev/null
+++ b/protocols/FacebookRM/src/requests/feeds.h
@@ -0,0 +1,60 @@
+/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2011-16 Robert Pösel
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _FACEBOOK_REQUEST_FEEDS_H_
+#define _FACEBOOK_REQUEST_FEEDS_H_
+
+// getting newsfeed posts
+class NewsfeedRequest : public HttpRequest
+{
+public:
+ NewsfeedRequest(facebook_client *fc) :
+ HttpRequest(REQUEST_GET, FACEBOOK_SERVER_REGULAR "/ajax/home/generic.php")
+ {
+ Url
+ << fc->get_newsfeed_type().c_str()
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str())
+ << "__a=1";
+ }
+};
+
+// getting memories ("on this day") posts
+class MemoriesRequest : public HttpRequest
+{
+public:
+ MemoriesRequest(facebook_client *fc) :
+ HttpRequest(REQUEST_GET, FACEBOOK_SERVER_REGULAR "/onthisday/story/query/")
+ {
+ Url
+ << "__a=1"
+ << "start_index=0"
+ << "num_stories=20"
+ << "last_section_header=0"
+ << LONG_VALUE("timestamp", ::time(NULL))
+ << CHAR_VALUE("__dyn", fc->__dyn())
+ << CHAR_VALUE("__req", fc->__req())
+ << CHAR_VALUE("__rev", fc->__rev())
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str());
+ }
+};
+
+#endif //_FACEBOOK_REQUEST_FEEDS_H_
diff --git a/protocols/FacebookRM/src/requests/history.h b/protocols/FacebookRM/src/requests/history.h
new file mode 100644
index 0000000000..426266c569
--- /dev/null
+++ b/protocols/FacebookRM/src/requests/history.h
@@ -0,0 +1,167 @@
+/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2011-16 Robert Pösel
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _FACEBOOK_REQUEST_HISTORY_H_
+#define _FACEBOOK_REQUEST_HISTORY_H_
+
+// getting thread info and messages
+// revised 17.8.2016
+class ThreadInfoRequest : public HttpRequest
+{
+public:
+ // Request only messages history
+ ThreadInfoRequest(facebook_client *fc, bool isChat, const char *id, int offset, const char *timestamp, int limit) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/mercury/thread_info.php")
+ {
+ Url
+ << "dpr=1";
+
+ setCommonBody(fc);
+
+ const char *type = isChat ? "thread_ids" : "user_ids";
+ ptrA idEncoded(mir_urlEncode(id));
+
+ //if (loadMessages) {
+ // Grrr, offset doesn't work at all, we need to use timestamps to get back in history...
+ // And we don't know, what's timestamp of first message, so we need to get from latest to oldest
+ CMStringA begin(::FORMAT, "messages[%s][%s]", type, idEncoded);
+
+ Body
+ << CMStringA(::FORMAT, "%s[offset]=%i", begin, offset).c_str()
+ << CMStringA(::FORMAT, "%s[timestamp]=%s", begin, timestamp).c_str()
+ << CMStringA(::FORMAT, "%s[limit]=%i", begin, limit).c_str();
+ //}
+
+ /*if (loadThreadInfo) {
+ data += "&threads[" + type + "][0]=" + idEncoded;
+ }*/
+ }
+
+ // Request only thread info // TODO: Make it array of ids
+ ThreadInfoRequest(facebook_client *fc, bool isChat, const char *id) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/mercury/thread_info.php")
+ {
+ Url
+ << "dpr=1";
+
+ setCommonBody(fc);
+
+ const char *type = isChat ? "thread_ids" : "user_ids";
+ ptrA idEncoded(mir_urlEncode(id));
+
+ // Load only thread info
+ Body << CMStringA(::FORMAT, "threads[%s][0]=%s", type, idEncoded).c_str();
+ }
+
+ // Request both thread info and messages for single contact/chat
+ ThreadInfoRequest(facebook_client *fc, bool isChat, const char *id, int limit) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/mercury/thread_info.php")
+ {
+ Url
+ << "dpr=1";
+
+ setCommonBody(fc);
+
+ const char *type = isChat ? "thread_ids" : "user_ids";
+ ptrA idEncoded(mir_urlEncode(id));
+
+ // Load messages
+ CMStringA begin(::FORMAT, "messages[%s][%s]", type, idEncoded);
+
+ Body
+ << CMStringA(::FORMAT, "%s[offset]=%i", begin, 0).c_str()
+ << CMStringA(::FORMAT, "%s[timestamp]=%s", begin, "").c_str()
+ << CMStringA(::FORMAT, "%s[limit]=%i", begin, limit).c_str();
+
+ // Load thread info
+ Body << CMStringA(::FORMAT, "threads[%s][0]=%s", type, idEncoded).c_str();
+ }
+
+ // Request both thread info and messages for more threads
+ ThreadInfoRequest(facebook_client *fc, const LIST<char> &ids, int offset, int limit) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/mercury/thread_info.php")
+ {
+ Url
+ << "dpr=1";
+
+ setCommonBody(fc);
+
+ for (int i = 0; i < ids.getCount(); i++) {
+ ptrA idEncoded(mir_urlEncode(ids[i]));
+
+ // Load messages
+ CMStringA begin(::FORMAT, "messages[%s][%s]", "thread_ids", idEncoded);
+ Body
+ << CMStringA(::FORMAT, "%s[offset]=%i", begin, offset).c_str()
+ //<< CMStringA(::FORMAT, "%s[timestamp]=%s", begin, "").c_str()
+ << CMStringA(::FORMAT, "%s[limit]=%i", begin, limit).c_str();
+
+ // Load thread info
+ Body << CMStringA(::FORMAT, "threads[%s][%i]=%s", "thread_ids", i, idEncoded).c_str();
+ }
+ }
+
+private:
+ void setCommonBody(facebook_client *fc)
+ {
+ Body
+ << "client=mercury"
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str())
+ << CHAR_VALUE("__dyn", fc->__dyn())
+ << CHAR_VALUE("__req", fc->__req())
+ << CHAR_VALUE("__rev", fc->__rev())
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << CHAR_VALUE("ttstamp", fc->ttstamp_.c_str())
+ << "__a=1"
+ << "__pc=PHASED:DEFAULT"
+ << "__be=-1";
+ }
+};
+
+// getting unread threads
+// revised 17.8.2016
+class UnreadThreadsRequest : public HttpRequest
+{
+public:
+ UnreadThreadsRequest(facebook_client *fc) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/mercury/unread_threads.php")
+ {
+ Url
+ << "dpr=1";
+
+ Body
+ << "folders[0]=inbox"
+ << "folders[1]=other" // TODO: "other" is probably unused, and there is now "pending" instead
+ << "client=mercury"
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str())
+ << CHAR_VALUE("__dyn", fc->__dyn())
+ << CHAR_VALUE("__req", fc->__req())
+ << CHAR_VALUE("__rev", fc->__rev())
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << CHAR_VALUE("ttstamp", fc->ttstamp_.c_str())
+ << "__a=1"
+ << "__pc=PHASED:DEFAULT"
+ << "__be=-1";
+ }
+};
+
+#endif //_FACEBOOK_REQUEST_HISTORY_H_
diff --git a/protocols/FacebookRM/src/requests/login.h b/protocols/FacebookRM/src/requests/login.h
new file mode 100644
index 0000000000..85a2da36c6
--- /dev/null
+++ b/protocols/FacebookRM/src/requests/login.h
@@ -0,0 +1,116 @@
+/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2011-16 Robert Pösel
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _FACEBOOK_REQUEST_LOGIN_H_
+#define _FACEBOOK_REQUEST_LOGIN_H_
+
+// connecting physically
+class LoginRequest : public HttpRequest
+{
+public:
+ LoginRequest() :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_LOGIN "/login.php")
+ {
+ Url
+ << "login_attempt=1";
+ }
+
+ LoginRequest(const char *username, const char *password, const char *urlData, const char *bodyData) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_LOGIN "/login.php")
+ {
+ Url
+ << "login_attempt=1"
+ << urlData; // additional data parsed from form
+
+ Body
+ << "persistent=1"
+ << CHAR_VALUE("email", ptrA(mir_urlEncode(username)))
+ << CHAR_VALUE("pass", ptrA(mir_urlEncode(password)))
+ << CHAR_VALUE("lgndim", "eyJ3IjoxOTIwLCJoIjoxMDgwLCJhdyI6MTgzNCwiYWgiOjEwODAsImMiOjMyfQ==") // means base64 encoded: {"w":1920,"h":1080,"aw":1834,"ah":1080,"c":32}
+ << bodyData; // additional data parsed from form
+ }
+};
+
+// request to receive login code via SMS
+class LoginSmsRequest : public HttpRequest
+{
+public:
+ LoginSmsRequest(facebook_client *fc, const char *dtsg) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/login/approvals/send_sms")
+ {
+ Url
+ << "dpr=1";
+
+ Body
+ << "method_requested=sms_requested"
+ << "__a=1"
+ << "__user=0"
+ << "__be=0"
+ << "__pc=EXP1:DEFAULT"
+ << CHAR_VALUE("current_time", (utils::time::unix_timestamp() + ".000").c_str())
+ << CHAR_VALUE("__dyn", fc->__dyn())
+ << CHAR_VALUE("__req", fc->__req())
+ << CHAR_VALUE("fb_dtsg", dtsg)
+ << CHAR_VALUE("ttstamp", fc->ttstamp_.c_str())
+ << CHAR_VALUE("__rev", fc->__rev());
+ }
+};
+
+// setting machine name
+class SetupMachineRequest : public HttpRequest
+{
+public:
+ SetupMachineRequest() :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/checkpoint/")
+ {
+ Url
+ << "next";
+ }
+
+ SetupMachineRequest(const char *dtsg, const char *nh, const char *submit) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/checkpoint/")
+ {
+ Url
+ << "next";
+
+ Body
+ << CMStringA(::FORMAT, "submit[%s]=%s", submit, submit).c_str()
+ << CHAR_VALUE("nh", nh)
+ << CHAR_VALUE("fb_dtsg", dtsg);
+ }
+};
+
+// disconnecting physically
+class LogoutRequest : public HttpRequest
+{
+public:
+ LogoutRequest(const char *dtsg, const char *logoutHash) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/logout.php")
+ {
+ Body
+ << "ref="
+ << CHAR_VALUE("fb_dtsg", dtsg)
+ << CHAR_VALUE("h", logoutHash);
+ }
+};
+
+#endif //_FACEBOOK_REQUEST_LOGIN_H_
diff --git a/protocols/FacebookRM/src/requests/messages.h b/protocols/FacebookRM/src/requests/messages.h
new file mode 100644
index 0000000000..a9427e401a
--- /dev/null
+++ b/protocols/FacebookRM/src/requests/messages.h
@@ -0,0 +1,161 @@
+/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright � 2011-16 Robert P�sel
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _FACEBOOK_REQUEST_MESSAGES_H_
+#define _FACEBOOK_REQUEST_MESSAGES_H_
+
+// sending messages
+// revised 17.8.2016
+class SendMessageRequest : public HttpRequest
+{
+public:
+ SendMessageRequest(facebook_client *fc, const char *userId, const char *threadId, const char *messageId, const char *messageText, bool isChat, const char *captcha, const char *captchaPersistData) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/messaging/send/")
+ {
+ // Don't notify errors for this request, because we're getting them inline in messaging window
+ NotifyErrors = false;
+
+ Url
+ << "dpr=1";
+
+ if (mir_strlen(captcha) > 0) {
+ Body
+ << CHAR_VALUE("captcha_persist_data", captchaPersistData)
+ << "recaptcha_challenge_field="
+ << CHAR_VALUE("captcha_response", captcha);
+ }
+
+ Body
+ << "client=mercury" // or "web_messenger" (whole messages page)
+ << "action_type=ma-type:user-generated-message";
+
+ // Experimental sticker sending support
+ std::string message_text = messageText; // FIXME: Rewrite this without std::string...
+ if (message_text.substr(0, 10) == "[[sticker:" && message_text.substr(message_text.length() - 2) == "]]") {
+ Body
+ << "body="
+ << CHAR_VALUE("sticker_id", ptrA(mir_urlEncode(message_text.substr(10, message_text.length() - 10 - 2).c_str())))
+ << "has_attachment=true";
+ // TODO: For sending GIF images instead of "sticker_id=" there is "image_ids[0]=", otherwise it's same
+ }
+ else {
+ Body
+ << CHAR_VALUE("body", ptrA(mir_urlEncode(messageText)))
+ << "has_attachment=false";
+ }
+
+ Body
+ << "ephemeral_ttl_mode=0"
+ // << "force_sms=true" // TODO: This is present always when sending via "web_messenger"
+ << CHAR_VALUE("message_id", messageId)
+ << CHAR_VALUE("offline_threading_id", messageId); // Same as message ID
+
+ if (isChat) {
+ // NOTE: Remove "id." prefix as here we need to give threadFbId and not threadId
+ std::string threadFbid = threadId; // FIXME: Rewrite this without std::string...
+ if (threadFbid.substr(0, 3) == "id.")
+ threadFbid = threadFbid.substr(3);
+
+ Body << CHAR_VALUE("thread_fbid", threadFbid.c_str());
+ }
+ else {
+ Body
+ << CHAR_VALUE("other_user_fbid", userId)
+ << CHAR_VALUE("specific_to_list[0]", CMStringA(::FORMAT, "fbid:%s", userId))
+ << CHAR_VALUE("specific_to_list[1]", CMStringA(::FORMAT, "fbid:%s", fc->self_.user_id.c_str()));
+ }
+
+ Body
+ << "signature_id=" // TODO: How to generate signature ID? It is present only when sending via "mercury"
+ << "source=source:chat:web" // or "source:titan:web" for web_messenger
+ << CHAR_VALUE("timestamp", utils::time::mili_timestamp().c_str())
+ << "ui_push_phase=V3"
+
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str())
+ << CHAR_VALUE("__dyn", fc->__dyn())
+ << CHAR_VALUE("__req", fc->__req())
+ << CHAR_VALUE("__rev", fc->__rev())
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << CHAR_VALUE("ttstamp", fc->ttstamp_.c_str())
+ << "__a=1"
+ << "__pc=PHASED:DEFAULT"
+ << "__be=-1";
+ }
+};
+
+// sending typing notification
+// revised 17.8.2016
+class SendTypingRequest : public HttpRequest
+{
+public:
+ SendTypingRequest(facebook_client *fc, const char *userId, bool isChat, bool isTyping) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/messaging/typ.php")
+ {
+ Url
+ << "dpr=1";
+
+ ptrA idEncoded(mir_urlEncode(userId));
+
+ Body
+ << (isTyping ? "typ=1" : "typ=0")
+ << CHAR_VALUE("to", isChat ? "" : idEncoded)
+ << CHAR_VALUE("thread", idEncoded)
+ << "source=mercury-chat"
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str())
+ << CHAR_VALUE("__dyn", fc->__dyn())
+ << CHAR_VALUE("__req", fc->__req())
+ << CHAR_VALUE("__rev", fc->__rev())
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << CHAR_VALUE("ttstamp", fc->ttstamp_.c_str())
+ << "__a=1"
+ << "__pc=PHASED:DEFAULT"
+ << "__be=-1";
+ }
+};
+
+// marking messages read
+class MarkMessageReadRequest : public HttpRequest
+{
+public:
+ MarkMessageReadRequest(facebook_client *fc, const LIST<char> &ids) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/mercury/change_read_status.php")
+ {
+ Url
+ << "__a=1";
+
+ for (int i = 0; i < ids.getCount(); i++) {
+ CMStringA id(::FORMAT, "ids[%s]=true", ptrA(mir_urlEncode(ids[i])));
+ Body << id.c_str();
+ }
+
+ Body
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << CHAR_VALUE("ttstamp", fc->ttstamp_.c_str())
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str())
+ << CHAR_VALUE("__dyn", fc->__dyn())
+ << CHAR_VALUE("__req", fc->__req())
+ << CHAR_VALUE("__rev", fc->__rev())
+ << "__a=1";
+ }
+};
+
+#endif //_FACEBOOK_REQUEST_MESSAGES_H_
diff --git a/protocols/FacebookRM/src/requests/notifications.h b/protocols/FacebookRM/src/requests/notifications.h
new file mode 100644
index 0000000000..4937c5d5bf
--- /dev/null
+++ b/protocols/FacebookRM/src/requests/notifications.h
@@ -0,0 +1,75 @@
+/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2011-16 Robert Pösel
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _FACEBOOK_REQUEST_NOTIFICATIONS_H_
+#define _FACEBOOK_REQUEST_NOTIFICATIONS_H_
+
+// getting notifications
+// revised 17.8.2016
+class GetNotificationsRequest : public HttpRequest
+{
+public:
+ GetNotificationsRequest(facebook_client *fc, int count) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/notifications/client/get.php")
+ {
+ Url
+ << "dpr=1";
+
+ Body
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str())
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << "cursor=" // when loading more
+ << INT_VALUE("length", count) // number of items to load
+ << "businessID=" // probably for pages?
+ << CHAR_VALUE("ttstamp", fc->ttstamp_.c_str())
+ << CHAR_VALUE("__dyn", fc->__dyn())
+ << CHAR_VALUE("__req", fc->__req())
+ << CHAR_VALUE("__rev", fc->__rev())
+ << "__pc=PHASED:DEFAULT"
+ << "__be=-1"
+ << "__a=1";
+ }
+};
+
+// marking notifications read
+// request revised 11.2.2016 (we're not using the main website request, as it doesn't work, but still the old one with GET parameters)
+class MarkNotificationReadRequest : public HttpRequest
+{
+public:
+ MarkNotificationReadRequest(facebook_client *fc, const char *id) :
+ HttpRequest(REQUEST_GET, FACEBOOK_SERVER_REGULAR "/ajax/notifications/mark_read.php")
+ {
+ Url
+ << "__a=1"
+ << "seen=0"
+ << "asyncSignal="
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str())
+ << CHAR_VALUE("ttstamp", fc->ttstamp_.c_str())
+ << CHAR_VALUE("__dyn", fc->__dyn())
+ << CHAR_VALUE("__req", fc->__req())
+ << CHAR_VALUE("__rev", fc->__rev())
+ << CHAR_VALUE("alert_ids%5B0%5D", ptrA(mir_urlEncode(id)));
+ }
+};
+
+#endif //_FACEBOOK_REQUEST_NOTIFICATIONS_H_
diff --git a/protocols/FacebookRM/src/requests/profile.h b/protocols/FacebookRM/src/requests/profile.h
new file mode 100644
index 0000000000..2eecbac018
--- /dev/null
+++ b/protocols/FacebookRM/src/requests/profile.h
@@ -0,0 +1,83 @@
+/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2011-16 Robert Pösel
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _FACEBOOK_REQUEST_PROFILE_H_
+#define _FACEBOOK_REQUEST_PROFILE_H_
+
+// getting own name, avatar, ...
+class HomeRequest : public HttpRequest
+{
+public:
+ HomeRequest() :
+ HttpRequest(REQUEST_GET, FACEBOOK_SERVER_MOBILE "/profile.php")
+ {
+ flags |= NLHRF_REDIRECT;
+
+ Url
+ << "v=info";
+ }
+};
+
+// getting fb_dtsg
+class DtsgRequest : public HttpRequest
+{
+public:
+ DtsgRequest() :
+ HttpRequest(REQUEST_GET, FACEBOOK_SERVER_MOBILE "/editprofile.php")
+ {
+ flags |= NLHRF_REDIRECT;
+
+ Url
+ << "edit=current_city"
+ << "type=basic";
+ }
+};
+
+// request mobile page containing profile picture
+class ProfilePictureRequest : public HttpRequest
+{
+public:
+ ProfilePictureRequest(bool mobileBasicWorks, const char *userId) :
+ HttpRequest(REQUEST_GET, FORMAT, "%s/profile/picture/view/", mobileBasicWorks ? FACEBOOK_SERVER_MBASIC : FACEBOOK_SERVER_MOBILE)
+ {
+ flags |= NLHRF_REDIRECT;
+
+ Url
+ << CHAR_VALUE("profile_id", userId);
+ }
+};
+
+// request mobile page containing user profile
+class ProfileRequest : public HttpRequest
+{
+public:
+ ProfileRequest(bool mobileBasicWorks, const char *data) :
+ HttpRequest(REQUEST_GET, FORMAT, "%s/%s", mobileBasicWorks ? FACEBOOK_SERVER_MBASIC : FACEBOOK_SERVER_MOBILE, data)
+ {
+ flags |= NLHRF_REDIRECT;
+
+ Url
+ << "v=info";
+ }
+};
+
+#endif //_FACEBOOK_REQUEST_PROFILE_H_
diff --git a/protocols/FacebookRM/src/requests/search.h b/protocols/FacebookRM/src/requests/search.h
new file mode 100644
index 0000000000..0b4e777874
--- /dev/null
+++ b/protocols/FacebookRM/src/requests/search.h
@@ -0,0 +1,46 @@
+/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2011-16 Robert Pösel
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _FACEBOOK_REQUEST_SEARCH_H_
+#define _FACEBOOK_REQUEST_SEARCH_H_
+
+// searching
+class SearchRequest : public HttpRequest
+{
+public:
+ SearchRequest(bool mobileBasicWorks, const char *query, int s, const char *ssid) :
+ HttpRequest(REQUEST_GET, FORMAT, "%s/search/", mobileBasicWorks ? FACEBOOK_SERVER_MBASIC : FACEBOOK_SERVER_MOBILE)
+ {
+ flags |= NLHRF_REDIRECT;
+
+ Url
+ << "search=people"
+ << CHAR_VALUE("query", query)
+ << INT_VALUE("s", s);
+
+ if (mir_strlen(ssid) > 0) {
+ Url << CHAR_VALUE("ssid", ssid);
+ }
+ }
+};
+
+#endif //_FACEBOOK_REQUEST_SEARCH_H_
diff --git a/protocols/FacebookRM/src/requests/status.h b/protocols/FacebookRM/src/requests/status.h
new file mode 100644
index 0000000000..f832a00062
--- /dev/null
+++ b/protocols/FacebookRM/src/requests/status.h
@@ -0,0 +1,74 @@
+/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2011-16 Robert Pösel
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _FACEBOOK_REQUEST_STATUS_H_
+#define _FACEBOOK_REQUEST_STATUS_H_
+
+// getting info about channel and connecting to it
+// revised 17.8.2016
+class ReconnectRequest : public HttpRequest
+{
+public:
+ ReconnectRequest(facebook_client *fc) :
+ HttpRequest(REQUEST_GET, FACEBOOK_SERVER_REGULAR "/ajax/presence/reconnect.php")
+ {
+ Url
+ << "__a=1"
+ << "__pc=PHASED:DEFAULT"
+ << "__be=-1"
+ << CHAR_VALUE("reason", fc->chat_reconnect_reason_.empty() ? "6" : fc->chat_reconnect_reason_.c_str())
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str())
+ << CHAR_VALUE("__dyn", fc->__dyn())
+ << CHAR_VALUE("__req", fc->__req())
+ << CHAR_VALUE("__rev", fc->__rev());
+ }
+};
+
+// setting chat visibility
+// revised 17.8.2016
+class SetVisibilityRequest : public HttpRequest
+{
+public:
+ SetVisibilityRequest(facebook_client *fc, bool online) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/chat/privacy/visibility.php")
+ {
+ Url
+ << "dpr=1";
+
+ Body
+ << (online ? "visibility=1" : "visibility=0")
+ << "window_id=0"
+ << "__a=1"
+ << "__pc=PHASED:DEFAULT"
+ << "__be=-1"
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << CHAR_VALUE("ttstamp", fc->ttstamp_.c_str())
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str())
+ << CHAR_VALUE("__dyn", fc->__dyn())
+ << CHAR_VALUE("__req", fc->__req())
+ << CHAR_VALUE("__rev", fc->__rev());
+ ;
+ }
+};
+
+#endif //_FACEBOOK_REQUEST_STATUS_H_
diff --git a/protocols/FacebookRM/src/requests/utils.h b/protocols/FacebookRM/src/requests/utils.h
new file mode 100644
index 0000000000..a9f6d548cb
--- /dev/null
+++ b/protocols/FacebookRM/src/requests/utils.h
@@ -0,0 +1,195 @@
+/*
+
+Facebook plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2011-16 Robert Pösel
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _FACEBOOK_REQUEST_UTILS_H_
+#define _FACEBOOK_REQUEST_UTILS_H_
+
+// refreshing captcha dialog (changing captcha type)
+class RefreshCaptchaRequest : public HttpRequest
+{
+public:
+ RefreshCaptchaRequest(facebook_client *fc, const char *captchaPersistData) :
+ HttpRequest(REQUEST_GET, FACEBOOK_SERVER_REGULAR "/captcha/refresh_ajax.php")
+ {
+ Url
+ << "__a=1"
+ << "new_captcha_type=TFBCaptcha"
+ << CHAR_VALUE("skipped_captcha_data", captchaPersistData)
+ << CHAR_VALUE("__dyn", fc->__dyn())
+ << CHAR_VALUE("__req", fc->__req())
+ << CHAR_VALUE("__rev", fc->__rev())
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str());
+ }
+};
+
+// getting data for given url (for sending/posting reasons)
+class LinkScraperRequest : public HttpRequest
+{
+public:
+ LinkScraperRequest(facebook_client *fc, status_data *status) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/composerx/attachment/link/scraper/")
+ {
+ Url
+ << "__a=1"
+ << "composerurihash=2"
+ << CHAR_VALUE("scrape_url", ptrA(mir_urlEncode(status->url.c_str())));
+
+ Body
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << CHAR_VALUE("targetid", status->user_id.empty() ? fc->self_.user_id.c_str() : status->user_id.c_str())
+ << CHAR_VALUE("xhpc_targetid", status->user_id.empty() ? fc->self_.user_id.c_str() : status->user_id.c_str())
+ << "istimeline=1"
+ << "composercontext=composer"
+ << "onecolumn=1"
+ << "nctr[_mod]=pagelet_timeline_recent"
+ << "__a=1"
+ << CHAR_VALUE("ttstamp", fc->ttstamp_.c_str())
+ << CHAR_VALUE("__user", status->isPage && !status->user_id.empty() ? status->user_id.c_str() : fc->self_.user_id.c_str())
+ << "loaded_components[0]=maininput"
+ << "loaded_components[1]=backdateicon"
+ << "loaded_components[2]=withtaggericon"
+ << "loaded_components[3]=cameraicon"
+ << "loaded_components[4]=placetaggericon"
+ << "loaded_components[5]=mainprivacywidget"
+ << "loaded_components[6]=withtaggericon"
+ << "loaded_components[7]=backdateicon"
+ << "loaded_components[8]=placetaggericon"
+ << "loaded_components[9]=cameraicon"
+ << "loaded_components[10]=mainprivacywidget"
+ << "loaded_components[11]=maininput"
+ << "loaded_components[12]=explicitplaceinput"
+ << "loaded_components[13]=hiddenplaceinput"
+ << "loaded_components[14]=placenameinput"
+ << "loaded_components[15]=hiddensessionid"
+ << "loaded_components[16]=withtagger"
+ << "loaded_components[17]=backdatepicker"
+ << "loaded_components[18]=placetagger"
+ << "loaded_components[19]=citysharericon";
+ }
+};
+
+// getting owned/admined pages list
+class GetPagesRequest : public HttpRequest
+{
+public:
+ GetPagesRequest() :
+ HttpRequest(REQUEST_GET, FACEBOOK_SERVER_REGULAR "/bookmarks/pages")
+ { }
+};
+
+// changing identity to post status for pages
+class SwitchIdentityRequest : public HttpRequest
+{
+public:
+ SwitchIdentityRequest(const char *dtsg, const char *userId) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/identity_switch.php")
+ {
+ Url
+ << "__a=1";
+
+ Body
+ << CHAR_VALUE("fb_dtsg", dtsg)
+ << CHAR_VALUE("user_id", userId)
+ << CHAR_VALUE("url", FACEBOOK_URL_HOMEPAGE);
+ }
+};
+
+// posting status to our or friends's wall
+class SharePostRequest : public HttpRequest
+{
+public:
+ SharePostRequest(facebook_client *fc, status_data *status, const char *linkData) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/updatestatus.php")
+ {
+ Url
+ << "__a=1";
+
+ ptrA text(mir_urlEncode(status->text.c_str()));
+
+ Body
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << CHAR_VALUE("__dyn", fc->__dyn())
+ << CHAR_VALUE("__req", fc->__req())
+ << CHAR_VALUE("ttstamp", fc->ttstamp_.c_str())
+ << CHAR_VALUE("__user", status->isPage && !status->user_id.empty() ? status->user_id.c_str() : fc->self_.user_id.c_str())
+ << CHAR_VALUE("xhpc_targetid", status->user_id.empty() ? fc->self_.user_id.c_str() : status->user_id.c_str())
+ << CHAR_VALUE("xhpc_message", text)
+ << CHAR_VALUE("xhpc_message_text", text)
+ << "xhpc_context=profile"
+ << "xhpc_ismeta=1"
+ << "xhpc_timeline=1"
+ << "xhpc_composerid=u_0_2y"
+ << "is_explicit_place="
+ << "composertags_place="
+ << "composertags_city="
+ << "composer_session_id="
+ << "composer_predicted_city="
+ << "disable_location_sharing=false"
+ << "nctr[_mod]=pagelet_composer";
+
+ if (!status->isPage) {
+ Body << CHAR_VALUE("audience[0][value]", fc->get_privacy_type().c_str());
+ }
+
+ if (!status->place.empty()) {
+ Body << CHAR_VALUE("composertags_place_name", ptrA(mir_urlEncode(status->place.c_str())));
+ }
+
+ // Status with users
+ for (std::vector<facebook_user*>::size_type i = 0; i < status->users.size(); i++) {
+ CMStringA withId(::FORMAT, "composertags_with[%i]", i);
+ CMStringA withName(::FORMAT, "text_composertags_with[%i]", i);
+
+ Body
+ << CHAR_VALUE(withId.c_str(), status->users[i]->user_id.c_str())
+ << CHAR_VALUE(withName.c_str(), status->users[i]->real_name.c_str());
+ }
+
+ // Link attachment
+ if (mir_strlen(linkData) > 0) {
+ Body
+ << linkData;
+ // << "no_picture=0" // for disabling link preview image
+ }
+ }
+};
+
+// sending pokes
+class SendPokeRequest : public HttpRequest
+{
+public:
+ SendPokeRequest(facebook_client *fc, const char *userId) :
+ HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/pokes/dialog/")
+ {
+ Url
+ << "__a=1";
+
+ Body
+ << "do_confirm=0"
+ << CHAR_VALUE("poke_target", userId)
+ << CHAR_VALUE("fb_dtsg", fc->dtsg_.c_str())
+ << CHAR_VALUE("__user", fc->self_.user_id.c_str())
+ << CHAR_VALUE("ttstamp", fc->ttstamp_.c_str());
+ }
+};
+
+#endif //_FACEBOOK_REQUEST_UTILS_H_
diff --git a/protocols/FacebookRM/src/stdafx.h b/protocols/FacebookRM/src/stdafx.h
index c492e974dc..e8d18e90c1 100644
--- a/protocols/FacebookRM/src/stdafx.h
+++ b/protocols/FacebookRM/src/stdafx.h
@@ -81,6 +81,18 @@ class FacebookProto;
#include "resource.h"
#include "version.h"
+#include "requests/contacts.h"
+#include "requests/feeds.h"
+#include "requests/history.h"
+#include "requests/channel.h"
+#include "requests/login.h"
+#include "requests/messages.h"
+#include "requests/notifications.h"
+#include "requests/profile.h"
+#include "requests/search.h"
+#include "requests/status.h"
+#include "requests/utils.h"
+
extern HINSTANCE g_hInstance;
extern std::string g_strUserAgent;
extern DWORD g_mirandaVersion;
@@ -106,3 +118,10 @@ private:
HANDLE handle_;
int timeout_;
};
+
+template <typename T>
+__inline static void FreeList(const LIST<T> &lst)
+{
+ for (int i = 0; i < lst.getCount(); i++)
+ mir_free(lst[i]);
+} \ No newline at end of file