diff options
Diffstat (limited to 'protocols/FacebookRM')
22 files changed, 1558 insertions, 921 deletions
| diff --git a/protocols/FacebookRM/facebook.vcxproj b/protocols/FacebookRM/facebook.vcxproj index 6d62bbe82f..8d14219953 100644 --- a/protocols/FacebookRM/facebook.vcxproj +++ b/protocols/FacebookRM/facebook.vcxproj @@ -29,7 +29,17 @@      <ClCompile Include="..\..\utils\std_string_utils.cpp">
        <PrecompiledHeader>NotUsing</PrecompiledHeader>
      </ClCompile>
 -    <ClInclude Include="src\requests\*.h" />
 +    <ClInclude Include="src\requests\channel.h" />
 +    <ClInclude Include="src\requests\contacts.h" />
 +    <ClInclude Include="src\requests\feeds.h" />
 +    <ClInclude Include="src\requests\history.h" />
 +    <ClInclude Include="src\requests\login.h" />
 +    <ClInclude Include="src\requests\messages.h" />
 +    <ClInclude Include="src\requests\search.h" />
 +    <ClInclude Include="src\requests\status.h" />
 +    <ClInclude Include="src\requests\profile.h" />
 +    <ClInclude Include="src\requests\notifications.h" />
 +    <ClInclude Include="src\requests\utils.h" />
    </ItemGroup>
    <ItemDefinitionGroup>
      <ClCompile>
 diff --git a/protocols/FacebookRM/facebook.vcxproj.filters b/protocols/FacebookRM/facebook.vcxproj.filters index aaf0565537..54b30eff0c 100644 --- a/protocols/FacebookRM/facebook.vcxproj.filters +++ b/protocols/FacebookRM/facebook.vcxproj.filters @@ -9,4 +9,42 @@        <Filter>Header Files\requests</Filter>
      </ClInclude>
    </ItemGroup>
 +  <ItemGroup>
 +    <ClInclude Include="src\requests\channel.h">
 +      <Filter>Header Files\requests</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\requests\chat.h">
 +      <Filter>Header Files\requests</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\requests\contacts.h">
 +      <Filter>Header Files\requests</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\requests\feeds.h">
 +      <Filter>Header Files\requests</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\requests\history.h">
 +      <Filter>Header Files\requests</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\requests\login.h">
 +      <Filter>Header Files\requests</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\requests\messages.h">
 +      <Filter>Header Files\requests</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\requests\notifications.h">
 +      <Filter>Header Files\requests</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\requests\profile.h">
 +      <Filter>Header Files\requests</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\requests\search.h">
 +      <Filter>Header Files\requests</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\requests\status.h">
 +      <Filter>Header Files\requests</Filter>
 +    </ClInclude>
 +    <ClInclude Include="src\requests\utils.h">
 +      <Filter>Header Files\requests</Filter>
 +    </ClInclude>
 +  </ItemGroup>
  </Project>
