diff options
Diffstat (limited to 'protocols/FacebookRM/src')
20 files changed, 1509 insertions, 920 deletions
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&", "\""); + postData = utils::text::source_get_form_data(&form, true); + getData = utils::text::source_get_value(&form, 2, "login.php?login_attempt=1&", "\""); } - 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 += "×tamp=" + 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 += "¤t_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 += "×tamp=" + utils::conversion::to_string((void*)×tamp, 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 |