From d16d69e7b86095c1493f4a7062751768c31a58fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Robert=20P=C3=B6sel?= <robyer@seznam.cz>
Date: Mon, 19 Oct 2015 20:11:55 +0000
Subject: Omegle: Various improvements * Remove typing weirdness * Fix
 resetting "stranger is typing" on receiving message * Make option "hi
 message" choose randomly from more messages

git-svn-id: http://svn.miranda-ng.org/main/trunk@15571 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
---
 protocols/Omegle/res/omegle.rc         |   11 +-
 protocols/Omegle/src/client.h          |    3 +-
 protocols/Omegle/src/communication.cpp | 1654 ++++++++++++++++----------------
 protocols/Omegle/src/messages.cpp      |  156 ++-
 protocols/Omegle/src/stdafx.h          |    1 +
 protocols/Omegle/src/utils.cpp         |   24 +-
 protocols/Omegle/src/utils.h           |    1 +
 7 files changed, 935 insertions(+), 915 deletions(-)

(limited to 'protocols/Omegle')

diff --git a/protocols/Omegle/res/omegle.rc b/protocols/Omegle/res/omegle.rc
index c8169d10cd..b48b175db7 100644
--- a/protocols/Omegle/res/omegle.rc
+++ b/protocols/Omegle/res/omegle.rc
@@ -71,10 +71,10 @@ BEGIN
     EDITTEXT        IDC_NAME,84,22,79,14,ES_AUTOHSCROLL
     CONTROL         "Meet strangers with common interests (separated by commas):",IDC_MEET_COMMON,
                     "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,39,288,10
-    EDITTEXT        IDC_INTERESTS,14,49,288,20,ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL
-    CONTROL         "Automatically send this message to stranger after connection:",IDC_HI_ENABLED,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,72,288,10
-    EDITTEXT        IDC_HI_MESSAGE,14,82,288,20,ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL
+    EDITTEXT        IDC_INTERESTS,14,49,288,14,ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL
+    CONTROL         "Automatically send one of these messages (each on new line) to stranger after connection:",IDC_HI_ENABLED,
+                    "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,14,65,288,15
+    EDITTEXT        IDC_HI_MESSAGE,14,82,288,20,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
     LTEXT           "This text will be sent when you use ""/asl"" message:",IDC_STATIC,14,105,288,8
     EDITTEXT        IDC_ASL_MESSAGE,14,114,288,20,ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL
     LTEXT           "Last used question (Question mode):",IDC_STATIC,14,136,288,8
@@ -150,8 +150,7 @@ END
 //
 // Generated from the TEXTINCLUDE 3 resource.
 //
-
-
+

 /////////////////////////////////////////////////////////////////////////////
 #endif    // not APSTUDIO_INVOKED
 
diff --git a/protocols/Omegle/src/client.h b/protocols/Omegle/src/client.h
index d3a6bf6856..b33c05350c 100644
--- a/protocols/Omegle/src/client.h
+++ b/protocols/Omegle/src/client.h
@@ -42,7 +42,7 @@ public:
 		send_message_lock_ = NULL;
 		state_ = STATE_INACTIVE;
 
-		old_typing_ = typing_ = spy_mode_ = false;
+		typing_ = spy_mode_ = false;
 
 		error_count_ = 0;
 
@@ -74,7 +74,6 @@ public:
 	// State of client
 	int state_;
 	bool typing_;
-	bool old_typing_;
 	bool spy_mode_;
 
 	// Data storage
