From 105158e0a4b2c23adb154e298aac9e10b665b18b Mon Sep 17 00:00:00 2001 From: George Hazan Date: Sun, 23 Dec 2018 19:26:06 +0300 Subject: Icq: implementation of new login --- protocols/Icq10/src/http.cpp | 164 ++++++++++++++++++ protocols/Icq10/src/http.h | 10 ++ protocols/Icq10/src/icq_proto.cpp | 310 --------------------------------- protocols/Icq10/src/icq_proto.h | 96 ----------- protocols/Icq10/src/proto.cpp | 351 ++++++++++++++++++++++++++++++++++++++ protocols/Icq10/src/proto.h | 126 ++++++++++++++ protocols/Icq10/src/server.cpp | 189 ++++++++++++++++++++ protocols/Icq10/src/stdafx.h | 9 +- 8 files changed, 848 insertions(+), 407 deletions(-) create mode 100644 protocols/Icq10/src/http.cpp create mode 100644 protocols/Icq10/src/http.h delete mode 100644 protocols/Icq10/src/icq_proto.cpp delete mode 100644 protocols/Icq10/src/icq_proto.h create mode 100644 protocols/Icq10/src/proto.cpp create mode 100644 protocols/Icq10/src/proto.h create mode 100644 protocols/Icq10/src/server.cpp (limited to 'protocols/Icq10') diff --git a/protocols/Icq10/src/http.cpp b/protocols/Icq10/src/http.cpp new file mode 100644 index 0000000000..a65f0bc3c6 --- /dev/null +++ b/protocols/Icq10/src/http.cpp @@ -0,0 +1,164 @@ +// ----------------------------------------------------------------------------- +// ICQ plugin for Miranda NG +// ----------------------------------------------------------------------------- +// Copyright © 2018 Miranda NG team +// +// 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, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// ----------------------------------------------------------------------------- + +#include "stdafx.h" + +#pragma comment(lib, "Rpcrt4.lib") + +void __cdecl CIcqProto::ServerThread(void*) +{ + m_hAPIConnection = nullptr; + m_bTerminated = false; + + int uin = getDword("UIN"); + ptrA szPassword(getStringA("Password")); + if (uin == 0 || szPassword == nullptr) { + debugLogA("Thread ended, UIN/password are not configured"); + ConnectionFailed(LOGINERR_BADUSERID); + return; + } + + debugLogA("CIcqProto::WorkerThread: %s", "entering"); + { + char mirVer[100]; + Miranda_GetVersionText(mirVer, _countof(mirVer)); + + auto *pReq = new AsyncHttpRequest(REQUEST_POST, "https://api.login.icq.net/auth/clientLogin", &CIcqProto::OnCheckPassword); + pReq << CHAR_PARAM("clientName", "Miranda NG") << CHAR_PARAM("clientVersion", mirVer) << CHAR_PARAM("devId", "ic1nmMjqg7Yu-0hL") + << CHAR_PARAM("f", "json") << CHAR_PARAM("tokenType", "longTerm") << INT_PARAM("s", uin) << CHAR_PARAM("pwd", szPassword); + pReq->flags |= NLHRF_NODUMPSEND; + Push(pReq); + } + + while (true) { + WaitForSingleObject(m_evRequestsQueue, 1000); + if (m_bTerminated) + break; + + AsyncHttpRequest *pReq; + bool need_sleep = false; + while (true) { + { + mir_cslock lck(m_csHttpQueue); + if (m_arHttpQueue.getCount() == 0) + break; + + pReq = m_arHttpQueue[0]; + m_arHttpQueue.remove(0); + need_sleep = (m_arHttpQueue.getCount() > 1); + } + if (m_bTerminated) + break; + ExecuteRequest(pReq); + if (need_sleep) { + Sleep(330); + debugLogA("CIcqProto::WorkerThread: %s", "need to sleep"); + } + } + } + + m_hWorkerThread = nullptr; + if (m_hAPIConnection) { + Netlib_CloseHandle(m_hAPIConnection); + m_hAPIConnection = nullptr; + } + + debugLogA("CIcqProto::WorkerThread: %s", "leaving"); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +AsyncHttpRequest::AsyncHttpRequest(int iType, const char *szUrl, MTHttpRequestHandler pFunc) +{ + flags = NLHRF_HTTP11 | NLHRF_SSL; + requestType = iType; + m_szUrl = szUrl; + m_pFunc = pFunc; + UuidCreate(&m_reqId); + + if (iType == REQUEST_POST) { + AddHeader("Content-Type", "application/x-www-form-urlencoded"); + + dataLength = m_szParam.GetLength(); + pData = m_szParam.Detach(); + } +} + +void CIcqProto::ExecuteRequest(AsyncHttpRequest *pReq) +{ + CMStringA str; + + pReq->szUrl = pReq->m_szUrl.GetBuffer(); + if (!pReq->m_szParam.IsEmpty()) { + if (pReq->requestType == REQUEST_GET) { + str.Format("%s?%s", pReq->m_szUrl.c_str(), pReq->m_szParam.c_str()); + pReq->szUrl = str.GetBuffer(); + } + else { + pReq->pData = mir_strdup(pReq->m_szParam); + pReq->dataLength = pReq->m_szParam.GetLength(); + } + } + + if (pReq->m_bMainSite) { + pReq->flags |= NLHRF_PERSISTENT; + pReq->nlc = m_hAPIConnection; + } + + RPC_CSTR szId; + UuidToStringA(&pReq->m_reqId, &szId); + debugLogA("Executing request %s:\n%s", (char*)szId, pReq->szUrl); + + NETLIBHTTPREQUEST *reply = Netlib_HttpTransaction(m_hNetlibUser, pReq); + if (reply != nullptr) { + if (pReq->m_pFunc != nullptr) + (this->*(pReq->m_pFunc))(reply, pReq); + + if (pReq->m_bMainSite) + m_hAPIConnection = reply->nlc; + + Netlib_FreeHttpRequest(reply); + } + else { + debugLogA("Request %s failed", (char*)szId); + + if (pReq->m_bMainSite) { + if (IsStatusConnecting(m_iStatus)) + ConnectionFailed(LOGINERR_NONETWORK); + m_hAPIConnection = nullptr; + } + } + + RpcStringFreeA(&szId); + delete pReq; +} + +void CIcqProto::Push(MHttpRequest *p) +{ + AsyncHttpRequest *pReq = (AsyncHttpRequest*)p; + + pReq->timeout = 10000; + { + mir_cslock lck(m_csHttpQueue); + m_arHttpQueue.insert(pReq); + } + + SetEvent(m_evRequestsQueue); +} diff --git a/protocols/Icq10/src/http.h b/protocols/Icq10/src/http.h new file mode 100644 index 0000000000..3c5285e2ad --- /dev/null +++ b/protocols/Icq10/src/http.h @@ -0,0 +1,10 @@ + +class CIcqProto; + +struct AsyncHttpRequest : public MTHttpRequest +{ + bool m_bMainSite = true; + GUID m_reqId; + + AsyncHttpRequest(int type, const char *szUrl, MTHttpRequestHandler pFunc = nullptr); +}; diff --git a/protocols/Icq10/src/icq_proto.cpp b/protocols/Icq10/src/icq_proto.cpp deleted file mode 100644 index abb02d21d6..0000000000 --- a/protocols/Icq10/src/icq_proto.cpp +++ /dev/null @@ -1,310 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera, George Hazan -// Copyright © 2012-2018 Miranda NG team -// -// 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, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Protocol Interface Implementation -// ----------------------------------------------------------------------------- - -#include "stdafx.h" - -#include "m_icolib.h" - -#pragma warning(disable:4355) - -CIcqProto::CIcqProto(const char* aProtoName, const wchar_t* aUserName) : - PROTO(aProtoName, aUserName) -{ -} - -CIcqProto::~CIcqProto() -{ -} - -//////////////////////////////////////////////////////////////////////////////////////// -// OnModulesLoadedEx - performs hook registration - -void CIcqProto::OnModulesLoaded() -{ -} - -void CIcqProto::OnShutdown() -{ -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_AddToList - adds a contact to the contact list - -MCONTACT CIcqProto::AddToList(int flags, PROTOSEARCHRESULT *psr) -{ - return 0; -} - -MCONTACT CIcqProto::AddToListByEvent(int flags, int iContact, MEVENT hDbEvent) -{ - return 0; // Failure -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_AuthAllow - processes the successful authorization - -int CIcqProto::Authorize(MEVENT hDbEvent) -{ - return 1; // Failure -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_AuthDeny - handles the unsuccessful authorization - -int CIcqProto::AuthDeny(MEVENT hDbEvent, const wchar_t* szReason) -{ - return 1; // Failure -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// PSR_AUTH - -int CIcqProto::AuthRecv(MCONTACT hContact, PROTORECVEVENT* pre) -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PSS_AUTHREQUEST - -int CIcqProto::AuthRequest(MCONTACT hContact, const wchar_t* szMessage) -{ - return 1; // Failure -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_FileAllow - starts a file transfer - -HANDLE CIcqProto::FileAllow(MCONTACT hContact, HANDLE hTransfer, const wchar_t* szPath) -{ - return nullptr; // Failure -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_FileCancel - cancels a file transfer - -int CIcqProto::FileCancel(MCONTACT hContact, HANDLE hTransfer) -{ - return 1; // Failure -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_FileDeny - denies a file transfer - -int CIcqProto::FileDeny(MCONTACT hContact, HANDLE hTransfer, const wchar_t* szReason) -{ - return 1; // Invalid contact -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_FileResume - processes file renaming etc - -int CIcqProto::FileResume(HANDLE hTransfer, int* action, const wchar_t** szFilename) -{ - return 1; // Failure -} - -//////////////////////////////////////////////////////////////////////////////////////// -// GetCaps - return protocol capabilities bits - -INT_PTR CIcqProto::GetCaps(int type, MCONTACT hContact) -{ - INT_PTR nReturn = 0; - - switch (type) { - - case PFLAGNUM_1: - nReturn = PF1_IM | PF1_URL | PF1_AUTHREQ | PF1_BASICSEARCH | PF1_ADDSEARCHRES | - PF1_VISLIST | PF1_INVISLIST | PF1_MODEMSG | PF1_FILE | PF1_EXTSEARCH | - PF1_EXTSEARCHUI | PF1_SEARCHBYEMAIL | PF1_SEARCHBYNAME | - PF1_ADDED | PF1_CONTACT | PF1_SERVERCLIST; - break; - - case PFLAGNUM_2: - return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | - PF2_FREECHAT | PF2_INVISIBLE | PF2_ONTHEPHONE; - - case PFLAGNUM_3: - return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | - PF2_FREECHAT | PF2_INVISIBLE; - - case PFLAGNUM_4: - nReturn = PF4_SUPPORTIDLE | PF4_IMSENDOFFLINE | PF4_INFOSETTINGSVC | PF4_SUPPORTTYPING | PF4_AVATARS; - break; - - case PFLAGNUM_5: - return PF2_FREECHAT | PF2_ONTHEPHONE; - - case PFLAG_UNIQUEIDTEXT: - return (INT_PTR)Translate("User ID"); - } - - return nReturn; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// GetInfo - retrieves a contact info - -int CIcqProto::GetInfo(MCONTACT hContact, int infoType) -{ - return 1; // Failure -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SearchBasic - searches the contact by UID - -HANDLE CIcqProto::SearchBasic(const wchar_t *pszSearch) -{ - // Failure - return nullptr; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SearchByEmail - searches the contact by its e-mail - -HANDLE CIcqProto::SearchByEmail(const wchar_t *email) -{ - return nullptr; // Failure -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_SearchByName - searches the contact by its first or last name, or by a nickname - -HANDLE CIcqProto::SearchByName(const wchar_t *nick, const wchar_t *firstName, const wchar_t *lastName) -{ - return nullptr; // Failure -} - -HWND CIcqProto::CreateExtendedSearchUI(HWND parent) -{ - return nullptr; // Failure -} - -HWND CIcqProto::SearchAdvanced(HWND hwndDlg) -{ - return nullptr; // Failure -} - -//////////////////////////////////////////////////////////////////////////////////////// -// RecvContacts - -int CIcqProto::RecvContacts(MCONTACT hContact, PROTORECVEVENT* pre) -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// RecvMsg - -MEVENT CIcqProto::RecvMsg(MCONTACT hContact, PROTORECVEVENT* pre) -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SendContacts - -int CIcqProto::SendContacts(MCONTACT hContact, int, int nContacts, MCONTACT *hContactsList) -{ - // Exit with Failure - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SendFile - sends a file - -HANDLE CIcqProto::SendFile(MCONTACT hContact, const wchar_t* szDescription, wchar_t** ppszFiles) -{ - return nullptr; // Failure -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_SendMessage - sends a message - -int CIcqProto::SendMsg(MCONTACT hContact, int, const char* pszSrc) -{ - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SendUrl - -int CIcqProto::SendUrl(MCONTACT hContact, int, const char* url) -{ - return 1; // Failure -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_SetStatus - sets the protocol status - -int CIcqProto::SetStatus(int iNewStatus) -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_GetAwayMsg - returns a contact's away message - -HANDLE CIcqProto::GetAwayMsg(MCONTACT hContact) -{ - return nullptr; // Failure -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PSR_AWAYMSG - processes received status mode message - -int CIcqProto::RecvAwayMsg(MCONTACT hContact, int, PROTORECVEVENT* evt) -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_SetAwayMsg - sets the away status message - -int CIcqProto::SetAwayMsg(int status, const wchar_t* msg) -{ - return 0; // Success -} - -///////////////////////////////////////////////////////////////////////////////////////// -// PS_UserIsTyping - sends a UTN notification - -int CIcqProto::UserIsTyping(MCONTACT hContact, int type) -{ - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// PS_SetApparentMode - sets the visibility status - -int CIcqProto::SetApparentMode(MCONTACT hContact, int mode) -{ - return 1; // Failure -} diff --git a/protocols/Icq10/src/icq_proto.h b/protocols/Icq10/src/icq_proto.h deleted file mode 100644 index 3e3d56accf..0000000000 --- a/protocols/Icq10/src/icq_proto.h +++ /dev/null @@ -1,96 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera, George Hazan -// Copyright © 2012-2018 Miranda NG team -// -// 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, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Protocol Interface declarations -// ----------------------------------------------------------------------------- - -#ifndef _ICQ_PROTO_H_ -#define _ICQ_PROTO_H_ - -#include "m_system.h" -#include "m_protoint.h" - -struct CIcqProto : public PROTO -{ - CIcqProto(const char*, const wchar_t*); - ~CIcqProto(); - - //==================================================================================== - // PROTO_INTERFACE - //==================================================================================== - - MCONTACT AddToList( int flags, PROTOSEARCHRESULT *psr) override; - MCONTACT AddToListByEvent( int flags, int iContact, MEVENT hDbEvent) override; - - int Authorize(MEVENT hDbEvent) override; - int AuthDeny(MEVENT hDbEvent, const wchar_t *szReason) override; - int AuthRecv(MCONTACT hContact, PROTORECVEVENT*) override; - int AuthRequest(MCONTACT hContact, const wchar_t *szMessage) override; - - HANDLE FileAllow(MCONTACT hContact, HANDLE hTransfer, const wchar_t *szPath) override; - int FileCancel(MCONTACT hContact, HANDLE hTransfer) override; - int FileDeny(MCONTACT hContact, HANDLE hTransfer, const wchar_t *szReason) override; - int FileResume( HANDLE hTransfer, int *action, const wchar_t **szFilename) override; - - INT_PTR GetCaps(int type, MCONTACT hContact = NULL) override; - int GetInfo(MCONTACT hContact, int infoType) override; - - HANDLE SearchBasic(const wchar_t *id) override; - HANDLE SearchByEmail(const wchar_t *email) override; - HANDLE SearchByName(const wchar_t *nick, const wchar_t *firstName, const wchar_t *lastName) override; - HWND SearchAdvanced(HWND owner) override; - HWND CreateExtendedSearchUI(HWND owner) override; - - int RecvContacts(MCONTACT hContact, PROTORECVEVENT*) override; - MEVENT RecvMsg(MCONTACT hContact, PROTORECVEVENT*) override; - - int SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT *hContactsList) override; - HANDLE SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles) override; - int SendMsg(MCONTACT hContact, int flags, const char *msg) override; - int SendUrl(MCONTACT hContact, int flags, const char *url) override; - - int SetApparentMode(MCONTACT hContact, int mode) override; - int SetStatus(int iNewStatus) override; - - HANDLE GetAwayMsg(MCONTACT hContact) override; - int RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT *evt) override; - int SetAwayMsg(int m_iStatus, const wchar_t *msg) override; - - int UserIsTyping(MCONTACT hContact, int type) override; - - void OnModulesLoaded() override; - void OnShutdown() override; -}; - -struct CMPlugin : public ACCPROTOPLUGIN -{ - CMPlugin(); - - int Load() override; - int Unload() override; -}; - -#endif diff --git a/protocols/Icq10/src/proto.cpp b/protocols/Icq10/src/proto.cpp new file mode 100644 index 0000000000..e9bb0ce0ea --- /dev/null +++ b/protocols/Icq10/src/proto.cpp @@ -0,0 +1,351 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera, George Hazan +// Copyright © 2012-2018 Miranda NG team +// +// 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, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Protocol Interface Implementation +// ----------------------------------------------------------------------------- + +#include "stdafx.h" + +#include "m_icolib.h" + +#pragma warning(disable:4355) + +CIcqProto::CIcqProto(const char* aProtoName, const wchar_t* aUserName) : + PROTO(aProtoName, aUserName), + m_arHttpQueue(10), + m_evRequestsQueue(CreateEvent(nullptr, FALSE, FALSE, nullptr)) +{ + CMStringW descr(FORMAT, TranslateT("%s server connection"), m_tszUserName); + + NETLIBUSER nlu = {}; + nlu.szSettingsModule = m_szModuleName; + nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE; + nlu.szDescriptiveName.w = descr.GetBuffer(); + m_hNetlibUser = Netlib_RegisterUser(&nlu); +} + +CIcqProto::~CIcqProto() +{ + m_arHttpQueue.destroy(); + ::CloseHandle(m_evRequestsQueue); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// OnModulesLoadedEx - performs hook registration + +void CIcqProto::OnModulesLoaded() +{ +} + +void CIcqProto::OnShutdown() +{ +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_AddToList - adds a contact to the contact list + +MCONTACT CIcqProto::AddToList(int flags, PROTOSEARCHRESULT *psr) +{ + return 0; +} + +MCONTACT CIcqProto::AddToListByEvent(int flags, int iContact, MEVENT hDbEvent) +{ + return 0; // Failure +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_AuthAllow - processes the successful authorization + +int CIcqProto::Authorize(MEVENT hDbEvent) +{ + return 1; // Failure +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_AuthDeny - handles the unsuccessful authorization + +int CIcqProto::AuthDeny(MEVENT hDbEvent, const wchar_t* szReason) +{ + return 1; // Failure +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// PSR_AUTH + +int CIcqProto::AuthRecv(MCONTACT hContact, PROTORECVEVENT* pre) +{ + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSS_AUTHREQUEST + +int CIcqProto::AuthRequest(MCONTACT hContact, const wchar_t* szMessage) +{ + return 1; // Failure +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_FileAllow - starts a file transfer + +HANDLE CIcqProto::FileAllow(MCONTACT hContact, HANDLE hTransfer, const wchar_t* szPath) +{ + return nullptr; // Failure +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_FileCancel - cancels a file transfer + +int CIcqProto::FileCancel(MCONTACT hContact, HANDLE hTransfer) +{ + return 1; // Failure +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_FileDeny - denies a file transfer + +int CIcqProto::FileDeny(MCONTACT hContact, HANDLE hTransfer, const wchar_t* szReason) +{ + return 1; // Invalid contact +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_FileResume - processes file renaming etc + +int CIcqProto::FileResume(HANDLE hTransfer, int* action, const wchar_t** szFilename) +{ + return 1; // Failure +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetCaps - return protocol capabilities bits + +INT_PTR CIcqProto::GetCaps(int type, MCONTACT hContact) +{ + INT_PTR nReturn = 0; + + switch (type) { + + case PFLAGNUM_1: + nReturn = PF1_IM | PF1_URL | PF1_AUTHREQ | PF1_BASICSEARCH | PF1_ADDSEARCHRES | + PF1_VISLIST | PF1_INVISLIST | PF1_MODEMSG | PF1_FILE | PF1_EXTSEARCH | + PF1_EXTSEARCHUI | PF1_SEARCHBYEMAIL | PF1_SEARCHBYNAME | + PF1_ADDED | PF1_CONTACT | PF1_SERVERCLIST; + break; + + case PFLAGNUM_2: + return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | + PF2_FREECHAT | PF2_INVISIBLE | PF2_ONTHEPHONE; + + case PFLAGNUM_3: + return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | + PF2_FREECHAT | PF2_INVISIBLE; + + case PFLAGNUM_4: + nReturn = PF4_SUPPORTIDLE | PF4_IMSENDOFFLINE | PF4_INFOSETTINGSVC | PF4_SUPPORTTYPING | PF4_AVATARS; + break; + + case PFLAGNUM_5: + return PF2_FREECHAT | PF2_ONTHEPHONE; + + case PFLAG_UNIQUEIDTEXT: + return (INT_PTR)Translate("User ID"); + } + + return nReturn; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// GetInfo - retrieves a contact info + +int CIcqProto::GetInfo(MCONTACT hContact, int infoType) +{ + return 1; // Failure +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SearchBasic - searches the contact by UID + +HANDLE CIcqProto::SearchBasic(const wchar_t *pszSearch) +{ + // Failure + return nullptr; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SearchByEmail - searches the contact by its e-mail + +HANDLE CIcqProto::SearchByEmail(const wchar_t *email) +{ + return nullptr; // Failure +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_SearchByName - searches the contact by its first or last name, or by a nickname + +HANDLE CIcqProto::SearchByName(const wchar_t *nick, const wchar_t *firstName, const wchar_t *lastName) +{ + return nullptr; // Failure +} + +HWND CIcqProto::CreateExtendedSearchUI(HWND parent) +{ + return nullptr; // Failure +} + +HWND CIcqProto::SearchAdvanced(HWND hwndDlg) +{ + return nullptr; // Failure +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvContacts + +int CIcqProto::RecvContacts(MCONTACT hContact, PROTORECVEVENT* pre) +{ + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// RecvMsg + +MEVENT CIcqProto::RecvMsg(MCONTACT hContact, PROTORECVEVENT* pre) +{ + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendContacts + +int CIcqProto::SendContacts(MCONTACT hContact, int, int nContacts, MCONTACT *hContactsList) +{ + // Exit with Failure + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendFile - sends a file + +HANDLE CIcqProto::SendFile(MCONTACT hContact, const wchar_t* szDescription, wchar_t** ppszFiles) +{ + return nullptr; // Failure +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_SendMessage - sends a message + +int CIcqProto::SendMsg(MCONTACT hContact, int, const char* pszSrc) +{ + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// SendUrl + +int CIcqProto::SendUrl(MCONTACT hContact, int, const char* url) +{ + return 1; // Failure +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_SetStatus - sets the protocol status + +int CIcqProto::SetStatus(int iNewStatus) +{ + debugLogA("CIcqProto::SetStatus iNewStatus = %d, m_iStatus = %d, m_iDesiredStatus = %d m_hWorkerThread = %p", iNewStatus, m_iStatus, m_iDesiredStatus, m_hWorkerThread); + + if (iNewStatus == m_iStatus) + return 0; + + m_iDesiredStatus = iNewStatus; + int iOldStatus = m_iStatus; + + // go offline + if (iNewStatus == ID_STATUS_OFFLINE) { + if (m_bOnline) { + SetServerStatus(ID_STATUS_OFFLINE); + ShutdownSession(); + } + m_iStatus = m_iDesiredStatus; + setAllContactStatuses(ID_STATUS_OFFLINE, false); + + ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)iOldStatus, m_iStatus); + } + // not logged in? come on + else if (m_hWorkerThread == nullptr && !IsStatusConnecting(m_iStatus)) { + m_iStatus = ID_STATUS_CONNECTING; + ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)iOldStatus, m_iStatus); + m_hWorkerThread = ForkThreadEx(&CIcqProto::ServerThread, nullptr, nullptr); + } + else if (m_bOnline) { + debugLogA("setting server online status to %d", iNewStatus); + SetServerStatus(iNewStatus); + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_GetAwayMsg - returns a contact's away message + +HANDLE CIcqProto::GetAwayMsg(MCONTACT hContact) +{ + return nullptr; // Failure +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PSR_AWAYMSG - processes received status mode message + +int CIcqProto::RecvAwayMsg(MCONTACT hContact, int, PROTORECVEVENT* evt) +{ + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_SetAwayMsg - sets the away status message + +int CIcqProto::SetAwayMsg(int status, const wchar_t* msg) +{ + return 0; // Success +} + +///////////////////////////////////////////////////////////////////////////////////////// +// PS_UserIsTyping - sends a UTN notification + +int CIcqProto::UserIsTyping(MCONTACT hContact, int type) +{ + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// PS_SetApparentMode - sets the visibility status + +int CIcqProto::SetApparentMode(MCONTACT hContact, int mode) +{ + return 1; // Failure +} diff --git a/protocols/Icq10/src/proto.h b/protocols/Icq10/src/proto.h new file mode 100644 index 0000000000..45fb20f845 --- /dev/null +++ b/protocols/Icq10/src/proto.h @@ -0,0 +1,126 @@ +// ---------------------------------------------------------------------------80 +// ICQ plugin for Miranda Instant Messenger +// ________________________________________ +// +// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede +// Copyright © 2001-2002 Jon Keating, Richard Hughes +// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004-2010 Joe Kucera, George Hazan +// Copyright © 2012-2018 Miranda NG team +// +// 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, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// ----------------------------------------------------------------------------- +// DESCRIPTION: +// +// Protocol Interface declarations +// ----------------------------------------------------------------------------- + +#ifndef _ICQ_PROTO_H_ +#define _ICQ_PROTO_H_ + +#include "m_system.h" +#include "m_protoint.h" + +class CIcqProto : public PROTO +{ + bool m_bOnline = false, m_bTerminated = false; + void ConnectionFailed(int iReason); + void OnLoggedIn(void); + void OnLoggedOut(void); + void SetServerStatus(int iNewStatus); + void ShutdownSession(void); + + void OnCheckPassword(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnStartSession(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + + HNETLIBCONN m_hAPIConnection; + CMStringA m_szSessionSecret; + CMStringA m_szAToken; + + ////////////////////////////////////////////////////////////////////////////////////// + // http queue + + mir_cs m_csHttpQueue; + HANDLE m_evRequestsQueue; + LIST m_arHttpQueue; + + void ExecuteRequest(AsyncHttpRequest*); + void Push(MHttpRequest*); + + ////////////////////////////////////////////////////////////////////////////////////// + // threads + + HANDLE m_hWorkerThread; + void __cdecl ServerThread(void*); + + ////////////////////////////////////////////////////////////////////////////////////// + // PROTO_INTERFACE + + MCONTACT AddToList( int flags, PROTOSEARCHRESULT *psr) override; + MCONTACT AddToListByEvent( int flags, int iContact, MEVENT hDbEvent) override; + + int Authorize(MEVENT hDbEvent) override; + int AuthDeny(MEVENT hDbEvent, const wchar_t *szReason) override; + int AuthRecv(MCONTACT hContact, PROTORECVEVENT*) override; + int AuthRequest(MCONTACT hContact, const wchar_t *szMessage) override; + + HANDLE FileAllow(MCONTACT hContact, HANDLE hTransfer, const wchar_t *szPath) override; + int FileCancel(MCONTACT hContact, HANDLE hTransfer) override; + int FileDeny(MCONTACT hContact, HANDLE hTransfer, const wchar_t *szReason) override; + int FileResume( HANDLE hTransfer, int *action, const wchar_t **szFilename) override; + + INT_PTR GetCaps(int type, MCONTACT hContact = NULL) override; + int GetInfo(MCONTACT hContact, int infoType) override; + + HANDLE SearchBasic(const wchar_t *id) override; + HANDLE SearchByEmail(const wchar_t *email) override; + HANDLE SearchByName(const wchar_t *nick, const wchar_t *firstName, const wchar_t *lastName) override; + HWND SearchAdvanced(HWND owner) override; + HWND CreateExtendedSearchUI(HWND owner) override; + + int RecvContacts(MCONTACT hContact, PROTORECVEVENT*) override; + MEVENT RecvMsg(MCONTACT hContact, PROTORECVEVENT*) override; + + int SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT *hContactsList) override; + HANDLE SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles) override; + int SendMsg(MCONTACT hContact, int flags, const char *msg) override; + int SendUrl(MCONTACT hContact, int flags, const char *url) override; + + int SetApparentMode(MCONTACT hContact, int mode) override; + int SetStatus(int iNewStatus) override; + + HANDLE GetAwayMsg(MCONTACT hContact) override; + int RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT *evt) override; + int SetAwayMsg(int m_iStatus, const wchar_t *msg) override; + + int UserIsTyping(MCONTACT hContact, int type) override; + + void OnModulesLoaded() override; + void OnShutdown() override; + +public: + CIcqProto(const char*, const wchar_t*); + ~CIcqProto(); +}; + +struct CMPlugin : public ACCPROTOPLUGIN +{ + CMPlugin(); + + int Load() override; + int Unload() override; +}; + +#endif diff --git a/protocols/Icq10/src/server.cpp b/protocols/Icq10/src/server.cpp new file mode 100644 index 0000000000..7668c154f6 --- /dev/null +++ b/protocols/Icq10/src/server.cpp @@ -0,0 +1,189 @@ +// ----------------------------------------------------------------------------- +// ICQ plugin for Miranda NG +// ----------------------------------------------------------------------------- +// Copyright © 2018 Miranda NG team +// +// 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, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// ----------------------------------------------------------------------------- + +#include "stdafx.h" + +void CIcqProto::ConnectionFailed(int iReason) +{ + debugLogA("ConnectionFailed -> reason %d", iReason); + + ProtoBroadcastAck(0, ACKTYPE_LOGIN, ACKRESULT_FAILED, nullptr, iReason); + ShutdownSession(); +} + +void CIcqProto::OnLoggedIn() +{ + debugLogA("CIcqProto::OnLoggedIn"); + m_bOnline = true; + SetServerStatus(m_iDesiredStatus); +} + +void CIcqProto::OnLoggedOut() +{ + debugLogA("CIcqProto::OnLoggedOut"); + m_bOnline = false; + m_bTerminated = true; + + ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, ID_STATUS_OFFLINE); + m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; + + setAllContactStatuses(ID_STATUS_OFFLINE, false); +} + +void CIcqProto::SetServerStatus(int iStatus) +{ + int iOldStatus = m_iStatus; m_iStatus = iStatus; + ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)iOldStatus, m_iStatus); +} + +void CIcqProto::ShutdownSession() +{ + if (m_bTerminated) + return; + + debugLogA("CIcqProto::ShutdownSession"); + + // shutdown all resources + if (m_hWorkerThread) + SetEvent(m_evRequestsQueue); + if (m_hAPIConnection) + Netlib_Shutdown(m_hAPIConnection); + + OnLoggedOut(); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#define CAPS "094613504c7f11d18222444553540000,094613514c7f11d18222444553540000,094613534c7f11d18222444553540000,094613544c7f11d18222444553540000,094613594c7f11d18222444553540000,0946135b4c7f11d18222444553540000,0946135a4c7f11d18222444553540000" +#define EVENTS "myInfo,presence,buddylist,typing,dataIM,userAddedToBuddyList,service,webrtcMsg,mchat,hist,hiddenChat,diff,permitDeny,imState,notification,apps" +#define FIELDS "aimId,buddyIcon,bigBuddyIcon,iconId,bigIconId,largeIconId,displayId,friendly,offlineMsg,state,statusMsg,userType,phoneNumber,cellNumber,smsNumber,workNumber,otherNumber,capabilities,ssl,abPhoneNumber,moodIcon,lastName,abPhones,abContactName,lastseen,mute,livechat,official" + +void CIcqProto::OnCheckPassword(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*) +{ + if (pReply->resultCode != 200 || pReply->pData == nullptr) { + ConnectionFailed(LOGINERR_WRONGPROTOCOL); + return; + } + + JSONROOT root(pReply->pData); + if (!root) { + ConnectionFailed(LOGINERR_WRONGPROTOCOL); + return; + } + + JSONNode response = (*root)["response"]; + switch (response["statusCode"].as_int()) { + case 200: + { + JSONNode data = response["data"]; + m_szAToken = data["token"]["a"].as_mstring(); + m_szSessionSecret = data["sessionSecret"].as_mstring(); + + CMStringA szUin = data["loginId"].as_mstring(); + if (szUin) + setDword("UIN", atoi(szUin)); + } + break; + + case 440: + ConnectionFailed(LOGINERR_WRONGPASSWORD); + return; + + default: + ConnectionFailed(LOGINERR_WRONGPROTOCOL); + return; + } + + ptrA szDeviceId(getStringA("DeviceId")); + if (szDeviceId == nullptr) { + UUID deviceId; + UuidCreate(&deviceId); + RPC_CSTR szId; + UuidToStringA(&deviceId, &szId); + szDeviceId = mir_strdup((char*)szId); + setString("DeviceId", szDeviceId); + RpcStringFreeA(&szId); + } + + int ts = time(0); + CMStringA nonce(FORMAT, "%d-2", ts); + + auto *pReq = new AsyncHttpRequest(REQUEST_POST, "https://api.icq.net/aim/startSession", &CIcqProto::OnStartSession); + + RPC_CSTR szId; + UuidToStringA(&pReq->m_reqId, &szId); + + pReq << CHAR_PARAM("a", m_szAToken) << INT_PARAM("activeTimeout", 180) << CHAR_PARAM("assertCaps", CAPS) + << INT_PARAM("buildNumber", __BUILD_NUM) << CHAR_PARAM("clientName", "Miranda NG") << INT_PARAM("clientVersion", 5000) + << CHAR_PARAM("deviceId", szDeviceId) << CHAR_PARAM("events", EVENTS) << CHAR_PARAM("f", "json") << CHAR_PARAM("imf", "plain") + << CHAR_PARAM("inactiveView", "offline") << CHAR_PARAM("includePresenceFields", FIELDS) << CHAR_PARAM("invisible", "false") + << CHAR_PARAM("k", "ic1nmMjqg7Yu-0hL") << INT_PARAM("majorVersion", __MAJOR_VERSION) << INT_PARAM("minorVersion", __MINOR_VERSION) + << INT_PARAM("mobile", 0) << CHAR_PARAM("nonce", nonce) << INT_PARAM("pointVersion", 0) << CHAR_PARAM("r", (char*)szId) + << INT_PARAM("rawMsg", 0) << INT_PARAM("sessionTimeout", 7776000) << INT_PARAM("ts", ts) << CHAR_PARAM("view", "online"); + + BYTE hashOut[MIR_SHA256_HASH_SIZE]; + ptrA szPassword(getStringA("Password")); + mir_hmac_sha256(hashOut, (BYTE*)szPassword.get(), mir_strlen(szPassword), (BYTE*)m_szSessionSecret.c_str(), m_szSessionSecret.GetLength()); + ptrA szSessionKey(mir_base64_encode(hashOut, sizeof(hashOut))); + + CMStringA hashData(FORMAT, "POST&%s&%s", ptrA(mir_urlEncode(pReq->szUrl)), ptrA(mir_urlEncode(pReq->m_szParam))); + mir_hmac_sha256(hashOut, (BYTE*)szSessionKey.get(), mir_strlen(szSessionKey), (BYTE*)hashData.c_str(), hashData.GetLength()); + + pReq->m_szParam.Empty(); + pReq << CHAR_PARAM("a", m_szAToken) << INT_PARAM("activeTimeout", 180) << CHAR_PARAM("assertCaps", CAPS) + << INT_PARAM("buildNumber", __BUILD_NUM) << CHAR_PARAM("clientName", "Miranda NG") << INT_PARAM("clientVersion", 5000) + << CHAR_PARAM("deviceId", szDeviceId) << CHAR_PARAM("events", EVENTS) << CHAR_PARAM("f", "json") << CHAR_PARAM("imf", "plain") + << CHAR_PARAM("inactiveView", "offline") << CHAR_PARAM("includePresenceFields", FIELDS) << CHAR_PARAM("invisible", "false") + << CHAR_PARAM("k", "ic1nmMjqg7Yu-0hL") << INT_PARAM("majorVersion", __MAJOR_VERSION) << INT_PARAM("minorVersion", __MINOR_VERSION) + << INT_PARAM("mobile", 0) << CHAR_PARAM("nonce", nonce) << INT_PARAM("pointVersion", 0) << CHAR_PARAM("r", (char*)szId) + << INT_PARAM("rawMsg", 0) << INT_PARAM("sessionTimeout", 7776000) << CHAR_PARAM("sig_sha256", ptrA(mir_base64_encode(hashOut, sizeof(hashOut)))) + << INT_PARAM("ts", ts) << CHAR_PARAM("view", "online"); + + Push(pReq); + RpcStringFreeA(&szId); +} + +void CIcqProto::OnStartSession(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*) +{ + if (pReply->resultCode != 200 || pReply->pData == nullptr) { + ConnectionFailed(LOGINERR_WRONGPROTOCOL); + return; + } + + JSONROOT root(pReply->pData); + if (!root) { + ConnectionFailed(LOGINERR_WRONGPROTOCOL); + return; + } + + JSONNode response = (*root)["response"]; + switch (response["statusCode"].as_int()) { + case 200: + OnLoggedIn(); + break; + + case 401: + ConnectionFailed(LOGINERR_WRONGPASSWORD); + break; + + default: + ConnectionFailed(LOGINERR_WRONGPROTOCOL); + } +} diff --git a/protocols/Icq10/src/stdafx.h b/protocols/Icq10/src/stdafx.h index 3191bcf750..078ef4fe19 100644 --- a/protocols/Icq10/src/stdafx.h +++ b/protocols/Icq10/src/stdafx.h @@ -58,12 +58,18 @@ #include #include #include +#include #include #include #include #include #include +#include +#include +#include +#include + // Project resources #include "resource.h" @@ -72,4 +78,5 @@ #define MODULENAME "ICQ" -#include "icq_proto.h" +#include "http.h" +#include "proto.h" -- cgit v1.2.3