\ No newline at end of file diff --git a/protocols/FacebookRM/src/client.h b/protocols/FacebookRM/src/client.h index 22297ebf26..14af119921 100644 --- a/protocols/FacebookRM/src/client.h +++ b/protocols/FacebookRM/src/client.h @@ -146,18 +146,18 @@ public:  	// Helpers for data
 -	std::string __inline __dyn() {
 +	__inline const char *__dyn() {
  		return ""; // FIXME: What's this value and where it come from? Looks like it is the same through all requests.
  	}
 -	std::string __inline __req() {
 +	__inline const char *__req() {
  		// Increment request number and convert it to string with radix 36 (whole numbers + whole alphabet)
  		char buffer[10];
  		itoa(InterlockedIncrement(&this->chat_req_), buffer, 36);
 -		return std::string(buffer);
 +		return ptrA(mir_strdup(buffer));
  	}
 -	std::string __inline __rev() {
 +	__inline const char *__rev() {
  		return "2509236"; // FIXME: Some version of communication protocol? This version is from 17.8.2016
  	}
 @@ -208,15 +208,9 @@ public:  	// HTTP communication
 -	http::response flap(RequestType request_type, std::string *post_data = NULL, std::string *get_data = NULL);
 +	http::response sendRequest(HttpRequest *request);
  	bool save_url(const std::string &url,const std::wstring &filename, HANDLE &nlc);
 -	bool notify_errors(RequestType);
 -	std::string choose_server(RequestType);
 -	std::string choose_action(RequestType, std::string *get_data = NULL);
 -
 -	NETLIBHTTPHEADER *get_request_headers(int request_type, int *headers_count);
 -
  	////////////////////////////////////////////////////////////
  	// Netlib handle
 diff --git a/protocols/FacebookRM/src/communication.cpp b/protocols/FacebookRM/src/communication.cpp index a7002d41e1..452a6fe24a 100644 --- a/protocols/FacebookRM/src/communication.cpp +++ b/protocols/FacebookRM/src/communication.cpp @@ -27,7 +27,7 @@ void facebook_client::client_notify(wchar_t* message)  	parent->NotifyEvent(parent->m_tszUserName, message, NULL, EVENT_CLIENT);  } -http::response facebook_client::flap(RequestType request_type, std::string *post_data, std::string *get_data) +http::response facebook_client::sendRequest(HttpRequest *request)  {  	http::response resp; @@ -36,80 +36,56 @@ http::response facebook_client::flap(RequestType request_type, std::string *post  		return resp;  	} -	// Prepare the request -	NETLIBHTTPREQUEST nlhr = { sizeof(NETLIBHTTPREQUEST) }; - -	std::string server = choose_server(request_type); - -	// Set request URL -	std::string url = HTTP_PROTO_SECURE + server + choose_action(request_type, get_data);  	if (!parent->m_locale.empty()) -		url += "&locale=" + parent->m_locale; -	 -	nlhr.szUrl = (char*)url.c_str(); - -	// Set timeout (bigger for channel request) -	switch (request_type) { -	case REQUEST_MESSAGES_RECEIVE: -		nlhr.timeout = 1000 * 65; -		break; - -	default: -		nlhr.timeout = 1000 * 20; -		break; -	} - -	// Set request type (GET/POST) and eventually also POST data -	if (post_data != NULL) { -		nlhr.requestType = REQUEST_POST; -		nlhr.pData = (char*)(*post_data).c_str(); -		nlhr.dataLength = (int)post_data->length(); -	} else { -		nlhr.requestType = REQUEST_GET; -	} - -	// Set headers - it depends on requestType so it must be after setting that -	nlhr.headers = get_request_headers(nlhr.requestType, &nlhr.headersCount);	 +		request->Url << CHAR_VALUE("locale", parent->m_locale.c_str()); -	// Set flags -	nlhr.flags = NLHRF_HTTP11 | NLHRF_SSL; +	request->Headers +		<< CHAR_VALUE("Accept-Language", "en,en-US;q=0.9") +		<< CHAR_VALUE("Accept", "*/*") +		<< CHAR_VALUE("User-Agent", g_strUserAgent.c_str()) +		<< CHAR_VALUE("Cookie", ptrA(load_cookies())); // FIXME: Rework load_cookies to not do strdup -	if (server == FACEBOOK_SERVER_MBASIC || server == FACEBOOK_SERVER_MOBILE) { -		nlhr.flags |= NLHRF_REDIRECT; +	if (request->requestType == REQUEST_POST) { +		request->Headers +			<< CHAR_VALUE("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");  	} +	// TODO: rather change http_request than doing this ifdef magic here?  #ifdef _DEBUG  -	nlhr.flags |= NLHRF_DUMPASTEXT; +	request->flags &= ~NLHRF_NODUMP; +	request->flags |= NLHRF_DUMPASTEXT;  #else -	nlhr.flags |= NLHRF_NODUMP; +	request->flags &= ~NLHRF_DUMPASTEXT; +	request->flags |= NLHRF_NODUMP;  #endif +	// FIXME: Support persistent connection for various requests +	/*  	// Set persistent connection (or not)  	switch (request_type) {  	case REQUEST_LOGIN: -		nlhr.nlc = NULL; +		request->nlc = NULL;  		break;  	case REQUEST_MESSAGES_RECEIVE: -		nlhr.nlc = hMsgCon; -		nlhr.flags |= NLHRF_PERSISTENT; +		request->nlc = hMsgCon; +		request->flags |= NLHRF_PERSISTENT;  		break;  	default:  		WaitForSingleObject(fcb_conn_lock_, INFINITE); -		nlhr.nlc = hFcbCon; -		nlhr.flags |= NLHRF_PERSISTENT; +		request->nlc = hFcbCon; +		request->flags |= NLHRF_PERSISTENT;  		break;  	} - -	parent->debugLogA("@@@ Sending request to '%s'", nlhr.szUrl); +	*/ +	parent->debugLogA("@@@ Sending request to '%s'", request->szUrl);  	// Send the request	 -	NETLIBHTTPREQUEST *pnlhr = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)handle_, (LPARAM)&nlhr);	 - -	mir_free(nlhr.headers[3].szValue); -	mir_free(nlhr.headers); +	NETLIBHTTPREQUEST *pnlhr = request->Send(handle_); +	// FIXME: Support persistent connection for various requests +	/*  	// Remember the persistent connection handle (or not)  	switch (request_type) {  	case REQUEST_LOGIN: @@ -125,6 +101,7 @@ http::response facebook_client::flap(RequestType request_type, std::string *post  		hFcbCon = pnlhr ? pnlhr->nlc : NULL;  		break;  	} +	*/  	// Check and copy response data  	if (pnlhr != NULL) { @@ -134,12 +111,16 @@ http::response facebook_client::flap(RequestType request_type, std::string *post  		resp.data = pnlhr->pData ? pnlhr->pData : "";  		CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)pnlhr); -	} else { +	} +	else {  		parent->debugLogA("!!! No response from server (time-out)");  		resp.code = HTTP_CODE_FAKE_DISCONNECTED;  		// Better to have something set explicitely as this value is compaired in all communication requests  	} +	// Delete the request object +	delete request; +  	// Get Facebook's error message  	if (resp.code == HTTP_CODE_OK) {  		std::string::size_type pos = resp.data.find("\"error\":"); @@ -180,7 +161,7 @@ http::response facebook_client::flap(RequestType request_type, std::string *post  				resp.code = HTTP_CODE_FAKE_ERROR;  				parent->debugLogA("!!! Received Facebook error: %d -- %s", error_num, error.c_str()); -				if (notify_errors(request_type) && !silent) +				if (request->NotifyErrors && !silent)  					client_notify(_A2T(error.c_str()));  			}  		} @@ -223,359 +204,6 @@ bool facebook_client::handle_error(const std::string &method, int action)  ////////////////////////////////////////////////////////////////////////////// -std::string facebook_client::choose_server(RequestType request_type) -{ -	switch (request_type) -	{ -	case REQUEST_LOGIN: -		return FACEBOOK_SERVER_LOGIN; - -	case REQUEST_MESSAGES_RECEIVE: -	case REQUEST_ACTIVE_PING: -	{ -		std::string server = FACEBOOK_SERVER_CHAT; -		utils::text::replace_first(&server, "%s", this->chat_conn_num_.empty() ? "0" : this->chat_conn_num_); -		utils::text::replace_first(&server, "%s", this->chat_channel_host_); -		return server; -	} - -	case REQUEST_HOME: -	case REQUEST_DTSG: -		return FACEBOOK_SERVER_MOBILE; - -	case REQUEST_LOAD_FRIENDSHIPS: -	case REQUEST_SEARCH: -	case REQUEST_USER_INFO_MOBILE: -	case REQUEST_PROFILE_PICTURE: -		return this->mbasicWorks ? FACEBOOK_SERVER_MBASIC : FACEBOOK_SERVER_MOBILE; - -		//	case REQUEST_LOGOUT: -		//	case REQUEST_USER_INFO: -		//	case REQUEST_USER_INFO_ALL: -		//	case REQUEST_FEEDS: -		//	case REQUEST_PAGES: -		//	case REQUEST_NOTIFICATIONS: -		//	case REQUEST_RECONNECT: -		//	case REQUEST_POST_STATUS: -		//	case REQUEST_IDENTITY_SWITCH: -		//	case REQUEST_CAPTCHA_REFRESH: -		//	case REQUEST_LINK_SCRAPER: -		//	case REQUEST_MESSAGES_SEND: -		//	case REQUEST_THREAD_INFO: -		//	case REQUEST_THREAD_SYNC: -		//	case REQUEST_VISIBILITY: -		//	case REQUEST_POKE: -		//	case REQUEST_MARK_READ: -		//	case REQUEST_NOTIFICATIONS_READ: -		//	case REQUEST_TYPING_SEND: -		//	case REQUEST_SETUP_MACHINE: -		//  case REQUEST_DELETE_FRIEND: -		//	case REQUEST_ADD_FRIEND: -		//	case REQUEST_CANCEL_FRIENDSHIP: -		//	case REQUEST_FRIENDSHIP: -		//	case REQUEST_UNREAD_THREADS: -		//	case REQUEST_ON_THIS_DAY: -		//	case REQUEST_LOGIN_SMS: -	default: -		return FACEBOOK_SERVER_REGULAR; -	} -} - -std::string facebook_client::choose_action(RequestType request_type, std::string *get_data) -{ -	// NOTE: Parameter "client" used in some requests's POST data could be "jewel" (top bar?), "mercury" (chat window, source=source:chat:web) or "web_messenger" (whole chat messages page, source=source:titan:web) - -	switch (request_type) -	{ -	case REQUEST_LOGIN: -	{ -		std::string action = "/login.php?login_attempt=1"; -		if (get_data != NULL) { -			action += *get_data; -		} -		return action; -	} - -	case REQUEST_SETUP_MACHINE: -		return "/checkpoint/?next"; - -	case REQUEST_LOGOUT: -		return "/logout.php?"; - -	case REQUEST_HOME: -		return "/profile.php?v=info"; - -	case REQUEST_DTSG: -		return "/editprofile.php?edit=current_city&type=basic"; - -	case REQUEST_USER_INFO: // ok, 17.8.2016 -		return "/chat/user_info/?dpr=1"; - -	case REQUEST_USER_INFO_ALL: // ok, 17.8.2016 -		return "/chat/user_info_all/?dpr=1&viewer=" + self_.user_id; - -	case REQUEST_USER_INFO_MOBILE: -	{ -		std::string action = "/%sv=info"; -		if (get_data != NULL) { -			utils::text::replace_all(&action, "%s", *get_data); -		} -		return action; -	} - -	case REQUEST_LOAD_FRIENDSHIPS: -	{ -		return "/friends/center/requests/?"; -	} - -	case REQUEST_SEARCH: -	{ -		std::string action = "/search/?search=people&query="; -		if (get_data != NULL) { -			action += *get_data; -		} -		return action; -	} - -	case REQUEST_UNREAD_THREADS: // ok, 17.8.2016 -	{ -		return "/ajax/mercury/unread_threads.php?dpr=1"; -	} - -	case REQUEST_DELETE_FRIEND: -	{ -		std::string action = "/ajax/profile/removefriendconfirm.php?__a=1"; -		if (get_data != NULL) { -			action += *get_data; -		} -		return action; -	} - -	case REQUEST_ADD_FRIEND: -	{ -		return "/ajax/add_friend/action.php?__a=1"; -	} - -	case REQUEST_CANCEL_FRIENDSHIP: -	{ -		return "/ajax/friends/requests/cancel.php?__a=1"; -	} - -	case REQUEST_FRIENDSHIP: -	{ -		return "/requests/friends/ajax/?__a=1"; -	} - -	case REQUEST_FEEDS: -	{ -		std::string action = "/ajax/home/generic.php?" + get_newsfeed_type(); -		action += "&__user=" + self_.user_id + "&__a=1"; - -		/*std::string newest = utils::conversion::to_string((void*)&this->last_feeds_update_, UTILS_CONV_TIME_T); -		utils::text::replace_first(&action, "%s", newest); -		utils::text::replace_first(&action, "%s", self_.user_id);*/ -		return action; -	} - -	case REQUEST_PAGES: -	{ -		return "/bookmarks/pages?"; -	} - -	case REQUEST_NOTIFICATIONS: // ok, 17.8.2016 -	{ -		return "/ajax/notifications/client/get.php?dpr=1"; -	} - -	case REQUEST_RECONNECT: // ok, 17.8.2016 -	{ -		std::string action = "/ajax/presence/reconnect.php?__a=1&reason=%s&fb_dtsg=%s&__user=%s"; - -		if (this->chat_reconnect_reason_.empty()) -			this->chat_reconnect_reason_ = "6"; - -		utils::text::replace_first(&action, "%s", this->chat_reconnect_reason_); -		utils::text::replace_first(&action, "%s", this->dtsg_); -		utils::text::replace_first(&action, "%s", this->self_.user_id); - -		action += "&__dyn=" + __dyn(); -		action += "&__req=" + __req(); -		action += "&__rev=" + __rev(); -		action += "&__pc=PHASED:DEFAULT&__be=-1&__a=1"; - -		return action; -	} - -	case REQUEST_POST_STATUS: -		return "/ajax/updatestatus.php?__a=1"; - -	case REQUEST_IDENTITY_SWITCH: -		return "/identity_switch.php?__a=1"; - -	case REQUEST_CAPTCHA_REFRESH: -	{ -		std::string action = "/captcha/refresh_ajax.php?__a=1"; -		if (get_data != NULL) { -			action += "&" + (*get_data); -		} -		return action; -	} - -	case REQUEST_LINK_SCRAPER: -	{ -		std::string action = "/ajax/composerx/attachment/link/scraper/?__a=1&composerurihash=2&scrape_url="; -		if (get_data != NULL) { -			action += utils::url::encode(*get_data); -		} -		return action; -	} - -	case REQUEST_MESSAGES_SEND: -		return "/messaging/send/?dpr=1"; - -	case REQUEST_THREAD_INFO: // ok, 17.8.2016 -		return "/ajax/mercury/thread_info.php?dpr=1"; - -	case REQUEST_THREAD_SYNC: // TODO: This doesn't work anymore -		return "/ajax/mercury/thread_sync.php?__a=1"; - -	case REQUEST_MESSAGES_RECEIVE: -	case REQUEST_ACTIVE_PING: -	{ -		bool isPing = (request_type == REQUEST_ACTIVE_PING); - -		std::string action = (isPing ? "/active_ping" : "/pull"); -		action += "?channel=" + (this->chat_channel_.empty() ? "p_" + self_.user_id : this->chat_channel_);		 -		if (!isPing) -			action += "&seq=" + (this->chat_sequence_num_.empty() ? "0" : this->chat_sequence_num_); -		action += "&partition=" + (this->chat_channel_partition_.empty() ? "0" : this->chat_channel_partition_); -		action += "&clientid=" + this->chat_clientid_; -		action += "&cb=" + utils::text::rand_string(4, "0123456789abcdefghijklmnopqrstuvwxyz", &this->random_); - -		/* -		original cb = return (1048576 * Math.random() | 0).toString(36); -		char buffer[10]; -		itoa(((int)(1048576 * (((double)rand()) / (RAND_MAX + 1))) | 0), buffer, 36); -		action += "&cb=" + buffer; -		*/ - -		int idleSeconds = parent->IdleSeconds(); -		if (idleSeconds > 0 && !parent->isInvisible()) -			action += "&idle=" + utils::conversion::to_string(&idleSeconds, UTILS_CONV_UNSIGNED_NUMBER); - -		if (!isPing) { -			action += "&qp=y"; // TODO: what's this item? -			action += "&pws=fresh"; // TODO: what's this item? -			action += "&isq=487632"; // TODO: what's this item? -			action += "&msgs_recv=" + utils::conversion::to_string(&this->chat_msgs_recv_, UTILS_CONV_UNSIGNED_NUMBER); -			// TODO: sometimes there is &tur=1711 and &qpmade=<some actual timestamp> and &isq=487632 -			// action += "&request_batch=1"; // it somehow batches up more responses to one - then response has special "t=batched" type and "batches" array with the data -			// action += "&msgr_region=LLA"; // it was here only for first pull, same as request_batch -		} - -		action += "&cap=8"; // TODO: what's this item? Sometimes it's 0, sometimes 8 -		action += "&uid=" + self_.user_id; -		action += "&viewer_uid=" + self_.user_id; - -		if (!this->chat_sticky_num_.empty() && !this->chat_sticky_pool_.empty()) { -			action += "&sticky_token=" + this->chat_sticky_num_; -			action += "&sticky_pool=" + this->chat_sticky_pool_; -		} - -		if (!isPing && !this->chat_traceid_.empty()) -			action += "&traceid=" + this->chat_traceid_; - -		if (parent->isInvisible()) -			action += "&state=offline"; -		else if (isPing || idleSeconds < 60) -			action += "&state=active"; - -		return action; -	} - -	case REQUEST_VISIBILITY: -		return "/ajax/chat/privacy/visibility.php?dpr=1"; // ok, 17.8.2016 - -	case REQUEST_POKE: -		return "/pokes/dialog/?__a=1"; - -	case REQUEST_MARK_READ: -		return "/ajax/mercury/change_read_status.php?__a=1"; - -	case REQUEST_NOTIFICATIONS_READ: -	{ -		std::string action = "/ajax/notifications/mark_read.php?__a=1"; -		if (get_data != NULL) { -			action += "&" + (*get_data); -		} -		return action; -	} - -	case REQUEST_TYPING_SEND: -		return "/ajax/messaging/typ.php?dpr=1"; // ok, 17.8.2016 - -	case REQUEST_ON_THIS_DAY: -	{ -		std::string action = "/onthisday/story/query/?__a=1"; -		if (get_data != NULL) { -			action += "&" + (*get_data); -		} -		return action; -	} - -	case REQUEST_LOGIN_SMS: -	{ -		return "/ajax/login/approvals/send_sms?dpr=1"; -	} - -	case REQUEST_PROFILE_PICTURE: -	{ -		return "/profile/picture/view/?profile_id=" + self_.user_id; -	} - -	default: -		return "/?_fb_noscript=1"; -	} -} - -bool facebook_client::notify_errors(RequestType request_type) -{ -	switch (request_type) -	{ -	case REQUEST_MESSAGES_SEND: -		return false; - -	default: -		return true; -	} -} - -NETLIBHTTPHEADER *facebook_client::get_request_headers(int request_type, int *headers_count) -{ -	if (request_type == REQUEST_POST) -		*headers_count = 5; -	else -		*headers_count = 4; - -	NETLIBHTTPHEADER *headers = (NETLIBHTTPHEADER*)mir_calloc(sizeof(NETLIBHTTPHEADER)*(*headers_count)); - -	if (request_type == REQUEST_POST) { -		headers[4].szName = "Content-Type"; -		headers[4].szValue = "application/x-www-form-urlencoded; charset=utf-8"; -	} - -	headers[3].szName = "Cookie"; -	headers[3].szValue = load_cookies(); -	headers[2].szName = "User-Agent"; -	headers[2].szValue = (char *)g_strUserAgent.c_str(); -	headers[1].szName = "Accept"; -	headers[1].szValue = "*/*"; -	headers[0].szName = "Accept-Language"; -	headers[0].szValue = "en,en-US;q=0.9"; - -	return headers; -} -  std::string facebook_client::get_newsfeed_type()  {  	BYTE feed_type = parent->getByte(FACEBOOK_KEY_FEED_TYPE, 0); @@ -803,12 +431,8 @@ bool facebook_client::login(const char *username, const char *password)  	username_ = username;  	password_ = password; -	// Prepare login data -	std::string data = "persistent=1"; -	data += "&email=" + utils::url::encode(username); -	data += "&pass=" + utils::url::encode(password); - -	std::string get_data = ""; +	std::string postData; +	std::string getData;  	if (cookies.empty()) {  		// Set device ID @@ -817,7 +441,8 @@ bool facebook_client::login(const char *username, const char *password)  			cookies["datr"] = device;  		// Get initial cookies -		http::response resp = flap(REQUEST_LOGIN); +		LoginRequest *request = new LoginRequest(); +		http::response resp = sendRequest(request);  		// Also parse cookies set by JavaScript (more variant exists in time, so check all known now)  		parseJsCookies("[\"DeferredCookie\",\"addToQueue\",[],[\"", resp.data, cookies); @@ -827,14 +452,13 @@ bool facebook_client::login(const char *username, const char *password)  		std::string form = utils::text::source_get_value(&resp.data, 2, "<form", "</form>");  		utils::text::replace_all(&form, "\\\"", "\""); -		data += "&" + utils::text::source_get_form_data(&form, true); -		get_data += "&" + utils::text::source_get_value(&form, 2, "login.php?login_attempt=1&", "\""); +		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 | 