diff --git a/protocols/Omegle/src/communication.cpp b/protocols/Omegle/src/communication.cpp
index 9b0ba9f3d5..a869a47391 100644
--- a/protocols/Omegle/src/communication.cpp
+++ b/protocols/Omegle/src/communication.cpp
@@ -1,824 +1,830 @@
-/*
-
-Omegle plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright � 2011-15 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/>.
-*/
-
-#include "stdafx.h"
-
-http::response Omegle_client::flap(const int request_type, std::string *post_data, std::string *get_data)
-{
-	http::response resp;
-
-	// Prepare the request
-	NETLIBHTTPREQUEST nlhr = { sizeof(NETLIBHTTPREQUEST) };
-
-	// Set request URL
-	std::string url = choose_server(request_type) + choose_action(request_type, get_data);
-	nlhr.szUrl = (char*)url.c_str();
-
-	// Set timeout (bigger for channel request)
-	nlhr.timeout = 1000 * ((request_type == OMEGLE_REQUEST_EVENTS) ? 65 : 20);
-
-	// 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);
-
-	// Set flags
-	nlhr.flags = NLHRF_HTTP11;
-
-#ifdef _DEBUG 
-	nlhr.flags |= NLHRF_DUMPASTEXT;
-#else
-	nlhr.flags |= NLHRF_NODUMP;
-#endif	
-
-	// Set persistent connection (or not)
-	switch (request_type)
-	{
-	case OMEGLE_REQUEST_HOME:
-		nlhr.nlc = NULL;
-		break;
-
-	case OMEGLE_REQUEST_EVENTS:
-		nlhr.nlc = hEventsConnection;
-		nlhr.flags |= NLHRF_PERSISTENT;
-		break;
-
-	default:
-		WaitForSingleObject(connection_lock_, INFINITE);
-		nlhr.nlc = hConnection;
-		nlhr.flags |= NLHRF_PERSISTENT;
-		break;
-	}
-
-	parent->debugLogA("@@@@@ Sending request to '%s'", nlhr.szUrl);
-
-	// Send the request	
-	NETLIBHTTPREQUEST *pnlhr = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)handle_, (LPARAM)&nlhr);
-
-	mir_free(nlhr.headers);
-
-	// Remember the persistent connection handle (or not)
-	switch ( request_type )
-	{
-	case OMEGLE_REQUEST_HOME:
-		break;
-
-	case OMEGLE_REQUEST_EVENTS:
-		hEventsConnection = pnlhr ? pnlhr->nlc : NULL;
-		break;
-
-	default:
-		ReleaseMutex(connection_lock_);
-		hConnection = pnlhr ? pnlhr->nlc : NULL;
-		break;
-	}
-
-	// Check and copy response data
-	if (pnlhr != NULL)
-	{
-		parent->debugLogA("@@@@@ Got response with code %d", pnlhr->resultCode);
-		store_headers(&resp, pnlhr->headers, pnlhr->headersCount);
-		resp.code = pnlhr->resultCode;
-		resp.data = pnlhr->pData ? pnlhr->pData : "";
-
-		parent->debugLogA("&&&&& Got response: %s", resp.data.c_str());
-
-		CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)pnlhr);
-	} 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
-	}
-
-	return resp;
-}
-
-bool Omegle_client::handle_entry(const std::string &method )
-{
-	parent->debugLogA("   >> Entering %s()", method.c_str());
-	return true;
-}
-
-bool Omegle_client::handle_success(const std::string &method )
-{
-	parent->debugLogA("   << Quitting %s()", method.c_str());
-	reset_error();
-	return true;
-}
-
-bool Omegle_client::handle_error(const std::string &method, bool force_disconnect )
-{
-	bool result;
-	increment_error();
-	parent->debugLogA("!!!!! %s(): Something with Omegle went wrong", method.c_str());
-
-	if ( force_disconnect )
-		result = false;
-	else if ( error_count_ <= (UINT)db_get_b(NULL,parent->m_szModuleName,OMEGLE_KEY_TIMEOUTS_LIMIT,OMEGLE_TIMEOUTS_LIMIT))
-		result = true;
-	else
-		result = false;
-
-	if ( result == false )
-	{
-		reset_error();
-		parent->UpdateChat(NULL, TranslateT("Connection error."));
-		parent->StopChat(false);
-	}
-
-	return result;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-std::string Omegle_client::get_server( bool not_last )
-{
-	int q = not_last ? 1 : 0;	
-
-	int server = db_get_b(NULL, parent->m_szModuleName, OMEGLE_KEY_SERVER, 0);
-	if (server < 0 || server >= (int)(_countof(servers)-q))
-		server = 0;
-
-	if (server == 0) {
-		srand(::time(NULL));
-		server = (rand() % (_countof(servers)-1-q))+1;
-	}
-
-	return servers[server];
-}
-
-std::string Omegle_client::get_language()
-{
-	int language = db_get_b(NULL, parent->m_szModuleName, OMEGLE_KEY_LANGUAGE, 0);
-	if (language < 0 || language >= (_countof(languages)))
-		language = 0;
-
-	return language > 0 ? languages[language].id : "en";
-}
-
-std::string Omegle_client::choose_server(int request_type)
-{
-	switch ( request_type )
-	{
-	case OMEGLE_REQUEST_HOME:
-		return OMEGLE_SERVER_REGULAR;
-	
-/*	case OMEGLE_REQUEST_START:
-	case OMEGLE_REQUEST_STOP:
-	case OMEGLE_REQUEST_SEND:
-	case OMEGLE_REQUEST_EVENTS:
-	case OMEGLE_REQUEST_TYPING_START:
-	case OMEGLE_REQUEST_TYPING_STOP:
-	case OMEGLE_REQUEST_RECAPTCHA:
-	case OMEGLE_REQUEST_COUNT:
-*/	default:
-		std::string server = OMEGLE_SERVER_CHAT;
-		utils::text::replace_first( &server, "%s", this->server_ );
-		return server;
-	}
-}
-
-std::string Omegle_client::choose_action(int request_type, std::string* get_data)
-{
-	switch ( request_type )
-	{
-	case OMEGLE_REQUEST_START:
-		{
-			std::string action = "/start?rcs=1&spid=&lang=";
-			action += get_language();
-			if (get_data != NULL)
-				action += (*get_data);
-
-			return action;
-		}
-
-	case OMEGLE_REQUEST_STOP:
-		return "/disconnect";
-
-	case OMEGLE_REQUEST_SEND:
-		return "/send";
-
-	case OMEGLE_REQUEST_EVENTS:
-		return "/events";
-
-	case OMEGLE_REQUEST_TYPING_START:
-		return "/typing";
-
-	case OMEGLE_REQUEST_TYPING_STOP:
-		return "/stoppedtyping";
-
-	case OMEGLE_REQUEST_RECAPTCHA:
-		return "/recaptcha";
-
-	case OMEGLE_REQUEST_COUNT:
-		return "/count";
-
-	// "/stoplookingforcommonlikes"
-
-/*	case OMEGLE_REQUEST_HOME:
-*/	default:
-		return "/";
-	}
-}
-
-
-NETLIBHTTPHEADER* Omegle_client::get_request_headers( int request_type, int* headers_count )
-{
-	if (request_type == REQUEST_POST)
-		*headers_count = 4;
-	else
-		*headers_count = 3;
-
-	NETLIBHTTPHEADER *headers = (NETLIBHTTPHEADER*)mir_calloc(sizeof(NETLIBHTTPHEADER)*(*headers_count));
-
-	if (request_type == REQUEST_POST) {
-		headers[3].szName = "Content-Type";
-		headers[3].szValue = "application/x-www-form-urlencoded; charset=utf-8";
-	}
-
-	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;
-}
-
-void Omegle_client::store_headers( http::response* resp, NETLIBHTTPHEADER* headers, int headersCount )
-{
-	for ( size_t i = 0; i < (size_t)headersCount; i++ )
-	{
-		std::string header_name = headers[i].szName;
-		std::string header_value = headers[i].szValue;
-
-		// TODO RM: (un)comment
-		//parent->debugLogA("----- Got header '%s': %s", header_name.c_str(), header_value.c_str());
-		resp->headers[header_name] = header_value;
-	}
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-bool Omegle_client::start()
-{
-	handle_entry( "start" );
-
-	this->server_ = get_server();
-	//parent->debugLogA("Chosing server %s", this->server_.c_str());
-	//std::string log = Translate("Chosing server: ") + this->server_;
-	//parent->UpdateChat(NULL, log.c_str());
-
-	std::string data;
-
-	if (this->spy_mode_) {
-		//// get last server from list, which is for spy mode
-		//this->server_ = servers[_countof(servers)-1];
-
-		if (this->question_.empty()) {
-			data = "&wantsspy=1";
-		} else {
-			data = "&ask=" + utils::url::encode(this->question_);
-			data += "&cansavequestion=";
-			data += db_get_b(NULL, parent->m_szModuleName, OMEGLE_KEY_REUSE_QUESTION, 0) ? "1" : "0";
-		}
-	}
-	else if ( db_get_b(NULL, parent->m_szModuleName, OMEGLE_KEY_MEET_COMMON, 0))
-	{
-		DBVARIANT dbv;
-		if (!db_get_utf(NULL, parent->m_szModuleName, OMEGLE_KEY_INTERESTS, &dbv))
-		{
-			std::string topics = dbv.pszVal;
-			std::string topic;
-		
-			db_free(&dbv);
-
-			std::string::size_type pos = 0;
-			std::string::size_type pos2 = 0;
-			while ((pos2 = topics.find(",", pos)) != std::string::npos) {
-				topic = topics.substr(pos, pos2 - pos);
-				topic = utils::text::trim(topic);
-
-				if (!topic.empty()) {
-					if (pos > 0)
-						data += ",";
-
-					data += "\"" + topic + "\"";
-				}
-
-				pos = pos2 + 1;
-			}
-		
-			topic = topics.substr(pos);
-			topic = utils::text::trim(topic);
-			if (!topic.empty()) {			
-				if (pos > 0)
-					data += ",";
-				data += "\"" + topic + "\"";			
-			}
-
-			parent->debugLogA("TOPICS: %s", data.c_str());
-
-			if (!data.empty()) {
-				data = "[" + data + "]";
-				data = "&topics=" + utils::url::encode(data);
-			}
-
-			//// get any server but last, which is for spy mode
-			//this->server_ = get_server(true);
-		}
-	}
-
-	if (db_get_b(NULL, parent->m_szModuleName, OMEGLE_KEY_SERVER_INFO, 0))
-	{
-		std::string count = get_page( OMEGLE_REQUEST_COUNT );
-		if (!count.empty()) {
-			char str[255];
-			mir_snprintf(str, Translate("Connected to server %s. There are %s users online now."), server_.c_str(), count.c_str());
-
-			TCHAR *msg = mir_a2t(str);
-			parent->UpdateChat(NULL, msg);
-			mir_free(msg);
-		}
-	} else {
-		char str[255];
-		mir_snprintf(str, Translate("Connected to server %s."), server_.c_str());
-
-		TCHAR *msg = mir_a2t(str);
-		parent->UpdateChat(NULL, msg);
-		mir_free(msg);
-	}
-
-	// Send validation
-	http::response resp = flap( OMEGLE_REQUEST_START, NULL, &data );
-
-	switch ( resp.code )
-	{
-	case HTTP_CODE_FAKE_DISCONNECTED:
-	{
-		// If is is only timeout error, try login once more
-		if ( handle_error( "start" ))
-			return start();
-		else
-			return false;
-	}
-
-	case HTTP_CODE_OK:
-	{ 
-		if (!resp.data.empty()) {
-			this->chat_id_ = resp.data.substr(1,resp.data.length()-2);
-			this->state_ = STATE_WAITING;
-
-			return handle_success( "start" );
-		} else {
-			return handle_error( "start", FORCE_DISCONNECT );
-		}
-	}
-
-	default:
-		return handle_error( "start", FORCE_DISCONNECT );
-	}
-}
-
-bool Omegle_client::stop()
-{
-	if ( parent->isOffline())
-		return true;
-
-	handle_entry( "stop" );
-
-	std::string data = "id=" + this->chat_id_;
-
-	http::response resp = flap( OMEGLE_REQUEST_STOP, &data );
-
-	if (hConnection)
-		Netlib_CloseHandle(hConnection);
-	hConnection = NULL;
-
-	if (hEventsConnection)
-		Netlib_CloseHandle(hEventsConnection);
-	hEventsConnection = NULL;
-
-	if (resp.data == "win") {
-		return handle_success( "stop" );
-	} else {
-		return handle_error( "stop" );
-	}
-
-/*	switch ( resp.code )
-	{
-	case HTTP_CODE_OK:
-	case HTTP_CODE_FOUND:
-
-	default:
-		
-	}*/
-}
-
-bool Omegle_client::events()
-{
-	handle_entry( "events" );
-
-	std::string data = "id=" + this->chat_id_;
-
-	// Get update
-	http::response resp = flap( OMEGLE_REQUEST_EVENTS, &data );
-
-	// Return
-	switch ( resp.code )
-	{
-	case HTTP_CODE_OK:
-	{
-		if ( resp.data == "null" ) {
-			// Everything is OK, no new message received -- OR it is a problem
-			// TODO: if we are waiting for Stranger with common likes, then we should try standard Stranger if this takes too long
-			return handle_error( "events" );
-		} else if ( resp.data == "fail" ) {
-			// Something went wrong
-			return handle_error( "events" );
-		}
-		
-		std::string::size_type pos = 0;
-		bool newStranger = false;
-		bool waiting = false;
-		
-		if ( resp.data.find( "[\"waiting\"]" ) != std::string::npos ) {
-			// We are just waiting for new Stranger
-			waiting = true;
-		}
-
-		/*if ( (pos = resp.data.find( "[\"count\"," )) != std::string::npos ) {
-			// We got info about count of connected people there
-			pos += 9;
-
-			std::string count = utils::text::trim( resp.data.substr(pos, resp.data.find("]", pos) - pos));
-
-			char str[255];
-			mir_snprintf(str, Translate("On whole Omegle are %s strangers online now."), count.c_str());
-			
-			TCHAR *msg = mir_a2t_cp(str,CP_UTF8);
-			parent->UpdateChat(NULL, msg);
-			mir_free(msg);
-		}*/
-
-		if ( (pos = resp.data.find( "[\"serverMessage\"," )) != std::string::npos ) {
-			// We got server message
-			pos += 18;
-
-			std::string message = utils::text::trim( resp.data.substr(pos, resp.data.find("\"]", pos) - pos));
-			TCHAR *tstr = Langpack_PcharToTchar(message.c_str());
-			parent->UpdateChat(NULL, tstr);
-			mir_free(tstr);
-		}
-
-		if ( resp.data.find( "[\"connected\"]" ) != std::string::npos ) {
-			// Stranger connected
-			if (this->spy_mode_ && !this->question_.empty()) {
-				parent->AddChatContact(TranslateT("Stranger 1"));
-				parent->AddChatContact(TranslateT("Stranger 2"));
-				this->state_ = STATE_SPY;
-			} else {			
-				parent->AddChatContact(TranslateT("Stranger"));
-				this->state_ = STATE_ACTIVE;
-			}
-
-			newStranger = true;
-			waiting = false;
-		}
-
-		if ( (pos = resp.data.find( "[\"commonLikes\"," )) != std::string::npos ) {
-			pos += 17;
-			std::string like = resp.data.substr(pos, resp.data.find("\"]", pos) - pos);
-			utils::text::replace_all(&like, "\", \"", ", ");
-
-			parent->debugLogA("Got common likes: '%s'", like.c_str());
-
-			like = Translate("You and the Stranger both like: ") + like;
-
-			TCHAR *msg = mir_a2t(like.c_str());
-			parent->SetTopic(msg);
-			mir_free(msg);
-		}
-
-		if ( (pos = resp.data.find( "[\"question\"," )) != std::string::npos ) {
-			pos += 13;
-
-			std::string question = utils::text::trim(
-				utils::text::special_expressions_decode(
-					utils::text::slashu_to_utf8(
-						resp.data.substr(pos, resp.data.find("\"]", pos) - pos)	)) );
-
-			TCHAR *msg = mir_a2t_cp(question.c_str(),CP_UTF8);
-			parent->SetTopic(msg);
-			mir_free(msg);
-		}
-
-		if ( resp.data.find( "[\"typing\"]" ) != std::string::npos
-			|| resp.data.find( "[\"spyTyping\"," ) != std::string::npos )
-		{
-			// Stranger is typing, not supported by chat module yet
-			SkinPlaySound( "StrangerTyp" );
-			
-			
-			StatusTextData st = { 0 };
-			st.cbSize = sizeof(st);
-			// st.hIcon = IcoLib_GetIconByHandle(GetIconHandle("typing_on")); // TODO: typing icon
-
-			mir_sntprintf(st.tszText, TranslateT("%s is typing."), TranslateT("Stranger"));
-
-			CallService(MS_MSG_SETSTATUSTEXT, (WPARAM)parent->GetChatHandle(), (LPARAM)&st);
-		}
-
-		if ( resp.data.find( "[\"stoppedTyping\"]" ) != std::string::npos
-			|| resp.data.find( "[\"spyStoppedTyping\"," ) != std::string::npos )
-		{
-			// Stranger stopped typing, not supported by chat module yet
-			SkinPlaySound( "StrangerTypStop" );
-			
-			StatusTextData st = { 0 };
-			st.cbSize = sizeof(st);
-			// st.hIcon = IcoLib_GetIconByHandle(GetIconHandle("typing_off")); // TODO: typing icon
-
-			mir_sntprintf(st.tszText, TranslateT("%s stopped typing."), TranslateT("Stranger"));
-
-			CallService(MS_MSG_SETSTATUSTEXT, (WPARAM)parent->GetChatHandle(), (LPARAM)&st);
-		}
-
-		pos = 0;
-		while ( (pos = resp.data.find( "[\"gotMessage\",", pos )) != std::string::npos ) {
-			pos += 15;
-
-			std::string message = utils::text::trim(
-				utils::text::special_expressions_decode(
-					utils::text::slashu_to_utf8(
-						resp.data.substr(pos, resp.data.find("\"]", pos) - pos)	)) );
-			
-			if (state_ == STATE_ACTIVE) {
-				TCHAR *msg = mir_a2t_cp(message.c_str(),CP_UTF8);
-				parent->UpdateChat(TranslateT("Stranger"), msg);
-				mir_free(msg);
-
-				CallService(MS_MSG_SETSTATUSTEXT, (WPARAM)parent->GetChatHandle(), 0);
-			}
-		}
-
-		pos = 0;
-		while ( (pos = resp.data.find( "[\"spyMessage\",", pos )) != std::string::npos ) {
-			pos += 15;
-
-			std::string message = resp.data.substr(pos, resp.data.find("\"]", pos) - pos);
-			
-			if (state_ == STATE_SPY) {
-				std::string stranger = message.substr(0, message.find("\""));
-				message = message.substr(stranger.length() + 4);
-
-				message = utils::text::trim(
-							utils::text::special_expressions_decode(
-								utils::text::slashu_to_utf8( message )) );
-				
-				stranger = Translate(stranger.c_str());
-				
-				TCHAR *str = mir_a2t_cp(stranger.c_str(), CP_UTF8);				
-				TCHAR *msg = mir_a2t_cp(message.c_str(), CP_UTF8);
-
-				parent->UpdateChat(str, msg);
-
-				mir_free(msg);
-				mir_free(str);
-			}
-		}
-
-		if ( resp.data.find( "[\"strangerDisconnected\"]" ) != std::string::npos ) {
-			// Stranger disconnected
-			if (db_get_b(NULL, parent->m_szModuleName, OMEGLE_KEY_DONT_STOP, 0))
-			{
-				SkinPlaySound( "StrangerChange" );
-				parent->NewChat();
-			}
-			else			
-				parent->StopChat(false);
-		}
-
-		if ( (pos = resp.data.find( "[\"spyDisconnected\"," )) != std::string::npos ) {
-			pos += 20;
-
-			std::string stranger = utils::text::trim(
-				utils::text::special_expressions_decode(
-					utils::text::slashu_to_utf8(
-						resp.data.substr(pos, resp.data.find("\"]", pos) - pos)	)) );
-
-			char str[255];
-			mir_snprintf(str, Translate("%s disconnected."), Translate(stranger.c_str()));
-			
-			TCHAR *msg = mir_a2t(str);
-			parent->UpdateChat(NULL, msg);
-			mir_free(msg);
-
-			// Stranger disconnected
-			if (db_get_b(NULL, parent->m_szModuleName, OMEGLE_KEY_DONT_STOP, 0))
-			{
-				SkinPlaySound( "StrangerChange" );
-				parent->NewChat();
-			}
-			else
-				parent->StopChat(false);
-		}
-
-		if ( resp.data.find( "[\"recaptchaRequired\"" ) != std::string::npos ) {
-			// Nothing to do with recaptcha
-			parent->UpdateChat(NULL, TranslateT("Recaptcha is required.\nOpen http://omegle.com , solve Recaptcha and try again."));
-			parent->StopChat(false);
-		}
-
-		if ( resp.data.find( "[\"recaptchaRejected\"]" ) != std::string::npos ) {
-			// Nothing to do with recaptcha
-			parent->StopChat(false);
-		}
-
-		if ( (pos = resp.data.find( "[\"error\"," )) != std::string::npos ) {
-			pos += 10;
-
-			std::string error = utils::text::trim(
-				utils::text::special_expressions_decode(
-					utils::text::slashu_to_utf8(
-						resp.data.substr(pos, resp.data.find("\"]", pos) - pos)	)) );
-
-			error = Translate("Error: ") + error;
-
-			TCHAR *msg = mir_a2t(error.c_str());
-			parent->UpdateChat(NULL, msg);
-			mir_free(msg);
-		}
-				
-		if (newStranger && state_ != STATE_SPY) {
-			// We got new stranger in this event, lets say him "Hi message" if enabled			
-			if ( db_get_b( NULL, parent->m_szModuleName, OMEGLE_KEY_HI_ENABLED, 0 )) {
-				DBVARIANT dbv;
-				if ( !db_get_utf( NULL, parent->m_szModuleName, OMEGLE_KEY_HI, &dbv )) {
-					std::string *message = new std::string(dbv.pszVal);
-					db_free(&dbv);
-	
-					parent->debugLogA("**Chat - saying Hi! message");
-					parent->ForkThread(&OmegleProto::SendMsgWorker, message);
-				}
-				else parent->debugLogA("**Chat - Hi message is enabled but not used");
-			}
-		}
-
-		if (waiting) {
-			// If we are only waiting in this event...
-			parent->UpdateChat(NULL, TranslateT("We are still waiting..."));
-		}
-
-		return handle_success( "events" );
-	}
-
-	case HTTP_CODE_FAKE_DISCONNECTED:
-		// timeout
-		return handle_success( "events" );
-
-	case HTTP_CODE_FAKE_ERROR:
-	default:
-		return handle_error( "events" );
-	}
-}
-
-bool Omegle_client::send_message(const std::string &message_text )
-{
-	handle_entry( "send_message" );
-
-	std::string data = "msg=" + utils::url::encode( message_text );
-	data += "&id=" + this->chat_id_;
-
-	http::response resp = flap( OMEGLE_REQUEST_SEND, &data );
-
-	switch ( resp.code )
-	{
-	case HTTP_CODE_OK:
-		if (resp.data == "win") {
-			return handle_success( "send_message" );
-		}
-
-	case HTTP_CODE_FAKE_ERROR:
-	case HTTP_CODE_FAKE_DISCONNECTED:
-	default:
-		return handle_error( "send_message" );
-	}
-}
-
-bool Omegle_client::typing_start()
-{
-	handle_entry( "typing_start" );
-
-	std::string data = "id=" + this->chat_id_;
-
-	http::response resp = flap( OMEGLE_REQUEST_TYPING_START, &data );
-
-	switch ( resp.code )
-	{
-	case HTTP_CODE_OK:
-		if (resp.data == "win") {
-			return handle_success( "typing_start" );
-		}
-
-	case HTTP_CODE_FAKE_ERROR:
-	case HTTP_CODE_FAKE_DISCONNECTED:
-	default:
-		return handle_error( "typing_start" );
-	}
-}
-
-bool Omegle_client::typing_stop()
-{
-	handle_entry( "typing_stop" );
-
-	std::string data = "id=" + this->chat_id_;
-
-	http::response resp = flap( OMEGLE_REQUEST_TYPING_STOP, &data );
-
-	switch ( resp.code )
-	{
-	case HTTP_CODE_OK:
-		if (resp.data == "win") {
-			return handle_success( "typing_stop" );
-		}
-
-	case HTTP_CODE_FAKE_ERROR:
-	case HTTP_CODE_FAKE_DISCONNECTED:
-	default:
-		return handle_error( "typing_stop" );
-	}
-}
-
-bool Omegle_client::recaptcha()
-{
-	// TODO: Implement!
-
-	handle_entry( "recaptcha" );
-
-	// data:{id:this.clientID,challenge:b,response:a}}
-	//std::string data = "?id=...&challenge= ..., &response= ...";
-
-	http::response resp = flap( OMEGLE_REQUEST_RECAPTCHA );
-
-	switch ( resp.code )
-	{
-	case HTTP_CODE_OK:
-/*		if (resp.data == "win") {
-			return handle_success( "typing_start" );
-		}*/
-
-	case HTTP_CODE_FAKE_ERROR:
-	case HTTP_CODE_FAKE_DISCONNECTED:
-	default:
-		return handle_error( "typing_start" );
-	}
-}
-
-std::string Omegle_client::get_page(const int request_type)
-{
-	handle_entry("get_page");
-
-	http::response resp = flap(request_type);
-
-	switch ( resp.code )
-	{
-	case HTTP_CODE_OK:
-		handle_success("get_page");
-		break;
-
-	case HTTP_CODE_FAKE_ERROR:
-	case HTTP_CODE_FAKE_DISCONNECTED:
-	default:
-		handle_error("get_page");
-	}
-
-	return resp.data;
-}
+/*
+
+Omegle plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright � 2011-15 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/>.
+*/
+
+#include "stdafx.h"
+
+http::response Omegle_client::flap(const int request_type, std::string *post_data, std::string *get_data)
+{
+	http::response resp;
+
+	// Prepare the request
+	NETLIBHTTPREQUEST nlhr = { sizeof(NETLIBHTTPREQUEST) };
+
+	// Set request URL
+	std::string url = choose_server(request_type) + choose_action(request_type, get_data);
+	nlhr.szUrl = (char*)url.c_str();
+
+	// Set timeout (bigger for channel request)
+	nlhr.timeout = 1000 * ((request_type == OMEGLE_REQUEST_EVENTS) ? 65 : 20);
+
+	// 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);
+
+	// Set flags
+	nlhr.flags = NLHRF_HTTP11;
+
+#ifdef _DEBUG 
+	nlhr.flags |= NLHRF_DUMPASTEXT;
+#else
+	nlhr.flags |= NLHRF_NODUMP;
+#endif	
+
+	// Set persistent connection (or not)
+	switch (request_type)
+	{
+	case OMEGLE_REQUEST_HOME:
+		nlhr.nlc = NULL;
+		break;
+
+	case OMEGLE_REQUEST_EVENTS:
+		nlhr.nlc = hEventsConnection;
+		nlhr.flags |= NLHRF_PERSISTENT;
+		break;
+
+	default:
+		WaitForSingleObject(connection_lock_, INFINITE);
+		nlhr.nlc = hConnection;
+		nlhr.flags |= NLHRF_PERSISTENT;
+		break;
+	}
+
+	parent->debugLogA("@@@@@ Sending request to '%s'", nlhr.szUrl);
+
+	// Send the request	
+	NETLIBHTTPREQUEST *pnlhr = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)handle_, (LPARAM)&nlhr);
+
+	mir_free(nlhr.headers);
+
+	// Remember the persistent connection handle (or not)
+	switch ( request_type )
+	{
+	case OMEGLE_REQUEST_HOME:
+		break;
+
+	case OMEGLE_REQUEST_EVENTS:
+		hEventsConnection = pnlhr ? pnlhr->nlc : NULL;
+		break;
+
+	default:
+		ReleaseMutex(connection_lock_);
+		hConnection = pnlhr ? pnlhr->nlc : NULL;
+		break;
+	}
+
+	// Check and copy response data
+	if (pnlhr != NULL)
+	{
+		parent->debugLogA("@@@@@ Got response with code %d", pnlhr->resultCode);
+		store_headers(&resp, pnlhr->headers, pnlhr->headersCount);
+		resp.code = pnlhr->resultCode;
+		resp.data = pnlhr->pData ? pnlhr->pData : "";
+
+		parent->debugLogA("&&&&& Got response: %s", resp.data.c_str());
+
+		CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)pnlhr);
+	} 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
+	}
+
+	return resp;
+}
+
+bool Omegle_client::handle_entry(const std::string &method )
+{
+	parent->debugLogA("   >> Entering %s()", method.c_str());
+	return true;
+}
+
+bool Omegle_client::handle_success(const std::string &method )
+{
+	parent->debugLogA("   << Quitting %s()", method.c_str());
+	reset_error();
+	return true;
+}
+
+bool Omegle_client::handle_error(const std::string &method, bool force_disconnect )
+{
+	bool result;
+	increment_error();
+	parent->debugLogA("!!!!! %s(): Something with Omegle went wrong", method.c_str());
+
+	if ( force_disconnect )
+		result = false;
+	else if ( error_count_ <= (UINT)db_get_b(NULL,parent->m_szModuleName,OMEGLE_KEY_TIMEOUTS_LIMIT,OMEGLE_TIMEOUTS_LIMIT))
+		result = true;
+	else
+		result = false;
+
+	if ( result == false )
+	{
+		reset_error();
+		parent->UpdateChat(NULL, TranslateT("Connection error."));
+		parent->StopChat(false);
+	}
+
+	return result;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+std::string Omegle_client::get_server( bool not_last )
+{
+	int q = not_last ? 1 : 0;	
+
+	int server = db_get_b(NULL, parent->m_szModuleName, OMEGLE_KEY_SERVER, 0);
+	if (server < 0 || server >= (int)(_countof(servers)-q))
+		server = 0;
+
+	if (server == 0) {
+		srand(::time(NULL));
+		server = (rand() % (_countof(servers)-1-q))+1;
+	}
+
+	return servers[server];
+}
+
+std::string Omegle_client::get_language()
+{
+	int language = db_get_b(NULL, parent->m_szModuleName, OMEGLE_KEY_LANGUAGE, 0);
+	if (language < 0 || language >= (_countof(languages)))
+		language = 0;
+
+	return language > 0 ? languages[language].id : "en";
+}
+
+std::string Omegle_client::choose_server(int request_type)
+{
+	switch ( request_type )
+	{
+	case OMEGLE_REQUEST_HOME:
+		return OMEGLE_SERVER_REGULAR;
+	
+/*	case OMEGLE_REQUEST_START:
+	case OMEGLE_REQUEST_STOP:
+	case OMEGLE_REQUEST_SEND:
+	case OMEGLE_REQUEST_EVENTS:
+	case OMEGLE_REQUEST_TYPING_START:
+	case OMEGLE_REQUEST_TYPING_STOP:
+	case OMEGLE_REQUEST_RECAPTCHA:
+	case OMEGLE_REQUEST_COUNT:
+*/	default:
+		std::string server = OMEGLE_SERVER_CHAT;
+		utils::text::replace_first( &server, "%s", this->server_ );
+		return server;
+	}
+}
+
+std::string Omegle_client::choose_action(int request_type, std::string* get_data)
+{
+	switch ( request_type )
+	{
+	case OMEGLE_REQUEST_START:
+		{
+			std::string action = "/start?rcs=1&spid=&lang=";
+			action += get_language();
+			if (get_data != NULL)
+				action += (*get_data);
+
+			return action;
+		}
+
+	case OMEGLE_REQUEST_STOP:
+		return "/disconnect";
+
+	case OMEGLE_REQUEST_SEND:
+		return "/send";
+
+	case OMEGLE_REQUEST_EVENTS:
+		return "/events";
+
+	case OMEGLE_REQUEST_TYPING_START:
+		return "/typing";
+
+	case OMEGLE_REQUEST_TYPING_STOP:
+		return "/stoppedtyping";
+
+	case OMEGLE_REQUEST_RECAPTCHA:
+		return "/recaptcha";
+
+	case OMEGLE_REQUEST_COUNT:
+		return "/count";
+
+	// "/stoplookingforcommonlikes"
+
+/*	case OMEGLE_REQUEST_HOME:
+*/	default:
+		return "/";
+	}
+}
+
+
+NETLIBHTTPHEADER* Omegle_client::get_request_headers( int request_type, int* headers_count )
+{
+	if (request_type == REQUEST_POST)
+		*headers_count = 4;
+	else
+		*headers_count = 3;
+
+	NETLIBHTTPHEADER *headers = (NETLIBHTTPHEADER*)mir_calloc(sizeof(NETLIBHTTPHEADER)*(*headers_count));
+
+	if (request_type == REQUEST_POST) {
+		headers[3].szName = "Content-Type";
+		headers[3].szValue = "application/x-www-form-urlencoded; charset=utf-8";
+	}
+
+	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;
+}
+
+void Omegle_client::store_headers( http::response* resp, NETLIBHTTPHEADER* headers, int headersCount )
+{
+	for ( size_t i = 0; i < (size_t)headersCount; i++ )
+	{
+		std::string header_name = headers[i].szName;
+		std::string header_value = headers[i].szValue;
+
+		// TODO RM: (un)comment
+		//parent->debugLogA("----- Got header '%s': %s", header_name.c_str(), header_value.c_str());
+		resp->headers[header_name] = header_value;
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool Omegle_client::start()
+{
+	handle_entry( "start" );
+
+	this->server_ = get_server();
+	//parent->debugLogA("Chosing server %s", this->server_.c_str());
+	//std::string log = Translate("Chosing server: ") + this->server_;
+	//parent->UpdateChat(NULL, log.c_str());
+
+	std::string data;
+
+	if (this->spy_mode_) {
+		//// get last server from list, which is for spy mode
+		//this->server_ = servers[_countof(servers)-1];
+
+		if (this->question_.empty()) {
+			data = "&wantsspy=1";
+		} else {
+			data = "&ask=" + utils::url::encode(this->question_);
+			data += "&cansavequestion=";
+			data += db_get_b(NULL, parent->m_szModuleName, OMEGLE_KEY_REUSE_QUESTION, 0) ? "1" : "0";
+		}
+	}
+	else if ( db_get_b(NULL, parent->m_szModuleName, OMEGLE_KEY_MEET_COMMON, 0))
+	{
+		DBVARIANT dbv;
+		if (!db_get_utf(NULL, parent->m_szModuleName, OMEGLE_KEY_INTERESTS, &dbv))
+		{
+			std::string topics = dbv.pszVal;
+			std::string topic;
+		
+			db_free(&dbv);
+
+			std::string::size_type pos = 0;
+			std::string::size_type pos2 = 0;
+			while ((pos2 = topics.find(",", pos)) != std::string::npos) {
+				topic = topics.substr(pos, pos2 - pos);
+				topic = utils::text::trim(topic);
+
+				if (!topic.empty()) {
+					if (pos > 0)
+						data += ",";
+
+					data += "\"" + topic + "\"";
+				}
+
+				pos = pos2 + 1;
+			}
+		
+			topic = topics.substr(pos);
+			topic = utils::text::trim(topic);
+			if (!topic.empty()) {			
+				if (pos > 0)
+					data += ",";
+				data += "\"" + topic + "\"";			
+			}
+
+			parent->debugLogA("TOPICS: %s", data.c_str());
+
+			if (!data.empty()) {
+				data = "[" + data + "]";
+				data = "&topics=" + utils::url::encode(data);
+			}
+
+			//// get any server but last, which is for spy mode
+			//this->server_ = get_server(true);
+		}
+	}
+
+	if (db_get_b(NULL, parent->m_szModuleName, OMEGLE_KEY_SERVER_INFO, 0))
+	{
+		std::string count = get_page( OMEGLE_REQUEST_COUNT );
+		if (!count.empty()) {
+			char str[255];
+			mir_snprintf(str, Translate("Connected to server %s. There are %s users online now."), server_.c_str(), count.c_str());
+
+			TCHAR *msg = mir_a2t(str);
+			parent->UpdateChat(NULL, msg);
+			mir_free(msg);
+		}
+	} else {
+		char str[255];
+		mir_snprintf(str, Translate("Connected to server %s."), server_.c_str());
+
+		TCHAR *msg = mir_a2t(str);
+		parent->UpdateChat(NULL, msg);
+		mir_free(msg);
+	}
+
+	// Send validation
+	http::response resp = flap( OMEGLE_REQUEST_START, NULL, &data );
+
+	switch ( resp.code )
+	{
+	case HTTP_CODE_FAKE_DISCONNECTED:
+	{
+		// If is is only timeout error, try login once more
+		if ( handle_error( "start" ))
+			return start();
+		else
+			return false;
+	}
+
+	case HTTP_CODE_OK:
+	{ 
+		if (!resp.data.empty()) {
+			this->chat_id_ = resp.data.substr(1,resp.data.length()-2);
+			this->state_ = STATE_WAITING;
+
+			return handle_success( "start" );
+		} else {
+			return handle_error( "start", FORCE_DISCONNECT );
+		}
+	}
+
+	default:
+		return handle_error( "start", FORCE_DISCONNECT );
+	}
+}
+
+bool Omegle_client::stop()
+{
+	if ( parent->isOffline())
+		return true;
+
+	handle_entry( "stop" );
+
+	std::string data = "id=" + this->chat_id_;
+
+	http::response resp = flap( OMEGLE_REQUEST_STOP, &data );
+
+	if (hConnection)
+		Netlib_CloseHandle(hConnection);
+	hConnection = NULL;
+
+	if (hEventsConnection)
+		Netlib_CloseHandle(hEventsConnection);
+	hEventsConnection = NULL;
+
+	if (resp.data == "win") {
+		return handle_success( "stop" );
+	} else {
+		return handle_error( "stop" );
+	}
+
+/*	switch ( resp.code )
+	{
+	case HTTP_CODE_OK:
+	case HTTP_CODE_FOUND:
+
+	default:
+		
+	}*/
+}
+
+bool Omegle_client::events()
+{
+	handle_entry( "events" );
+
+	std::string data = "id=" + this->chat_id_;
+
+	// Get update
+	http::response resp = flap( OMEGLE_REQUEST_EVENTS, &data );
+
+	// Return
+	switch ( resp.code )
+	{
+	case HTTP_CODE_OK:
+	{
+		if ( resp.data == "null" ) {
+			// Everything is OK, no new message received -- OR it is a problem
+			// TODO: if we are waiting for Stranger with common likes, then we should try standard Stranger if this takes too long
+			return handle_error( "events" );
+		} else if ( resp.data == "fail" ) {
+			// Something went wrong
+			return handle_error( "events" );
+		}
+		
+		std::string::size_type pos = 0;
+		bool newStranger = false;
+		bool waiting = false;
+		
+		if ( resp.data.find( "[\"waiting\"]" ) != std::string::npos ) {
+			// We are just waiting for new Stranger
+			waiting = true;
+		}
+
+		/*if ( (pos = resp.data.find( "[\"count\"," )) != std::string::npos ) {
+			// We got info about count of connected people there
+			pos += 9;
+
+			std::string count = utils::text::trim( resp.data.substr(pos, resp.data.find("]", pos) - pos));
+
+			char str[255];
+			mir_snprintf(str, Translate("On whole Omegle are %s strangers online now."), count.c_str());
+			
+			TCHAR *msg = mir_a2t_cp(str,CP_UTF8);
+			parent->UpdateChat(NULL, msg);
+			mir_free(msg);
+		}*/
+
+		if ( (pos = resp.data.find( "[\"serverMessage\"," )) != std::string::npos ) {
+			// We got server message
+			pos += 18;
+
+			std::string message = utils::text::trim( resp.data.substr(pos, resp.data.find("\"]", pos) - pos));
+			TCHAR *tstr = Langpack_PcharToTchar(message.c_str());
+			parent->UpdateChat(NULL, tstr);
+			mir_free(tstr);
+		}
+
+		if ( resp.data.find( "[\"connected\"]" ) != std::string::npos ) {
+			// Stranger connected
+			if (this->spy_mode_ && !this->question_.empty()) {
+				parent->AddChatContact(TranslateT("Stranger 1"));
+				parent->AddChatContact(TranslateT("Stranger 2"));
+				this->state_ = STATE_SPY;
+			} else {			
+				parent->AddChatContact(TranslateT("Stranger"));
+				this->state_ = STATE_ACTIVE;
+			}
+
+			newStranger = true;
+			waiting = false;
+		}
+
+		if ( (pos = resp.data.find( "[\"commonLikes\"," )) != std::string::npos ) {
+			pos += 17;
+			std::string like = resp.data.substr(pos, resp.data.find("\"]", pos) - pos);
+			utils::text::replace_all(&like, "\", \"", ", ");
+
+			parent->debugLogA("Got common likes: '%s'", like.c_str());
+
+			like = Translate("You and the Stranger both like: ") + like;
+
+			TCHAR *msg = mir_a2t(like.c_str());
+			parent->SetTopic(msg);
+			mir_free(msg);
+		}
+
+		if ( (pos = resp.data.find( "[\"question\"," )) != std::string::npos ) {
+			pos += 13;
+
+			std::string question = utils::text::trim(
+				utils::text::special_expressions_decode(
+					utils::text::slashu_to_utf8(
+						resp.data.substr(pos, resp.data.find("\"]", pos) - pos)	)) );
+
+			TCHAR *msg = mir_a2t_cp(question.c_str(),CP_UTF8);
+			parent->SetTopic(msg);
+			mir_free(msg);
+		}
+
+		if ( resp.data.find( "[\"typing\"]" ) != std::string::npos
+			|| resp.data.find( "[\"spyTyping\"," ) != std::string::npos )
+		{
+			// Stranger is typing, not supported by chat module yet
+			SkinPlaySound( "StrangerTyp" );
+			
+			
+			StatusTextData st = { 0 };
+			st.cbSize = sizeof(st);
+			// st.hIcon = IcoLib_GetIconByHandle(GetIconHandle("typing_on")); // TODO: typing icon
+
+			mir_sntprintf(st.tszText, TranslateT("%s is typing."), TranslateT("Stranger"));
+
+			CallService(MS_MSG_SETSTATUSTEXT, (WPARAM)parent->GetChatHandle(), (LPARAM)&st);
+		}
+
+		if ( resp.data.find( "[\"stoppedTyping\"]" ) != std::string::npos
+			|| resp.data.find( "[\"spyStoppedTyping\"," ) != std::string::npos )
+		{
+			// Stranger stopped typing, not supported by chat module yet
+			SkinPlaySound( "StrangerTypStop" );
+			
+			StatusTextData st = { 0 };
+			st.cbSize = sizeof(st);
+			// st.hIcon = IcoLib_GetIconByHandle(GetIconHandle("typing_off")); // TODO: typing icon
+
+			mir_sntprintf(st.tszText, TranslateT("%s stopped typing."), TranslateT("Stranger"));
+
+			CallService(MS_MSG_SETSTATUSTEXT, (WPARAM)parent->GetChatHandle(), (LPARAM)&st);
+		}
+
+		pos = 0;
+		while ( (pos = resp.data.find( "[\"gotMessage\",", pos )) != std::string::npos ) {
+			pos += 15;
+
+			std::string message = utils::text::trim(
+				utils::text::special_expressions_decode(
+					utils::text::slashu_to_utf8(
+						resp.data.substr(pos, resp.data.find("\"]", pos) - pos)	)) );
+			
+			if (state_ == STATE_ACTIVE) {
+				TCHAR *msg = mir_a2t_cp(message.c_str(),CP_UTF8);
+				parent->UpdateChat(TranslateT("Stranger"), msg);
+				mir_free(msg);
+			}
+
+			CallService(MS_MSG_SETSTATUSTEXT, (WPARAM)parent->GetChatHandle(), 0);
+		}
+
+		pos = 0;
+		while ( (pos = resp.data.find( "[\"spyMessage\",", pos )) != std::string::npos ) {
+			pos += 15;
+
+			std::string message = resp.data.substr(pos, resp.data.find("\"]", pos) - pos);
+			
+			if (state_ == STATE_SPY) {
+				std::string stranger = message.substr(0, message.find("\""));
+				message = message.substr(stranger.length() + 4);
+
+				message = utils::text::trim(
+							utils::text::special_expressions_decode(
+								utils::text::slashu_to_utf8( message )) );
+				
+				stranger = Translate(stranger.c_str());
+				
+				TCHAR *str = mir_a2t_cp(stranger.c_str(), CP_UTF8);				
+				TCHAR *msg = mir_a2t_cp(message.c_str(), CP_UTF8);
+
+				parent->UpdateChat(str, msg);
+
+				mir_free(msg);
+				mir_free(str);
+			}
+		}
+
+		if ( resp.data.find( "[\"strangerDisconnected\"]" ) != std::string::npos ) {
+			CallService(MS_MSG_SETSTATUSTEXT, (WPARAM)parent->GetChatHandle(), NULL);
+
+			// Stranger disconnected
+			if (db_get_b(NULL, parent->m_szModuleName, OMEGLE_KEY_DONT_STOP, 0))
+			{
+				SkinPlaySound( "StrangerChange" );
+				parent->NewChat();
+			}
+			else			
+				parent->StopChat(false);
+		}
+
+		if ( (pos = resp.data.find( "[\"spyDisconnected\"," )) != std::string::npos ) {
+			pos += 20;
+
+			std::string stranger = utils::text::trim(
+				utils::text::special_expressions_decode(
+					utils::text::slashu_to_utf8(
+						resp.data.substr(pos, resp.data.find("\"]", pos) - pos)	)) );
+
+			char str[255];
+			mir_snprintf(str, Translate("%s disconnected."), Translate(stranger.c_str()));
+			
+			TCHAR *msg = mir_a2t(str);
+			parent->UpdateChat(NULL, msg);
+			mir_free(msg);
+
+			// Stranger disconnected
+			if (db_get_b(NULL, parent->m_szModuleName, OMEGLE_KEY_DONT_STOP, 0))
+			{
+				SkinPlaySound( "StrangerChange" );
+				parent->NewChat();
+			}
+			else
+				parent->StopChat(false);
+		}
+
+		if ( resp.data.find( "[\"recaptchaRequired\"" ) != std::string::npos ) {
+			// Nothing to do with recaptcha
+			parent->UpdateChat(NULL, TranslateT("Recaptcha is required.\nOpen http://omegle.com , solve Recaptcha and try again."));
+			parent->StopChat(false);
+		}
+
+		if ( resp.data.find( "[\"recaptchaRejected\"]" ) != std::string::npos ) {
+			// Nothing to do with recaptcha
+			parent->StopChat(false);
+		}
+
+		if ( (pos = resp.data.find( "[\"error\"," )) != std::string::npos ) {
+			pos += 10;
+
+			std::string error = utils::text::trim(
+				utils::text::special_expressions_decode(
+					utils::text::slashu_to_utf8(
+						resp.data.substr(pos, resp.data.find("\"]", pos) - pos)	)) );
+
+			error = Translate("Error: ") + error;
+
+			TCHAR *msg = mir_a2t(error.c_str());
+			parent->UpdateChat(NULL, msg);
+			mir_free(msg);
+		}
+				
+		if (newStranger && state_ != STATE_SPY) {
+			// We got new stranger in this event, lets say him "Hi message" if enabled			
+			if ( db_get_b( NULL, parent->m_szModuleName, OMEGLE_KEY_HI_ENABLED, 0 )) {
+				DBVARIANT dbv;
+				if ( !db_get_utf( NULL, parent->m_szModuleName, OMEGLE_KEY_HI, &dbv )) {
+					std::vector<std::string> messages;
+					utils::text::explode(std::string(dbv.pszVal), "\r\n", &messages);
+					db_free(&dbv);
+
+					int pos = rand() % messages.size();
+					std::string *message = new std::string(messages.at(pos));
+	
+					parent->debugLogA("**Chat - saying Hi! message");
+					parent->ForkThread(&OmegleProto::SendMsgWorker, message);
+				}
+				else parent->debugLogA("**Chat - Hi message is enabled but not used");
+			}
+		}
+
+		if (waiting) {
+			// If we are only waiting in this event...
+			parent->UpdateChat(NULL, TranslateT("We are still waiting..."));
+		}
+
+		return handle_success( "events" );
+	}
+
+	case HTTP_CODE_FAKE_DISCONNECTED:
+		// timeout
+		return handle_success( "events" );
+
+	case HTTP_CODE_FAKE_ERROR:
+	default:
+		return handle_error( "events" );
+	}
+}
+
+bool Omegle_client::send_message(const std::string &message_text )
+{
+	handle_entry( "send_message" );
+
+	std::string data = "msg=" + utils::url::encode( message_text );
+	data += "&id=" + this->chat_id_;
+
+	http::response resp = flap( OMEGLE_REQUEST_SEND, &data );
+
+	switch ( resp.code )
+	{
+	case HTTP_CODE_OK:
+		if (resp.data == "win") {
+			return handle_success( "send_message" );
+		}
+
+	case HTTP_CODE_FAKE_ERROR:
+	case HTTP_CODE_FAKE_DISCONNECTED:
+	default:
+		return handle_error( "send_message" );
+	}
+}
+
+bool Omegle_client::typing_start()
+{
+	handle_entry( "typing_start" );
+
+	std::string data = "id=" + this->chat_id_;
+
+	http::response resp = flap( OMEGLE_REQUEST_TYPING_START, &data );
+
+	switch ( resp.code )
+	{
+	case HTTP_CODE_OK:
+		if (resp.data == "win") {
+			return handle_success( "typing_start" );
+		}
+
+	case HTTP_CODE_FAKE_ERROR:
+	case HTTP_CODE_FAKE_DISCONNECTED:
+	default:
+		return handle_error( "typing_start" );
+	}
+}
+
+bool Omegle_client::typing_stop()
+{
+	handle_entry( "typing_stop" );
+
+	std::string data = "id=" + this->chat_id_;
+
+	http::response resp = flap( OMEGLE_REQUEST_TYPING_STOP, &data );
+
+	switch ( resp.code )
+	{
+	case HTTP_CODE_OK:
+		if (resp.data == "win") {
+			return handle_success( "typing_stop" );
+		}
+
+	case HTTP_CODE_FAKE_ERROR:
+	case HTTP_CODE_FAKE_DISCONNECTED:
+	default:
+		return handle_error( "typing_stop" );
+	}
+}
+
+bool Omegle_client::recaptcha()
+{
+	// TODO: Implement!
+
+	handle_entry( "recaptcha" );
+
+	// data:{id:this.clientID,challenge:b,response:a}}
+	//std::string data = "?id=...&challenge= ..., &response= ...";
+
+	http::response resp = flap( OMEGLE_REQUEST_RECAPTCHA );
+
+	switch ( resp.code )
+	{
+	case HTTP_CODE_OK:
+/*		if (resp.data == "win") {
+			return handle_success( "typing_start" );
+		}*/
+
+	case HTTP_CODE_FAKE_ERROR:
+	case HTTP_CODE_FAKE_DISCONNECTED:
+	default:
+		return handle_error( "typing_start" );
+	}
+}
+
+std::string Omegle_client::get_page(const int request_type)
+{
+	handle_entry("get_page");
+
+	http::response resp = flap(request_type);
+
+	switch ( resp.code )
+	{
+	case HTTP_CODE_OK:
+		handle_success("get_page");
+		break;
+
+	case HTTP_CODE_FAKE_ERROR:
+	case HTTP_CODE_FAKE_DISCONNECTED:
+	default:
+		handle_error("get_page");
+	}
+
+	return resp.data;
+}
diff --git a/protocols/Omegle/src/messages.cpp b/protocols/Omegle/src/messages.cpp
index 5eea9b5893..666229ebfd 100644
--- a/protocols/Omegle/src/messages.cpp
+++ b/protocols/Omegle/src/messages.cpp
@@ -1,79 +1,77 @@
-/*
-
-Omegle plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright � 2011-15 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/>.
-
-*/
-
-#include "stdafx.h"
-
-void OmegleProto::SendMsgWorker(void *p)
-{
-	if(p == NULL)
-		return;
-  
-	ScopedLock s( facy.send_message_lock_ );
-
-	std::string data = *(std::string*)p;
-	delete (std::string*)p;
-
-	data = utils::text::trim(data);
-
-	if (facy.state_ == STATE_ACTIVE && data.length() && facy.send_message( data ))
-	{
-		TCHAR *msg = mir_a2t_cp(data.c_str(), CP_UTF8);
-		UpdateChat(facy.nick_, msg);
-		mir_free(msg);
-	}
-}
-
-void OmegleProto::SendTypingWorker(void *p)
-{
-	if (p == NULL)
-		return;
-
-	// Save typing info
-	bool typ = (*static_cast<int*>(p) == PROTOTYPE_SELFTYPING_ON);
-	delete (int*)p;
-
-	// Ignore same typing info
-	if (facy.typing_ == typ)
-		return;
-
-	facy.typing_ = typ;
-	// Wait for eventually changes to typing info by other thread and ignore if changed
-	SleepEx(2000, true);
-	if (facy.typing_ != typ || facy.old_typing_ == typ || facy.state_ != STATE_ACTIVE)
-		return;	
-
-	facy.old_typing_ = typ;
-	if (typ)
-		facy.typing_start();
-	else
-		facy.typing_stop();
-}
-
-void OmegleProto::NewChatWorker(void*)
-{
-	NewChat();
-}
-
-void OmegleProto::StopChatWorker(void*)
-{
-	StopChat();
-}
+/*
+
+Omegle plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright � 2011-15 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/>.
+
+*/
+
+#include "stdafx.h"
+
+void OmegleProto::SendMsgWorker(void *p)
+{
+	if(p == NULL)
+		return;
+  
+	ScopedLock s( facy.send_message_lock_ );
+
+	std::string data = *(std::string*)p;
+	delete (std::string*)p;
+
+	data = utils::text::trim(data);
+
+	if (facy.state_ == STATE_ACTIVE && data.length() && facy.send_message( data ))
+	{
+		TCHAR *msg = mir_a2t_cp(data.c_str(), CP_UTF8);
+		UpdateChat(facy.nick_, msg);
+		mir_free(msg);
+	}
+}
+
+void OmegleProto::SendTypingWorker(void *p)
+{
+	if (p == NULL)
+		return;
+
+	// Save typing info
+	bool typ = (*static_cast<int*>(p) == PROTOTYPE_SELFTYPING_ON);
+	delete (int*)p;
+
+	// Ignore same typing info
+	if (facy.typing_ == typ)
+		return;
+
+	if (facy.state_ != STATE_ACTIVE)
+		return;
+
+	facy.typing_ = typ;
+
+	if (typ)
+		facy.typing_start();
+	else
+		facy.typing_stop();
+}
+
+void OmegleProto::NewChatWorker(void*)
+{
+	NewChat();
+}
+
+void OmegleProto::StopChatWorker(void*)
+{
+	StopChat();
+}
diff --git a/protocols/Omegle/src/stdafx.h b/protocols/Omegle/src/stdafx.h
index 722a3520fe..58bd9ed275 100644
--- a/protocols/Omegle/src/stdafx.h
+++ b/protocols/Omegle/src/stdafx.h
@@ -29,6 +29,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include <sstream>
 #include <fstream>
 #include <map>
+#include <vector>
 #include <stdarg.h>
 #include <time.h>
 #include <assert.h>
diff --git a/protocols/Omegle/src/utils.cpp b/protocols/Omegle/src/utils.cpp
index 86db3feec1..0e5b4b2153 100644
--- a/protocols/Omegle/src/utils.cpp
+++ b/protocols/Omegle/src/utils.cpp
@@ -108,13 +108,29 @@ std::string utils::text::slashu_to_utf8(const std::string &data )
 	return new_string;
 }
 
-std::string utils::text::trim(const std::string &data )
+std::string utils::text::trim(const std::string &data)
 {
 	std::string spaces = " \t\r\n";
-	std::string::size_type begin = data.find_first_not_of( spaces );
-	std::string::size_type end = data.find_last_not_of( spaces ) + 1;
+	std::string::size_type begin = data.find_first_not_of(spaces);
+	std::string::size_type end = data.find_last_not_of(spaces);
 
-	return (begin != std::string::npos) ? data.substr( begin, end - begin ) : "";
+	return (end != std::string::npos) ? data.substr(begin, end + 1 - begin) : "";
+}
+
+void utils::text::explode(std::string str, std::string separator, std::vector<std::string>* results)
+{
+	std::string::size_type pos;
+	pos = str.find_first_of(separator);
+	while (pos != std::string::npos) {
+		if (pos > 0) {
+			results->push_back(str.substr(0, pos));
+		}
+		str = str.substr(pos + 1);
+		pos = str.find_first_of(separator);
+	}
+	if (str.length() > 0) {
+		results->push_back(str);
+	}
 }
 
 int utils::debug::log(const std::string &file_name, const std::string &text)
diff --git a/protocols/Omegle/src/utils.h b/protocols/Omegle/src/utils.h
index cd7dacbcd0..578d2874a7 100644
--- a/protocols/Omegle/src/utils.h
+++ b/protocols/Omegle/src/utils.h
@@ -37,6 +37,7 @@ namespace utils
 		std::string special_expressions_decode( std::string data );
 		std::string slashu_to_utf8(const std::string &data );
 		std::string trim(const std::string &data );
+		void explode(std::string str, std::string separator, std::vector<std::string>* results);
 	};
 
 	namespace debug
-- 
cgit v1.2.3