", "");
		// Get and strip optional nickname
		std::string::size_type pos = this->self_.real_name.find("
");
		if (pos != std::string::npos) {
			this->self_.nick = utils::text::source_get_value(&this->self_.real_name, 2, "(", ")");
			parent->debugLogA("      Got self nick name: %s", this->self_.nick.c_str());
			this->self_.real_name = this->self_.real_name.substr(0, pos - 1);
		}
		this->self_.real_name = utils::text::remove_html(this->self_.real_name);
		parent->debugLogA("      Got self real name: %s", this->self_.real_name.c_str());
		parent->SaveName(NULL, &this->self_);
		// Get avatar
		this->self_.image_url = utils::text::source_get_value(&resp.data, 3, "id=\"root", " debugLogA("      Got self avatar: %s", this->self_.image_url.c_str());
		parent->CheckAvatarChange(NULL, this->self_.image_url);
		// Get logout hash
		this->logout_hash_ = utils::text::source_get_value2(&resp.data, "/logout.php?h=", "&\"");
		parent->debugLogA("      Got self logout hash: %s", this->logout_hash_.c_str());
		if (this->self_.real_name.empty() || this->self_.image_url.empty() || this->logout_hash_.empty()) {
			parent->debugLogA("!!!!! Empty nick/avatar/hash. Source code:\n%s", resp.data.c_str());
			client_notify(TranslateT("Could not load all required data. Plugin may still work correctly, but you should report this and wait for plugin update."));
		}
		return handle_success("home");
	}
	case HTTP_CODE_FOUND:
		// Work-around for replica_down, f**king hell what's that?
		parent->debugLogA("      REPLICA_DOWN is back in force!");
		return this->home();
	
	default:
		return handle_error("home", FORCE_QUIT);
	}
}
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;
	http::response resp = flap(REQUEST_VISIBILITY, &data);
	
	if (!resp.error_title.empty())
		return handle_error("chat_state");
	return handle_success("chat_state");
}
bool facebook_client::reconnect()
{
	handle_entry("reconnect");
	// Request reconnect
	http::response resp = flap(REQUEST_RECONNECT);
	switch (resp.code)
	{
	case HTTP_CODE_OK:
	{
		this->chat_channel_ = utils::text::source_get_value(&resp.data, 2, "\"user_channel\":\"", "\"");
		parent->debugLogA("      Got self channel: %s", this->chat_channel_.c_str());
				
		this->chat_channel_partition_ = utils::text::source_get_value2(&resp.data, "\"partition\":", ",}");
		parent->debugLogA("      Got self channel partition: %s", this->chat_channel_partition_.c_str());
		
		this->chat_channel_host_ = utils::text::source_get_value(&resp.data, 2, "\"host\":\"", "\"");
		parent->debugLogA("      Got self channel host: %s", this->chat_channel_host_.c_str());
		this->chat_sequence_num_ = utils::text::source_get_value2(&resp.data, "\"seq\":", ",}");
		parent->debugLogA("      Got self sequence number: %s", this->chat_sequence_num_.c_str());
		this->chat_conn_num_ = utils::text::source_get_value2(&resp.data, "\"max_conn\":", ",}");
		parent->debugLogA("      Got self max_conn: %s", this->chat_conn_num_.c_str());
		
		this->chat_sticky_num_ = utils::text::source_get_value(&resp.data, 2, "\"sticky_token\":\"", "\"");
		parent->debugLogA("      Got self sticky_token: %s", this->chat_sticky_num_.c_str());
		//std::string retry_interval = utils::text::source_get_value2(&resp.data, "\"retry_interval\":", ",}");
		//parent->debugLogA("      Got self retry_interval: %s", retry_interval.c_str());
		//std::string visibility = utils::text::source_get_value2(&resp.data, "\"visibility\":", ",}");
		//parent->debugLogA("      Got self visibility: %s", visibility);
		return handle_success("reconnect");
	}
	 
	default:
		return handle_error("reconnect", FORCE_DISCONNECT);
	}
}
bool facebook_client::channel()
{
	handle_entry("channel");
	// Get update
	http::response resp = flap(REQUEST_MESSAGES_RECEIVE);
	if (resp.data.empty()) {
		// Something went wrong
		return handle_error("channel");
	}
	// Load traceId, if present
	std::string traceId = utils::text::source_get_value(&resp.data, 2, "\"tr\":\"", "\"");
	if (!traceId.empty()) {
		this->chat_traceid_ = traceId;
	}
	std::string type = utils::text::source_get_value(&resp.data, 2, "\"t\":\"", "\"");
	if (type == "continue" || type == "heartbeat") {
		// Everything is OK, no new message received
	}
	else if (type == "lb") {
		// Some new stuff (idk how does it work yet)
		this->chat_channel_host_ = utils::text::source_get_value(&resp.data, 2, "\"vip\":\"", "\"");
		parent->debugLogA("      Got self channel host: %s", this->chat_channel_host_.c_str());
		this->chat_sticky_num_ = utils::text::source_get_value2(&resp.data, "\"sticky\":\"", "\"");
		parent->debugLogA("      Got self sticky number: %s", this->chat_sticky_num_.c_str());
	}
	else if (type == "fullReload" || type == "refresh") {
		// Requested reload of page or relogin (due to some settings change, removing this session, etc.)
		parent->debugLogA("! ! ! Requested %s", type.c_str());
		this->chat_sequence_num_ = utils::text::source_get_value2(&resp.data, "\"seq\":", ",}");
		parent->debugLogA("      Got self sequence number: %s", this->chat_sequence_num_.c_str());
		if (type == "refresh") {
			this->chat_reconnect_reason_ = utils::text::source_get_value2(&resp.data, "\"reason\":", ",}");
			parent->debugLogA("      Reconnect reason: %s", this->chat_reconnect_reason_.c_str());
			return this->reconnect();
		}
	}
	else if (!type.empty()) {
		// Something has been received, throw to new thread to process
		std::string* response_data = new std::string(resp.data);
		parent->ForkThread(&FacebookProto::ProcessMessages, response_data);
		// Increment sequence number
		this->chat_sequence_num_ = utils::text::source_get_value2(&resp.data, "\"seq\":", ",}");
		parent->debugLogA("      Got self sequence number: %s", this->chat_sequence_num_.c_str());
	}
	else {
		// No type? This shouldn't happen unless there is a big API change.
		return handle_error("channel");
	}
	// Return
	switch (resp.code)
	{
	case HTTP_CODE_OK:
		return handle_success("channel");
	case HTTP_CODE_GATEWAY_TIMEOUT:
		// Maybe we have same clientid as other connected client, try to generate different one
		this->chat_clientid_ = utils::text::rand_string(8, "0123456789abcdef");
		// Intentionally fall to handle_error() below
	case HTTP_CODE_FAKE_DISCONNECTED:
	case HTTP_CODE_FAKE_ERROR:
	default:
		return handle_error("channel");
	}
}
int facebook_client::send_message(MCONTACT hContact, std::string message_recipient, std::string message_text, std::string *error_text, MessageMethod method, std::string captcha_persist_data, std::string captcha)
{
	ScopedLock s(send_message_lock_);
	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;
	}
	switch (method) {
		case MESSAGE_INBOX:
		{
			parent->debugLogA("    > Sending message through INBOX");
			data += "&action=send";
			data += "&body=" + utils::url::encode(message_text);
			data += "&recipients[0]=" + message_recipient;
			data += "&__user=" + this->self_.user_id;
			data += "&__a=1";
			data += "&fb_dtsg=" + this->dtsg_;
			data += "&phstamp=0";
			resp = flap(REQUEST_MESSAGE_SEND_INBOX, &data);
			break;
		}
		case MESSAGE_MERCURY:
		{
			parent->debugLogA("    > Sending message through CHAT");
			data += "&message_batch[0][action_type]=ma-type:user-generated-message";
			data += "&message_batch[0][thread_id]";
			data += "&message_batch[0][author]=fbid:" + this->self_.user_id;
			data += "&message_batch[0][author_email]";
			data += "&message_batch[0][coordinates]";
			data += "&message_batch[0][timestamp]=" + utils::time::mili_timestamp();
			data += "&message_batch[0][timestamp_absolute]";
			data += "&message_batch[0][timestamp_relative]";
			data += "&message_batch[0][is_unread]=false";
			data += "&message_batch[0][is_cleared]=false";
			data += "&message_batch[0][is_forward]=false";
			data += "&message_batch[0][spoof_warning]=false";
			data += "&message_batch[0][source]=source:chat:web";
			data += "&message_batch[0][source_tags][0]=source:chat";
			data += "&message_batch[0][body]=" + utils::url::encode(message_text);
			data += "&message_batch[0][has_attachment]=false";
			data += "&message_batch[0][html_body]=false";
			data += "&message_batch[0][specific_to_list][0]=fbid:" + message_recipient;
			data += "&message_batch[0][specific_to_list][1]=fbid:" + this->self_.user_id;
			data += "&message_batch[0][status]=0";
			data += "&message_batch[0][message_id]";
			data += "&message_batch[0][client_thread_id]=user:" + message_recipient;
			data += "&client=mercury";
			data += "&fb_dtsg=" + this->dtsg_;
			data += "&__user=" + this->self_.user_id;
			data += "&__a=1";
			data += "&phstamp=0";
			resp = flap(REQUEST_MESSAGE_SEND_CHAT, &data);
			break;
		}
		case MESSAGE_TID:
		{
			parent->debugLogA("    > Sending message through MERCURY (TID)");
			data += "&message_batch[0][action_type]=ma-type:user-generated-message";
			data += "&message_batch[0][thread_id]=" + message_recipient;
			data += "&message_batch[0][author]=fbid:" + this->self_.user_id;
			data += "&message_batch[0][timestamp]=" + utils::time::mili_timestamp();
			data += "&message_batch[0][timestamp_absolute]=";
			data += "&message_batch[0][timestamp_relative]=";
			data += "&message_batch[0][is_unread]=false";
			data += "&message_batch[0][is_cleared]=false";
			data += "&message_batch[0][is_forward]=false";
			data += "&message_batch[0][source]=source:chat:web";
			data += "&message_batch[0][body]=" + utils::url::encode(message_text);
			data += "&message_batch[0][has_attachment]=false";
			data += "&message_batch[0][is_html]=false";
			data += "&message_batch[0][message_id]=";
			data += "&fb_dtsg=" + this->dtsg_;
			data += "&__user=" + this->self_.user_id;
			data += "&phstamp=0";
			resp = flap(REQUEST_MESSAGE_SEND_CHAT, &data);
			break;
		}
		case MESSAGE_ASYNC:
		{
			parent->debugLogA("    > Sending message through ASYNC");
			data += "&action=send";
			data += "&body=" + utils::url::encode(message_text);
			data += "&recipients[0]=" + message_recipient;
			data += "&lsd=";
			data += "&fb_dtsg=" + this->dtsg_;
			resp = flap(REQUEST_ASYNC, &data);
			break;
		}
	}
	
	*error_text = resp.error_text;
	switch (resp.error_number)
	{
  	case 0: // Everything is OK
	{
		// Remember this message id
		std::string mid = utils::text::source_get_value(&resp.data, 2, "\"message_id\":\"", "\"");
		if (mid.empty())
			mid = utils::text::source_get_value(&resp.data, 2, "\"mid\":\"", "\"");
		parent->setString(hContact, FACEBOOK_KEY_MESSAGE_ID, mid.c_str());
		messages_ignore.insert(std::make_pair(mid, 0));
	} break;
    //case 1356002: // You are offline (probably you can't use mercury or some other request when chat is offline)
	case 1356003: // Contact is offline
	{
		MCONTACT hContact = parent->ContactIDToHContact(message_recipient);
		if (hContact != NULL)
  			parent->setWord(hContact, "Status", ID_STATUS_OFFLINE);
		return SEND_MESSAGE_ERROR;
	}
  	case 1356026: // Contact has alternative client
	{
		client_notify(TranslateT("Need confirmation for sending messages to other clients.\nOpen Facebook website and try to send message to this contact again!"));
		return SEND_MESSAGE_ERROR;
	}
	case 1357007: // Security check (captcha) is required
	{
		std::string imageUrl = utils::text::html_entities_decode(utils::text::slashu_to_utf8(utils::text::source_get_value(&resp.data, 3, "img class=\\\"img\\\"", "src=\\\"", "\\\"")));
		std::string captchaPersistData = utils::text::source_get_value(&resp.data, 3, "\\\"captcha_persist_data\\\"", "value=\\\"", "\\\"");
		parent->debugLogA("Got imageUrl: %s", imageUrl.c_str());
		parent->debugLogA("Got captchaPersistData: %s", captchaPersistData.c_str());
		std::string result;
		if (!parent->RunCaptchaForm(imageUrl, result)) {
			*error_text = Translate("User cancel captcha challenge.");
			return SEND_MESSAGE_CANCEL;
		}
		return send_message(hContact, message_recipient, message_text, error_text, method, captchaPersistData, result);
	}
 
    default: // Other error
		parent->debugLogA(" !!!  Send message error #%d: %s", resp.error_number, resp.error_text);
		return SEND_MESSAGE_ERROR;
 	}
	switch (resp.code)
	{
	case HTTP_CODE_OK:
		handle_success("send_message");
		return SEND_MESSAGE_OK;
	case HTTP_CODE_FAKE_ERROR:
	case HTTP_CODE_FAKE_DISCONNECTED:
	default:
		*error_text = Translate("Timeout when sending message.");
		handle_error("send_message");
		return SEND_MESSAGE_ERROR;
	}
}
bool facebook_client::post_status(status_data *status)
{
	if (status == NULL || (status->text.empty() && status->url.empty()))
		return false;
	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);
	}
	std::string data;
	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=0";
		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));
		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=0";
		std::string form = utils::text::source_get_value(&temp, 2, "
debugLogA("      Got self avatar: %s", this->self_.image_url.c_str());
		parent->CheckAvatarChange(NULL, this->self_.image_url);
		// Get logout hash
		this->logout_hash_ = utils::text::source_get_value2(&resp.data, "/logout.php?h=", "&\"");
		parent->debugLogA("      Got self logout hash: %s", this->logout_hash_.c_str());
		if (this->self_.real_name.empty() || this->self_.image_url.empty() || this->logout_hash_.empty()) {
			parent->debugLogA("!!!!! Empty nick/avatar/hash. Source code:\n%s", resp.data.c_str());
			client_notify(TranslateT("Could not load all required data. Plugin may still work correctly, but you should report this and wait for plugin update."));
		}
		return handle_success("home");
	}
	case HTTP_CODE_FOUND:
		// Work-around for replica_down, f**king hell what's that?
		parent->debugLogA("      REPLICA_DOWN is back in force!");
		return this->home();
	
	default:
		return handle_error("home", FORCE_QUIT);
	}
}
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;
	http::response resp = flap(REQUEST_VISIBILITY, &data);
	
	if (!resp.error_title.empty())
		return handle_error("chat_state");
	return handle_success("chat_state");
}
bool facebook_client::reconnect()
{
	handle_entry("reconnect");
	// Request reconnect
	http::response resp = flap(REQUEST_RECONNECT);
	switch (resp.code)
	{
	case HTTP_CODE_OK:
	{
		this->chat_channel_ = utils::text::source_get_value(&resp.data, 2, "\"user_channel\":\"", "\"");
		parent->debugLogA("      Got self channel: %s", this->chat_channel_.c_str());
				
		this->chat_channel_partition_ = utils::text::source_get_value2(&resp.data, "\"partition\":", ",}");
		parent->debugLogA("      Got self channel partition: %s", this->chat_channel_partition_.c_str());
		
		this->chat_channel_host_ = utils::text::source_get_value(&resp.data, 2, "\"host\":\"", "\"");
		parent->debugLogA("      Got self channel host: %s", this->chat_channel_host_.c_str());
		this->chat_sequence_num_ = utils::text::source_get_value2(&resp.data, "\"seq\":", ",}");
		parent->debugLogA("      Got self sequence number: %s", this->chat_sequence_num_.c_str());
		this->chat_conn_num_ = utils::text::source_get_value2(&resp.data, "\"max_conn\":", ",}");
		parent->debugLogA("      Got self max_conn: %s", this->chat_conn_num_.c_str());
		
		this->chat_sticky_num_ = utils::text::source_get_value(&resp.data, 2, "\"sticky_token\":\"", "\"");
		parent->debugLogA("      Got self sticky_token: %s", this->chat_sticky_num_.c_str());
		//std::string retry_interval = utils::text::source_get_value2(&resp.data, "\"retry_interval\":", ",}");
		//parent->debugLogA("      Got self retry_interval: %s", retry_interval.c_str());
		//std::string visibility = utils::text::source_get_value2(&resp.data, "\"visibility\":", ",}");
		//parent->debugLogA("      Got self visibility: %s", visibility);
		return handle_success("reconnect");
	}
	 
	default:
		return handle_error("reconnect", FORCE_DISCONNECT);
	}
}
bool facebook_client::channel()
{
	handle_entry("channel");
	// Get update
	http::response resp = flap(REQUEST_MESSAGES_RECEIVE);
	if (resp.data.empty()) {
		// Something went wrong
		return handle_error("channel");
	}
	// Load traceId, if present
	std::string traceId = utils::text::source_get_value(&resp.data, 2, "\"tr\":\"", "\"");
	if (!traceId.empty()) {
		this->chat_traceid_ = traceId;
	}
	std::string type = utils::text::source_get_value(&resp.data, 2, "\"t\":\"", "\"");
	if (type == "continue" || type == "heartbeat") {
		// Everything is OK, no new message received
	}
	else if (type == "lb") {
		// Some new stuff (idk how does it work yet)
		this->chat_channel_host_ = utils::text::source_get_value(&resp.data, 2, "\"vip\":\"", "\"");
		parent->debugLogA("      Got self channel host: %s", this->chat_channel_host_.c_str());
		this->chat_sticky_num_ = utils::text::source_get_value2(&resp.data, "\"sticky\":\"", "\"");
		parent->debugLogA("      Got self sticky number: %s", this->chat_sticky_num_.c_str());
	}
	else if (type == "fullReload" || type == "refresh") {
		// Requested reload of page or relogin (due to some settings change, removing this session, etc.)
		parent->debugLogA("! ! ! Requested %s", type.c_str());
		this->chat_sequence_num_ = utils::text::source_get_value2(&resp.data, "\"seq\":", ",}");
		parent->debugLogA("      Got self sequence number: %s", this->chat_sequence_num_.c_str());
		if (type == "refresh") {
			this->chat_reconnect_reason_ = utils::text::source_get_value2(&resp.data, "\"reason\":", ",}");
			parent->debugLogA("      Reconnect reason: %s", this->chat_reconnect_reason_.c_str());
			return this->reconnect();
		}
	}
	else if (!type.empty()) {
		// Something has been received, throw to new thread to process
		std::string* response_data = new std::string(resp.data);
		parent->ForkThread(&FacebookProto::ProcessMessages, response_data);
		// Increment sequence number
		this->chat_sequence_num_ = utils::text::source_get_value2(&resp.data, "\"seq\":", ",}");
		parent->debugLogA("      Got self sequence number: %s", this->chat_sequence_num_.c_str());
	}
	else {
		// No type? This shouldn't happen unless there is a big API change.
		return handle_error("channel");
	}
	// Return
	switch (resp.code)
	{
	case HTTP_CODE_OK:
		return handle_success("channel");
	case HTTP_CODE_GATEWAY_TIMEOUT:
		// Maybe we have same clientid as other connected client, try to generate different one
		this->chat_clientid_ = utils::text::rand_string(8, "0123456789abcdef");
		// Intentionally fall to handle_error() below
	case HTTP_CODE_FAKE_DISCONNECTED:
	case HTTP_CODE_FAKE_ERROR:
	default:
		return handle_error("channel");
	}
}
int facebook_client::send_message(MCONTACT hContact, std::string message_recipient, std::string message_text, std::string *error_text, MessageMethod method, std::string captcha_persist_data, std::string captcha)
{
	ScopedLock s(send_message_lock_);
	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;
	}
	switch (method) {
		case MESSAGE_INBOX:
		{
			parent->debugLogA("    > Sending message through INBOX");
			data += "&action=send";
			data += "&body=" + utils::url::encode(message_text);
			data += "&recipients[0]=" + message_recipient;
			data += "&__user=" + this->self_.user_id;
			data += "&__a=1";
			data += "&fb_dtsg=" + this->dtsg_;
			data += "&phstamp=0";
			resp = flap(REQUEST_MESSAGE_SEND_INBOX, &data);
			break;
		}
		case MESSAGE_MERCURY:
		{
			parent->debugLogA("    > Sending message through CHAT");
			data += "&message_batch[0][action_type]=ma-type:user-generated-message";
			data += "&message_batch[0][thread_id]";
			data += "&message_batch[0][author]=fbid:" + this->self_.user_id;
			data += "&message_batch[0][author_email]";
			data += "&message_batch[0][coordinates]";
			data += "&message_batch[0][timestamp]=" + utils::time::mili_timestamp();
			data += "&message_batch[0][timestamp_absolute]";
			data += "&message_batch[0][timestamp_relative]";
			data += "&message_batch[0][is_unread]=false";
			data += "&message_batch[0][is_cleared]=false";
			data += "&message_batch[0][is_forward]=false";
			data += "&message_batch[0][spoof_warning]=false";
			data += "&message_batch[0][source]=source:chat:web";
			data += "&message_batch[0][source_tags][0]=source:chat";
			data += "&message_batch[0][body]=" + utils::url::encode(message_text);
			data += "&message_batch[0][has_attachment]=false";
			data += "&message_batch[0][html_body]=false";
			data += "&message_batch[0][specific_to_list][0]=fbid:" + message_recipient;
			data += "&message_batch[0][specific_to_list][1]=fbid:" + this->self_.user_id;
			data += "&message_batch[0][status]=0";
			data += "&message_batch[0][message_id]";
			data += "&message_batch[0][client_thread_id]=user:" + message_recipient;
			data += "&client=mercury";
			data += "&fb_dtsg=" + this->dtsg_;
			data += "&__user=" + this->self_.user_id;
			data += "&__a=1";
			data += "&phstamp=0";
			resp = flap(REQUEST_MESSAGE_SEND_CHAT, &data);
			break;
		}
		case MESSAGE_TID:
		{
			parent->debugLogA("    > Sending message through MERCURY (TID)");
			data += "&message_batch[0][action_type]=ma-type:user-generated-message";
			data += "&message_batch[0][thread_id]=" + message_recipient;
			data += "&message_batch[0][author]=fbid:" + this->self_.user_id;
			data += "&message_batch[0][timestamp]=" + utils::time::mili_timestamp();
			data += "&message_batch[0][timestamp_absolute]=";
			data += "&message_batch[0][timestamp_relative]=";
			data += "&message_batch[0][is_unread]=false";
			data += "&message_batch[0][is_cleared]=false";
			data += "&message_batch[0][is_forward]=false";
			data += "&message_batch[0][source]=source:chat:web";
			data += "&message_batch[0][body]=" + utils::url::encode(message_text);
			data += "&message_batch[0][has_attachment]=false";
			data += "&message_batch[0][is_html]=false";
			data += "&message_batch[0][message_id]=";
			data += "&fb_dtsg=" + this->dtsg_;
			data += "&__user=" + this->self_.user_id;
			data += "&phstamp=0";
			resp = flap(REQUEST_MESSAGE_SEND_CHAT, &data);
			break;
		}
		case MESSAGE_ASYNC:
		{
			parent->debugLogA("    > Sending message through ASYNC");
			data += "&action=send";
			data += "&body=" + utils::url::encode(message_text);
			data += "&recipients[0]=" + message_recipient;
			data += "&lsd=";
			data += "&fb_dtsg=" + this->dtsg_;
			resp = flap(REQUEST_ASYNC, &data);
			break;
		}
	}
	
	*error_text = resp.error_text;
	switch (resp.error_number)
	{
  	case 0: // Everything is OK
	{
		// Remember this message id
		std::string mid = utils::text::source_get_value(&resp.data, 2, "\"message_id\":\"", "\"");
		if (mid.empty())
			mid = utils::text::source_get_value(&resp.data, 2, "\"mid\":\"", "\"");
		parent->setString(hContact, FACEBOOK_KEY_MESSAGE_ID, mid.c_str());
		messages_ignore.insert(std::make_pair(mid, 0));
	} break;
    //case 1356002: // You are offline (probably you can't use mercury or some other request when chat is offline)
	case 1356003: // Contact is offline
	{
		MCONTACT hContact = parent->ContactIDToHContact(message_recipient);
		if (hContact != NULL)
  			parent->setWord(hContact, "Status", ID_STATUS_OFFLINE);
		return SEND_MESSAGE_ERROR;
	}
  	case 1356026: // Contact has alternative client
	{
		client_notify(TranslateT("Need confirmation for sending messages to other clients.\nOpen Facebook website and try to send message to this contact again!"));
		return SEND_MESSAGE_ERROR;
	}
	case 1357007: // Security check (captcha) is required
	{
		std::string imageUrl = utils::text::html_entities_decode(utils::text::slashu_to_utf8(utils::text::source_get_value(&resp.data, 3, "img class=\\\"img\\\"", "src=\\\"", "\\\"")));
		std::string captchaPersistData = utils::text::source_get_value(&resp.data, 3, "\\\"captcha_persist_data\\\"", "value=\\\"", "\\\"");
		parent->debugLogA("Got imageUrl: %s", imageUrl.c_str());
		parent->debugLogA("Got captchaPersistData: %s", captchaPersistData.c_str());
		std::string result;
		if (!parent->RunCaptchaForm(imageUrl, result)) {
			*error_text = Translate("User cancel captcha challenge.");
			return SEND_MESSAGE_CANCEL;
		}
		return send_message(hContact, message_recipient, message_text, error_text, method, captchaPersistData, result);
	}
 
    default: // Other error
		parent->debugLogA(" !!!  Send message error #%d: %s", resp.error_number, resp.error_text);
		return SEND_MESSAGE_ERROR;
 	}
	switch (resp.code)
	{
	case HTTP_CODE_OK:
		handle_success("send_message");
		return SEND_MESSAGE_OK;
	case HTTP_CODE_FAKE_ERROR:
	case HTTP_CODE_FAKE_DISCONNECTED:
	default:
		*error_text = Translate("Timeout when sending message.");
		handle_error("send_message");
		return SEND_MESSAGE_ERROR;
	}
}
bool facebook_client::post_status(status_data *status)
{
	if (status == NULL || (status->text.empty() && status->url.empty()))
		return false;
	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);
	}
	std::string data;
	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=0";
		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));
		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=0";
		std::string form = utils::text::source_get_value(&temp, 2, "