summaryrefslogtreecommitdiff
path: root/protocols/Icq10/src
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2019-01-16 18:06:52 +0300
committerGeorge Hazan <ghazan@miranda.im>2019-01-16 18:06:52 +0300
commitaa514a9f95c8cd95c01952250f7cdb670a66af9a (patch)
treeecb84e10fc3af008e1a8ac9027f1b526634c8d65 /protocols/Icq10/src
parent4f0a4ae4724fdfe65f63ee41dc1790ccbb0668f7 (diff)
fixes #1761 (Rename Icq10 folder and ICQ/2018 in version.h to ICQ-WIM)
Diffstat (limited to 'protocols/Icq10/src')
-rw-r--r--protocols/Icq10/src/groupchats.cpp303
-rw-r--r--protocols/Icq10/src/http.cpp289
-rw-r--r--protocols/Icq10/src/http.h51
-rw-r--r--protocols/Icq10/src/main.cpp77
-rw-r--r--protocols/Icq10/src/options.cpp226
-rw-r--r--protocols/Icq10/src/proto.cpp479
-rw-r--r--protocols/Icq10/src/proto.h263
-rw-r--r--protocols/Icq10/src/resource.h29
-rw-r--r--protocols/Icq10/src/server.cpp859
-rw-r--r--protocols/Icq10/src/stdafx.cxx18
-rw-r--r--protocols/Icq10/src/stdafx.h95
-rw-r--r--protocols/Icq10/src/utils.cpp239
-rw-r--r--protocols/Icq10/src/version.h13
13 files changed, 0 insertions, 2941 deletions
diff --git a/protocols/Icq10/src/groupchats.cpp b/protocols/Icq10/src/groupchats.cpp
deleted file mode 100644
index 5d4253bc15..0000000000
--- a/protocols/Icq10/src/groupchats.cpp
+++ /dev/null
@@ -1,303 +0,0 @@
-// -----------------------------------------------------------------------------
-// ICQ plugin for Miranda NG
-// -----------------------------------------------------------------------------
-// Copyright © 2018-19 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::LoadChatInfo(SESSION_INFO *si)
-{
- int memberCount = getDword(si->hContact, "MemberCount");
- for (int i = 0; i < memberCount; i++) {
- char buf[100];
- mir_snprintf(buf, "m%d", i);
- ptrW szSetting(getWStringA(si->hContact, buf));
- JSONNode *node = json_parse(T2Utf(szSetting));
- if (node == nullptr)
- continue;
-
- CMStringW nick((*node)["nick"].as_mstring());
- CMStringW role((*node)["role"].as_mstring());
- CMStringW sn((*node)["sn"].as_mstring());
-
- GCEVENT gce = { m_szModuleName, si->ptszID, GC_EVENT_JOIN };
- gce.dwFlags = GCEF_SILENT;
- gce.ptszNick = nick;
- gce.ptszUID = sn;
- gce.time = ::time(0);
- gce.bIsMe = _wtoi(sn) == (int)m_dwUin;
- gce.ptszStatus = TranslateW(role);
- Chat_Event(&gce);
-
- json_delete(node);
- }
-}
-
-void CIcqProto::OnGetChatInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
-{
- SESSION_INFO *si = (SESSION_INFO*)pReq->pUserInfo;
-
- RobustReply root(pReply);
- if (root.error() != 20000)
- return;
-
- int n = 0;
- char buf[100];
- const JSONNode &results = root.results();
- for (auto &it : results["members"]) {
- mir_snprintf(buf, "m%d", n++);
-
- CMStringW friendly = it["friendly"].as_mstring();
- CMStringW role = it["role"].as_mstring();
- CMStringW sn = it["sn"].as_mstring();
-
- JSONNode member;
- member << WCHAR_PARAM("nick", friendly) << WCHAR_PARAM("role", role) << WCHAR_PARAM("sn", sn);
- ptrW text(json_write(&member));
- setWString(si->hContact, buf, text);
- }
-
- setDword(si->hContact, "MemberCount", n);
- setId(si->hContact, "InfoVersion", _wtoi64(results["infoVersion"].as_mstring()));
- setId(si->hContact, "MembersVersion", _wtoi64(results["membersVersion"].as_mstring()));
-
- LoadChatInfo(si);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Invitation dialog
-
-class CGroupchatInviteDlg : public CProtoDlgBase<CIcqProto>
-{
- typedef CProtoDlgBase<CIcqProto> CSuper;
-
- CCtrlClc m_clc;
- SESSION_INFO *m_si;
-
- void FilterList(CCtrlClc*)
- {
- for (auto &hContact : Contacts()) {
- char *proto = GetContactProto(hContact);
- if (mir_strcmp(proto, m_proto->m_szModuleName) || m_proto->isChatRoom(hContact))
- if (HANDLE hItem = m_clc.FindContact(hContact))
- m_clc.DeleteItem(hItem);
- }
- }
-
- void ResetListOptions(CCtrlClc*)
- {
- m_clc.SetBkBitmap(0, nullptr);
- m_clc.SetBkColor(GetSysColor(COLOR_WINDOW));
- m_clc.SetGreyoutFlags(0);
- m_clc.SetLeftMargin(4);
- m_clc.SetIndent(10);
- m_clc.SetHideEmptyGroups(1);
- m_clc.SetHideOfflineRoot(1);
- for (int i = 0; i <= FONTID_MAX; i++)
- m_clc.SetTextColor(i, GetSysColor(COLOR_WINDOWTEXT));
- }
-
-public:
- CGroupchatInviteDlg(CIcqProto *ppro, SESSION_INFO *si) :
- CSuper(ppro, IDD_GROUPCHAT_INVITE),
- m_si(si),
- m_clc(this, IDC_CLIST)
- {
- m_clc.OnNewContact =
- m_clc.OnListRebuilt = Callback(this, &CGroupchatInviteDlg::FilterList);
- m_clc.OnOptionsChanged = Callback(this, &CGroupchatInviteDlg::ResetListOptions);
- }
-
- bool OnInitDialog() override
- {
- SetWindowLongPtr(m_clc.GetHwnd(), GWL_STYLE,
- GetWindowLongPtr(m_clc.GetHwnd(), GWL_STYLE) | CLS_SHOWHIDDEN | CLS_HIDEOFFLINE | CLS_CHECKBOXES | CLS_HIDEEMPTYGROUPS | CLS_USEGROUPS | CLS_GREYALTERNATE | CLS_GROUPCHECKBOXES);
- m_clc.SendMsg(CLM_SETEXSTYLE, CLS_EX_DISABLEDRAGDROP | CLS_EX_TRACKSELECT, 0);
-
- ResetListOptions(&m_clc);
- FilterList(&m_clc);
- return true;
- }
-
- bool OnApply() override
- {
- CMStringA szMembers;
- for (auto &hContact : m_proto->AccContacts()) {
- if (m_proto->isChatRoom(hContact))
- continue;
-
- if (HANDLE hItem = m_clc.FindContact(hContact)) {
- if (m_clc.GetCheck(hItem)) {
- if (!szMembers.IsEmpty())
- szMembers.AppendChar(',');
- szMembers.Append(m_proto->GetUserId(hContact));
- }
- }
- }
-
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/mchat/AddChat");
- pReq << CHAR_PARAM("f", "json") << WCHAR_PARAM("chat_id", m_si->ptszID) << CHAR_PARAM("aimsid", m_proto->m_aimsid) << CHAR_PARAM("r", pReq->m_reqId) << CHAR_PARAM("members", szMembers);
- m_proto->Push(pReq);
- return true;
- }
-};
-
-void CIcqProto::InviteUserToChat(SESSION_INFO *si)
-{
- CGroupchatInviteDlg dlg(this, si);
- if (si->pDlg)
- dlg.SetParent(((CDlgBase*)si->pDlg)->GetHwnd());
- dlg.DoModal();
-}
-
-void CIcqProto::LeaveDestroyChat(SESSION_INFO *si)
-{
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/buddylist/hideChat");
- pReq << CHAR_PARAM("f", "json") << CHAR_PARAM("aimsid", m_aimsid) << WCHAR_PARAM("buddy", si->ptszID)
- << CHAR_PARAM("r", pReq->m_reqId) << INT64_PARAM("lastMsgId", getId(si->hContact, DB_KEY_LASTMSGID));
- Push(pReq);
-
- Chat_Terminate(si->pszModule, si->ptszID, true);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Group chats
-
-static gc_item sttLogListItems[] =
-{
- { LPGENW("&Invite a user"), IDM_INVITE, MENU_ITEM },
- { nullptr, 0, MENU_SEPARATOR },
- { LPGENW("&Leave/destroy chat"), IDM_LEAVE, MENU_ITEM }
-};
-
-int CIcqProto::GroupchatMenuHook(WPARAM, LPARAM lParam)
-{
- GCMENUITEMS *gcmi = (GCMENUITEMS*)lParam;
- if (gcmi == nullptr)
- return 0;
-
- if (mir_strcmpi(gcmi->pszModule, m_szModuleName))
- return 0;
-
- SESSION_INFO *si = g_chatApi.SM_FindSession(gcmi->pszID, gcmi->pszModule);
- if (si == nullptr)
- return 0;
-
- if (gcmi->Type == MENU_ON_LOG)
- Chat_AddMenuItems(gcmi->hMenu, _countof(sttLogListItems), sttLogListItems, &g_plugin);
-
- return 0;
-}
-
-int CIcqProto::GroupchatEventHook(WPARAM, LPARAM lParam)
-{
- GCHOOK *gch = (GCHOOK*)lParam;
- if (gch == nullptr)
- return 0;
-
- if (mir_strcmpi(gch->pszModule, m_szModuleName))
- return 0;
-
- SESSION_INFO *si = g_chatApi.SM_FindSession(gch->ptszID, gch->pszModule);
- if (si == nullptr)
- return 0;
-
- switch (gch->iType) {
- case GC_USER_MESSAGE:
- rtrimw(gch->ptszText);
- if (!mir_wstrlen(gch->ptszText))
- break;
-
- if (m_bOnline) {
- wchar_t *wszText = NEWWSTR_ALLOCA(gch->ptszText);
- Chat_UnescapeTags(wszText);
- SendMsg(si->hContact, 0, T2Utf(wszText));
- }
- break;
-
- case GC_USER_PRIVMESS:
- Chat_SendPrivateMessage(gch);
- break;
-
- case GC_USER_LOGMENU:
- Chat_ProcessLogMenu(si, gch->dwData);
- break;
- }
-
- return 0;
-}
-
-void CIcqProto::Chat_ProcessLogMenu(SESSION_INFO *si, int iChoice)
-{
- switch (iChoice) {
- case IDM_INVITE:
- InviteUserToChat(si);
- break;
-
- case IDM_LEAVE:
- LeaveDestroyChat(si);
- break;
- }
-}
-
-void CIcqProto::Chat_SendPrivateMessage(GCHOOK *gch)
-{
- MCONTACT hContact;
- DWORD dwUin = _wtoi(gch->ptszUID);
- auto *pCache = FindContactByUIN(dwUin);
- if (pCache == nullptr) {
- hContact = CreateContact(dwUin, true);
- setWString(hContact, "Nick", gch->ptszNick);
- db_set_b(hContact, "CList", "Hidden", 1);
- db_set_dw(hContact, "Ignore", "Mask1", 0);
- }
- else hContact = pCache->m_hContact;
-
- CallService(MS_MSG_SENDMESSAGE, hContact, 0);
-}
-
-void CIcqProto::ProcessGroupChat(const JSONNode &ev)
-{
- for (auto &it : ev["mchats"]) {
- CMStringW wszId(it["sender"].as_mstring());
- SESSION_INFO *si = g_chatApi.SM_FindSession(wszId, m_szModuleName);
- if (si == nullptr)
- continue;
-
- CMStringW method(it["method"].as_mstring());
- GCEVENT gce = { m_szModuleName, si->ptszID, (method == "add_members") ? GC_EVENT_JOIN : GC_EVENT_PART };
-
- int iStart = 0;
- CMStringW members(it["members"].as_mstring());
- while (true) {
- CMStringW member = members.Tokenize(L",", iStart);
- if (member.IsEmpty())
- break;
-
- auto *pCache = FindContactByUIN(_wtoi(member));
- if (pCache == nullptr)
- continue;
-
- gce.ptszNick = Clist_GetContactDisplayName(pCache->m_hContact);
- gce.ptszUID = member;
- gce.time = ::time(0);
- gce.bIsMe = _wtoi(member) == (int)m_dwUin;
- Chat_Event(&gce);
- }
- }
-}
diff --git a/protocols/Icq10/src/http.cpp b/protocols/Icq10/src/http.cpp
deleted file mode 100644
index e0bd34d17a..0000000000
--- a/protocols/Icq10/src/http.cpp
+++ /dev/null
@@ -1,289 +0,0 @@
-// -----------------------------------------------------------------------------
-// ICQ plugin for Miranda NG
-// -----------------------------------------------------------------------------
-// Copyright © 2018-19 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*)
-{
- memset(&m_ConnPool, 0, sizeof(m_ConnPool));
- m_bTerminated = false;
-
- debugLogA("CIcqProto::WorkerThread: %s", "entering");
-
- while (true) {
- WaitForSingleObject(m_evRequestsQueue, 1000);
- if (m_bTerminated)
- break;
-
- while (true) {
- bool bNeedSleep = false;
- AsyncHttpRequest *pReq;
- {
- mir_cslock lck(m_csHttpQueue);
- if (m_arHttpQueue.getCount() == 0)
- break;
-
- pReq = m_arHttpQueue[0];
- m_arHttpQueue.remove(0);
- bNeedSleep = (m_arHttpQueue.getCount() > 1);
- }
- if (m_bTerminated)
- break;
-
- ExecuteRequest(pReq);
- if (bNeedSleep)
- Sleep(200);
- }
-
- int ts = time(0);
- for (auto &it : m_ConnPool) {
- int idx = int(&it - m_ConnPool);
- if (idx == CONN_FETCH)
- continue;
-
- if (it.s && it.lastTs + it.timeout < ts) {
- debugLogA("Socket #1 (%p) expired", idx, it.s);
- Netlib_CloseHandle(it.s);
- it.s = nullptr;
- it.lastTs = 0;
- }
- }
- }
-
- m_hWorkerThread = nullptr;
- for (auto &it : m_ConnPool) {
- if (it.s)
- Netlib_CloseHandle(it.s);
- it.s = nullptr;
- it.lastTs = it.timeout = 0;
- }
-
- debugLogA("CIcqProto::WorkerThread: %s", "leaving");
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-AsyncHttpRequest::AsyncHttpRequest(IcqConnection conn, int iType, const char *szUrl, MTHttpRequestHandler pFunc) :
- m_conn(conn)
-{
- flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_DUMPASTEXT;
- requestType = iType;
- m_szUrl = szUrl;
- m_pFunc = pFunc;
-
- GUID packetId;
- UuidCreate(&packetId);
-
- RPC_CSTR szId;
- UuidToStringA(&packetId, &szId);
- strncpy_s(m_reqId, (char*)szId, _TRUNCATE);
- RpcStringFreeA(&szId);
-
- if (iType == REQUEST_POST) {
- AddHeader("Content-Type", "application/x-www-form-urlencoded");
-
- dataLength = m_szParam.GetLength();
- pData = m_szParam.Detach();
- }
-}
-
-void AsyncHttpRequest::ReplaceJsonParam(const char *paramName, const char *newValue)
-{
- CMStringA szOldValue(FORMAT, "\"%s\":\"", paramName);
- int idx = m_szParam.Find(szOldValue);
- if (idx == -1)
- return;
-
- idx += szOldValue.GetLength();
- int iEnd = m_szParam.Find("\"", idx);
- if (iEnd == -1)
- return;
-
- szOldValue += m_szParam.Mid(idx, iEnd + 1 - idx);
-
- CMStringA szNewValue(FORMAT, "\"%s\":\"%s\"", paramName, newValue);
- m_szParam.Replace(szOldValue, szNewValue);
-
- replaceStr(pData, nullptr);
- dataLength = 0;
-}
-
-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->dataLength = pReq->m_szParam.GetLength();
- pReq->pData = mir_strdup(pReq->m_szParam);
- }
- }
-
- if (pReq->m_conn == CONN_RAPI) {
- CMStringA szAgent(FORMAT, "%d Mail.ru Windows ICQ (version 10.0.1999)", DWORD(m_dwUin));
- pReq->AddHeader("User-Agent", szAgent);
-
- if (m_szRToken.IsEmpty()) {
- if (!RefreshRobustToken()) {
- delete pReq;
- return;
- }
-
- pReq->ReplaceJsonParam("authToken", m_szRToken);
- pReq->dataLength = pReq->m_szParam.GetLength();
- pReq->pData = mir_strdup(pReq->m_szParam);
- }
- }
-
- debugLogA("Executing request %s:\n%s", pReq->m_reqId, pReq->szUrl);
-
- if (pReq->m_conn != CONN_NONE) {
- pReq->flags |= NLHRF_PERSISTENT;
- pReq->nlc = m_ConnPool[pReq->m_conn].s;
- m_ConnPool[pReq->m_conn].lastTs = time(0);
- }
-
- NETLIBHTTPREQUEST *reply = Netlib_HttpTransaction(m_hNetlibUser, pReq);
- if (reply != nullptr) {
- if (pReq->m_conn != CONN_NONE) {
- auto &conn = m_ConnPool[pReq->m_conn];
- conn.s = reply->nlc;
- conn.timeout = 0;
- for (int i = 0; i < reply->headersCount; i++) {
- if (!mir_strcmp(reply->headers[i].szName, "Keep-Alive")) {
- int timeout;
- if (1 == sscanf(reply->headers[i].szValue, "timeout=%d", &timeout))
- conn.timeout = timeout;
- break;
- }
- }
- }
-
- if (pReq->m_conn == CONN_RAPI && reply->pData && strstr(reply->pData, "\"code\": 40201")) {
- RobustReply r(reply);
- if (r.error() == 40201) { // robust token expired
- m_szRToken.Empty();
-
- // if token refresh succeeded, replace it in the query and push request back
- if (RefreshRobustToken()) {
- pReq->ReplaceJsonParam("authToken", m_szRToken);
- Push(pReq);
- }
- else delete pReq;
- return;
- }
- }
-
- if (pReq->m_pFunc != nullptr)
- (this->*(pReq->m_pFunc))(reply, pReq);
-
- Netlib_FreeHttpRequest(reply);
- }
- else {
- debugLogA("Request %s failed", pReq->m_reqId);
-
- if (pReq->m_conn != CONN_NONE) {
- if (IsStatusConnecting(m_iStatus))
- ConnectionFailed(LOGINERR_NONETWORK);
- m_ConnPool[pReq->m_conn].s = nullptr;
- }
- }
-
- 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);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-JsonReply::JsonReply(NETLIBHTTPREQUEST *pReply)
-{
- if (pReply == nullptr) {
- m_errorCode = 500;
- return;
- }
-
- m_errorCode = pReply->resultCode;
- if (m_errorCode != 200)
- return;
-
- m_root = json_parse(pReply->pData);
- if (m_root == nullptr) {
- m_errorCode = 500;
- return;
- }
-
- JSONNode &response = (*m_root)["response"];
- m_errorCode = response["statusCode"].as_int();
- m_requestId = response["requestId"].as_mstring();
- m_detailCode = response["statusDetailCode"].as_int();
- m_data = &response["data"];
-}
-
-JsonReply::~JsonReply()
-{
- json_delete(m_root);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-RobustReply::RobustReply(NETLIBHTTPREQUEST *pReply)
-{
- if (pReply == nullptr) {
- m_errorCode = 500;
- return;
- }
-
- m_errorCode = pReply->resultCode;
- if (m_errorCode != 200)
- return;
-
- m_root = json_parse(pReply->pData);
- if (m_root == nullptr) {
- m_errorCode = 500;
- return;
- }
-
- m_errorCode = (*m_root)["status"]["code"].as_int();
- m_results = &(*m_root)["results"];
-}
-
-RobustReply::~RobustReply()
-{
- json_delete(m_root);
-}
diff --git a/protocols/Icq10/src/http.h b/protocols/Icq10/src/http.h
deleted file mode 100644
index bdcac34f50..0000000000
--- a/protocols/Icq10/src/http.h
+++ /dev/null
@@ -1,51 +0,0 @@
-
-class CIcqProto;
-
-enum IcqConnection
-{
- CONN_NONE = -1, CONN_MAIN = 0, CONN_FETCH = 1, CONN_RAPI = 2, CONN_LAST = 3
-};
-
-struct AsyncHttpRequest : public MTHttpRequest<CIcqProto>
-{
- IcqConnection m_conn;
- MCONTACT hContact;
- char m_reqId[50];
-
- AsyncHttpRequest(IcqConnection, int type, const char *szUrl, MTHttpRequestHandler pFunc = nullptr);
-
- void ReplaceJsonParam(const char *paramName, const char *newValue);
-};
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-class JsonReply
-{
- JSONNode *m_root = nullptr;
- int m_errorCode = 0, m_detailCode = 0;
- JSONNode* m_data = nullptr;
- CMStringA m_requestId;
-
-public:
- JsonReply(NETLIBHTTPREQUEST*);
- ~JsonReply();
-
- __forceinline const CMStringA& requestId() const { return m_requestId; }
- __forceinline JSONNode& data() const { return *m_data; }
- __forceinline int error() const { return m_errorCode; }
- __forceinline int detail() const { return m_detailCode; }
-};
-
-class RobustReply
-{
- JSONNode *m_root = nullptr;
- int m_errorCode = 0;
- JSONNode* m_results = nullptr;
-
-public:
- RobustReply(NETLIBHTTPREQUEST*);
- ~RobustReply();
-
- __forceinline JSONNode& results() const { return *m_results; }
- __forceinline int error() const { return m_errorCode; }
-};
diff --git a/protocols/Icq10/src/main.cpp b/protocols/Icq10/src/main.cpp
deleted file mode 100644
index 0f1888952d..0000000000
--- a/protocols/Icq10/src/main.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-// -----------------------------------------------------------------------------
-// ICQ plugin for Miranda NG
-// -----------------------------------------------------------------------------
-// Copyright © 2018-19 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"
-
-bool g_bPopupService;
-
-HWND g_hwndHeartbeat;
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-static PLUGININFOEX pluginInfoEx = {
- sizeof(PLUGININFOEX),
- __PLUGIN_NAME,
- PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
- __DESCRIPTION,
- __AUTHOR,
- __COPYRIGHT,
- __AUTHORWEB,
- UNICODE_AWARE,
- { 0xEFB2355B, 0x82B3, 0x4759, { 0xb7, 0xd8, 0x95, 0xf8, 0xe9, 0x50, 0x62, 0x91 } } // {EFB2355B-82B3-4759-B7D8-95F8E9506291}
-};
-
-CMPlugin::CMPlugin() :
- ACCPROTOPLUGIN<CIcqProto>(MODULENAME, pluginInfoEx)
-{
- SetUniqueId(DB_KEY_UIN);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-CMPlugin g_plugin;
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-int ModuleLoad(WPARAM, LPARAM)
-{
- g_bPopupService = ServiceExists(MS_POPUP_ADDPOPUPT);
- return 0;
-}
-
-int CMPlugin::Load()
-{
- g_hwndHeartbeat = CreateWindowEx(0, L"STATIC", nullptr, 0, 0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr);
-
- HookEvent(ME_SYSTEM_MODULELOAD, ModuleLoad);
- HookEvent(ME_SYSTEM_MODULEUNLOAD, ModuleLoad);
- ModuleLoad(0, 0);
- return 0;
-};
-
-int CMPlugin::Unload()
-{
- DestroyWindow(g_hwndHeartbeat);
- return 0;
-}
diff --git a/protocols/Icq10/src/options.cpp b/protocols/Icq10/src/options.cpp
deleted file mode 100644
index 3ff4494232..0000000000
--- a/protocols/Icq10/src/options.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-// -----------------------------------------------------------------------------
-// ICQ plugin for Miranda NG
-// -----------------------------------------------------------------------------
-// Copyright © 2018-19 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"
-
-struct CIcqRegistrationDlg : public CProtoDlgBase<CIcqProto>
-{
- CMStringA szTrans, szMsisdn;
- int iErrorCode;
-
- CCtrlEdit edtPhone, edtCode;
- CCtrlButton btnSendSms;
-
- CIcqRegistrationDlg(CIcqProto *ppro) :
- CProtoDlgBase<CIcqProto>(ppro, IDD_REGISTER),
- edtPhone(this, IDC_PHONE),
- edtCode(this, IDC_CODE),
- btnSendSms(this, IDC_SENDSMS)
- {
- btnSendSms.OnClick = Callback(this, &CIcqRegistrationDlg::onClick_SendSms);
- edtPhone.OnChange = Callback(this, &CIcqRegistrationDlg::onChange_Phone);
- }
-
- bool OnApply() override
- {
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "https://www.icq.com/smsreg/loginWithPhoneNumber.php", &CIcqProto::OnLoginViaPhone);
- pReq << CHAR_PARAM("locale", "en") << CHAR_PARAM("msisdn", szMsisdn) << CHAR_PARAM("trans_id", szTrans) << CHAR_PARAM("k", ICQ_APP_ID)
- << CHAR_PARAM("r", pReq->m_reqId) << CHAR_PARAM("f", "json") << WCHAR_PARAM("sms_code", ptrW(edtCode.GetText())) << INT_PARAM("create_account", 1);
- pReq->pUserInfo = this;
-
- SetCursor(LoadCursor(0, IDC_WAIT));
- m_proto->ExecuteRequest(pReq);
- SetCursor(LoadCursor(0, IDC_ARROW));
-
- if (iErrorCode != 200)
- return false;
-
- EndDialog(m_hwnd, 1);
- return true;
- }
-
- void onChange_Phone(CCtrlEdit*)
- {
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "https://clientapi.icq.net/fcgi-bin/smsphoneinfo", &CIcqProto::OnCheckPhone);
- pReq << CHAR_PARAM("service", "icq_registration") << CHAR_PARAM("info", "typing_check,score,iso_country_code")
- << WCHAR_PARAM("phone", ptrW(edtPhone.GetText())) << CHAR_PARAM("id", pReq->m_reqId);
- pReq->pUserInfo = this;
- m_proto->Push(pReq);
- }
-
- void onClick_SendSms(CCtrlButton*)
- {
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "https://www.icq.com/smsreg/requestPhoneValidation.php", &CIcqProto::OnValidateSms);
- pReq << CHAR_PARAM("locale", "en") << CHAR_PARAM("msisdn", szMsisdn) << CHAR_PARAM("r", pReq->m_reqId)
- << CHAR_PARAM("smsFormatType", "human") << CHAR_PARAM("k", ICQ_APP_ID);
- pReq->pUserInfo = this;
- m_proto->Push(pReq);
- }
-};
-
-void CIcqProto::OnCheckPhone(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
-{
- if (pReply == nullptr || pReply->resultCode != 200)
- return;
-
- CIcqRegistrationDlg *pDlg = (CIcqRegistrationDlg*)pReq->pUserInfo;
- pDlg->btnSendSms.Disable();
- pDlg->edtCode.Disable();
-
- JSONROOT root(pReply->pData);
- CMStringW wszStatus((*root)["status"].as_mstring());
- if (wszStatus != L"OK") {
- pDlg->edtCode.SetText((*root)["printable"].as_mstring());
- return;
- }
-
- CMStringA szPhoneNumber((*root)["typing_check"]["modified_phone_number"].as_mstring());
- CMStringA szPrefix((*root)["modified_prefix"].as_mstring());
-
- auto *pNew = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "https://www.icq.com/smsreg/normalizePhoneNumber.php", &CIcqProto::OnNormalizePhone);
- pNew << CHAR_PARAM("countryCode", szPrefix) << CHAR_PARAM("phoneNumber", szPhoneNumber.c_str() + szPrefix.GetLength())
- << CHAR_PARAM("k", ICQ_APP_ID) << CHAR_PARAM("r", pReq->m_reqId);
- pNew->pUserInfo = pDlg;
- Push(pNew);
-}
-
-void CIcqProto::OnNormalizePhone(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
-{
- CIcqRegistrationDlg *pDlg = (CIcqRegistrationDlg*)pReq->pUserInfo;
-
- JsonReply root(pReply);
- pDlg->iErrorCode = root.error();
- if (root.error() != 200)
- return;
-
- const JSONNode &data = root.data();
- pDlg->szMsisdn = data["msisdn"].as_mstring();
- pDlg->btnSendSms.Enable();
-}
-
-void CIcqProto::OnValidateSms(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
-{
- JsonReply root(pReply);
- if (root.error() != 200)
- return;
-
- CIcqRegistrationDlg *pDlg = (CIcqRegistrationDlg*)pReq->pUserInfo;
- const JSONNode &data = root.data();
- pDlg->szTrans = data["trans_id"].as_mstring();
-
- pDlg->edtCode.Enable();
- pDlg->edtCode.SetText(L"");
-}
-
-void CIcqProto::OnLoginViaPhone(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
-{
- CIcqRegistrationDlg *pDlg = (CIcqRegistrationDlg*)pReq->pUserInfo;
-
- JsonReply root(pReply);
- pDlg->iErrorCode = root.error();
- if (root.error() != 200)
- return;
-
- const JSONNode &data = root.data();
- m_szAToken = data["token"]["a"].as_mstring();
- m_szAToken = ptrA(mir_urlDecode(m_szAToken));
- setString(DB_KEY_ATOKEN, m_szAToken);
-
- m_szSessionKey = data["sessionKey"].as_mstring();
- m_szSessionKey = ptrA(mir_urlDecode(m_szSessionKey));
- setString(DB_KEY_SESSIONKEY, m_szSessionKey);
-
- m_dwUin = _wtoi(data["loginId"].as_mstring());
- setByte("PhoneReg", 1);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-class CIcqOptionsDlg : public CProtoDlgBase<CIcqProto>
-{
- CCtrlEdit edtUin, edtPassword;
- CCtrlCheck chkUseFriendly, chkHideChats;
- CCtrlButton btnCreate;
- CMStringW wszOldPass;
-
-public:
- CIcqOptionsDlg(CIcqProto *ppro, int iDlgID, bool bFullDlg) :
- CProtoDlgBase<CIcqProto>(ppro, iDlgID),
- edtUin(this, IDC_UIN),
- btnCreate(this, IDC_REGISTER),
- edtPassword(this, IDC_PASSWORD),
- chkHideChats(this, IDC_HIDECHATS),
- chkUseFriendly(this, IDC_USEFRIENDLY)
- {
- btnCreate.OnClick = Callback(this, &CIcqOptionsDlg::onClick_Register);
-
- CreateLink(edtUin, ppro->m_dwUin);
- CreateLink(edtPassword, ppro->m_szPassword);
- if (bFullDlg) {
- CreateLink(chkHideChats, ppro->m_bHideGroupchats);
- CreateLink(chkUseFriendly, ppro->m_bUseFriendly);
- }
-
- wszOldPass = ppro->m_szPassword;
- }
-
- bool OnApply() override
- {
- if (wszOldPass != ptrW(edtPassword.GetText())) {
- m_proto->delSetting(DB_KEY_ATOKEN);
- m_proto->delSetting(DB_KEY_SESSIONKEY);
- m_proto->delSetting("PhoneReg");
- }
- return true;
- }
-
- void onClick_Register(CCtrlButton*)
- {
- CIcqRegistrationDlg dlg(m_proto);
- dlg.SetParent(m_hwnd);
- if (dlg.DoModal()) {
- edtUin.SetInt(m_proto->getDword(DB_KEY_UIN));
- edtPassword.SetText(L"");
- wszOldPass.Empty();
- }
- }
-};
-
-INT_PTR CIcqProto::CreateAccMgrUI(WPARAM, LPARAM hwndParent)
-{
- CIcqOptionsDlg *pDlg = new CIcqOptionsDlg(this, IDD_OPTIONS_ACCMGR, false);
- pDlg->SetParent((HWND)hwndParent);
- pDlg->Create();
- return (INT_PTR)pDlg->GetHwnd();
-}
-
-int CIcqProto::OnOptionsInit(WPARAM wParam, LPARAM)
-{
- OPTIONSDIALOGPAGE odp = {};
- odp.szTitle.w = m_tszUserName;
- odp.flags = ODPF_UNICODE;
- odp.szGroup.w = LPGENW("Network");
-
- odp.position = 1;
-// odp.szTab.w = LPGENW("Account");
- odp.pDialog = new CIcqOptionsDlg(this, IDD_OPTIONS_FULL, true);
- g_plugin.addOptions(wParam, &odp);
- return 0;
-}
diff --git a/protocols/Icq10/src/proto.cpp b/protocols/Icq10/src/proto.cpp
deleted file mode 100644
index 86fb3257fb..0000000000
--- a/protocols/Icq10/src/proto.cpp
+++ /dev/null
@@ -1,479 +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-2019 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<CIcqProto>(aProtoName, aUserName),
- m_arHttpQueue(10),
- m_arOwnIds(1),
- m_arCache(20, NumericKeySortT),
- arMarkReadQueue(10, NumericKeySortT),
- m_evRequestsQueue(CreateEvent(nullptr, FALSE, FALSE, nullptr)),
- m_dwUin(this, DB_KEY_UIN, 0),
- m_szPassword(this, "Password"),
- m_bUseFriendly(this, "UseFriendly", 1),
- m_bHideGroupchats(this, "HideChats", 1)
-{
- // services
- CreateProtoService(PS_CREATEACCMGRUI, &CIcqProto::CreateAccMgrUI);
- CreateProtoService(PS_GETAVATARINFO, &CIcqProto::GetAvatarInfo);
- CreateProtoService(PS_GETMYAVATAR, &CIcqProto::GetAvatar);
- CreateProtoService(PS_GETAVATARCAPS, &CIcqProto::GetAvatarCaps);
- CreateProtoService(PS_SETMYAVATAR, &CIcqProto::SetAvatar);
-
- // events
- HookProtoEvent(ME_CLIST_GROUPCHANGE, &CIcqProto::OnGroupChange);
- HookProtoEvent(ME_DB_EVENT_MARKED_READ, &CIcqProto::OnDbEventRead);
- HookProtoEvent(ME_GC_EVENT, &CIcqProto::GroupchatEventHook);
- HookProtoEvent(ME_GC_BUILDMENU, &CIcqProto::GroupchatMenuHook);
- HookProtoEvent(ME_OPT_INITIALISE, &CIcqProto::OnOptionsInit);
-
- // netlib handle
- 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);
-
- m_hWorkerThread = ForkThreadEx(&CIcqProto::ServerThread, nullptr, nullptr);
-
- InitContactCache();
-}
-
-CIcqProto::~CIcqProto()
-{
- ::CloseHandle(m_evRequestsQueue);
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// OnModulesLoadedEx - performs hook registration
-
-void CIcqProto::OnModulesLoaded()
-{
- GCREGISTER gcr = {};
- gcr.dwFlags = GC_TYPNOTIF | GC_CHANMGR;
- gcr.ptszDispName = m_tszUserName;
- gcr.pszModule = m_szModuleName;
- Chat_Register(&gcr);
-}
-
-void CIcqProto::OnShutdown()
-{
- m_bTerminated = true;
-}
-
-void CIcqProto::OnContactDeleted(MCONTACT hContact)
-{
- CMStringA szId(GetUserId(hContact));
- if (!isChatRoom(hContact))
- m_arCache.remove(FindContactByUIN(atoi(szId)));
-
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/buddylist/removeBuddy");
- pReq << CHAR_PARAM("f", "json") << CHAR_PARAM("aimsid", m_aimsid) << CHAR_PARAM("buddy", szId)
- << CHAR_PARAM("r", pReq->m_reqId) << INT_PARAM("allGroups", 1);
- pReq->flags |= NLHRF_NODUMPSEND;
- Push(pReq);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-void CIcqProto::OnBuildProtoMenu()
-{
- CMenuItem mi(&g_plugin);
- mi.root = Menu_GetProtocolRoot(this);
- mi.flags = CMIF_UNMOVABLE;
-
- // "Bookmarks..."
- mi.pszService = "/UploadGroups";
- CreateProtoService(mi.pszService, &CIcqProto::UploadGroups);
- mi.name.a = LPGEN("Synchronize server groups");
- mi.position = 200001;
- mi.hIcolibItem = Skin_GetIconHandle(SKINICON_OTHER_GROUP);
- m_hUploadGroups = Menu_AddProtoMenuItem(&mi, m_szModuleName);
-
- Menu_ShowItem(m_hUploadGroups, false);
-}
-
-INT_PTR CIcqProto::UploadGroups(WPARAM, LPARAM)
-{
- for (auto &it : AccContacts()) {
- if (isChatRoom(it))
- continue;
-
- CMStringW wszIcqGroup(getMStringW(it, "IcqGroup")), wszMirGroup(db_get_wsm(it, "CList", "Group"));
- if (wszMirGroup.IsEmpty())
- wszMirGroup = L"General";
- if (wszIcqGroup != wszMirGroup)
- MoveContactToGroup(it, wszIcqGroup, wszMirGroup);
- }
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-void CIcqProto::MarkReadTimerProc(HWND hwnd, UINT, UINT_PTR id, DWORD)
-{
- CIcqProto *ppro = (CIcqProto*)id;
-
- mir_cslock lck(ppro->csMarkReadQueue);
- while (ppro->arMarkReadQueue.getCount()) {
- IcqCacheItem *pUser = ppro->arMarkReadQueue[0];
-
- auto *pReq = new AsyncHttpRequest(CONN_RAPI, REQUEST_POST, ICQ_ROBUST_SERVER);
- JSONNode request, params; params.set_name("params");
- params << CHAR_PARAM("sn", ppro->GetUserId(pUser->m_hContact)) << INT64_PARAM("lastRead", ppro->getId(pUser->m_hContact, DB_KEY_LASTMSGID));
- request << CHAR_PARAM("method", "setDlgStateWim") << CHAR_PARAM("reqId", pReq->m_reqId)
- << CHAR_PARAM("authToken", ppro->m_szRToken) << INT_PARAM("clientId", ppro->m_iRClientId) << params;
- pReq->m_szParam = ptrW(json_write(&request));
- ppro->Push(pReq);
-
- ppro->arMarkReadQueue.remove(0);
- }
- KillTimer(hwnd, id);
-}
-
-int CIcqProto::OnDbEventRead(WPARAM, LPARAM hDbEvent)
-{
- MCONTACT hContact = db_event_getContact(hDbEvent);
- if (!hContact)
- return 0;
-
- // filter out only events of my protocol
- const char *szProto = GetContactProto(hContact);
- if (mir_strcmp(szProto, m_szModuleName))
- return 0;
-
- if (m_bOnline) {
- SetTimer(g_hwndHeartbeat, UINT_PTR(this), 200, &CIcqProto::MarkReadTimerProc);
-
- IcqCacheItem *pCache = FindContactByUIN(getDword(hContact, DB_KEY_UIN));
- if (pCache) {
- mir_cslock lck(csMarkReadQueue);
- if (arMarkReadQueue.indexOf(pCache) == -1)
- arMarkReadQueue.insert(pCache);
- }
- }
- return 0;
-}
-
-int CIcqProto::OnGroupChange(WPARAM hContact, LPARAM lParam)
-{
- if (!m_bOnline)
- return 0;
-
- CLISTGROUPCHANGE *pParam = (CLISTGROUPCHANGE*)lParam;
- if (hContact == 0) { // whole group is changed
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/buddylist/");
- pReq << CHAR_PARAM("f", "json") << CHAR_PARAM("aimsid", m_aimsid) << CHAR_PARAM("r", pReq->m_reqId);
- if (pParam->pszOldName == nullptr) {
- pReq->m_szUrl += "addGroup";
- pReq << WCHAR_PARAM("group", pParam->pszNewName);
- }
- else if (pParam->pszNewName == nullptr) {
- pReq->m_szUrl += "removeGroup";
- pReq << WCHAR_PARAM("group", pParam->pszOldName);
- }
- else {
- pReq->m_szUrl += "renameGroup";
- pReq << WCHAR_PARAM("oldGroup", pParam->pszOldName) << WCHAR_PARAM("newGroup", pParam->pszNewName);
- }
- Push(pReq);
- }
- else MoveContactToGroup(hContact, getMStringW(hContact, "IcqGroup"), pParam->pszNewName);
-
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// PS_AddToList - adds a contact to the contact list
-
-MCONTACT CIcqProto::AddToList(int, PROTOSEARCHRESULT *psr)
-{
- if (mir_wstrlen(psr->id.w) == 0)
- return 0;
-
- DWORD dwUin = _wtol(psr->id.w);
-
- MCONTACT hContact = CreateContact(dwUin, true);
- if (psr->nick.w)
- setWString(hContact, "Nick", psr->nick.w);
- if (psr->firstName.w)
- setWString(hContact, "FirstName", psr->firstName.w);
- if (psr->lastName.w)
- setWString(hContact, "LastName", psr->lastName.w);
-
- return hContact;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// PSS_AUTHREQUEST
-
-int CIcqProto::AuthRequest(MCONTACT hContact, const wchar_t* szMessage)
-{
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, ICQ_API_SERVER "/buddylist/addBuddy", &CIcqProto::OnAddBuddy);
- pReq << CHAR_PARAM("f", "json") << CHAR_PARAM("aimsid", m_aimsid) << CHAR_PARAM("r", pReq->m_reqId) << WCHAR_PARAM("authorizationMsg", szMessage)
- << CHAR_PARAM("buddy", GetUserId(hContact)) << CHAR_PARAM("group", "General") << INT_PARAM("preAuthorized", 1);
- pReq->flags |= NLHRF_NODUMPSEND;
- pReq->hContact = hContact;
- Push(pReq);
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// PS_FileAllow - starts a file transfer
-
-HANDLE CIcqProto::FileAllow(MCONTACT, HANDLE, const wchar_t*)
-{
- return nullptr; // Failure
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// PS_FileCancel - cancels a file transfer
-
-int CIcqProto::FileCancel(MCONTACT, HANDLE)
-{
- return 1; // Failure
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// PS_FileDeny - denies a file transfer
-
-int CIcqProto::FileDeny(MCONTACT, HANDLE, const wchar_t*)
-{
- return 1; // Invalid contact
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// PS_FileResume - processes file renaming etc
-
-int CIcqProto::FileResume(HANDLE, int*, const wchar_t**)
-{
- return 1; // Failure
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// GetCaps - return protocol capabilities bits
-
-INT_PTR CIcqProto::GetCaps(int type, MCONTACT)
-{
- INT_PTR nReturn = 0;
-
- switch (type) {
- case PFLAGNUM_1:
- nReturn = PF1_IM | PF1_URL | PF1_AUTHREQ | PF1_BASICSEARCH | PF1_ADDSEARCHRES | /*PF1_SEARCHBYNAME | TODO */
- PF1_VISLIST | PF1_INVISLIST | PF1_MODEMSG | PF1_FILE | PF1_CONTACT | PF1_SERVERCLIST;
- break;
-
- case PFLAGNUM_2:
- return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | PF2_INVISIBLE;
-
- case PFLAGNUM_3:
- return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | PF2_INVISIBLE;
-
- case PFLAGNUM_4:
- nReturn = PF4_FORCEAUTH | PF4_SUPPORTIDLE | PF4_IMSENDOFFLINE | PF4_SUPPORTTYPING | PF4_AVATARS | PF4_SERVERMSGID;
- break;
-
- case PFLAG_UNIQUEIDTEXT:
- return (INT_PTR)Translate("ICQ number or phone");
- }
-
- return nReturn;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// GetInfo - retrieves a contact info
-
-int CIcqProto::GetInfo(MCONTACT hContact, int)
-{
- RetrieveUserInfo(hContact);
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// SearchBasic - searches the contact by UID
-
-HANDLE CIcqProto::SearchBasic(const wchar_t *pszSearch)
-{
- if (!m_bOnline)
- return nullptr;
-
- auto *pReq = new AsyncHttpRequest(CONN_RAPI, REQUEST_POST, ICQ_ROBUST_SERVER, &CIcqProto::OnSearchResults);
-
- JSONNode request, params; params.set_name("params");
- params << WCHAR_PARAM("keyword", pszSearch);
- request << CHAR_PARAM("method", "search") << CHAR_PARAM("reqId", pReq->m_reqId) << CHAR_PARAM("authToken", m_szRToken)
- << INT_PARAM("clientId", m_iRClientId) << params;
- pReq->m_szParam = ptrW(json_write(&request));
- Push(pReq);
- return pReq;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// SendFile - sends a file
-
-HANDLE CIcqProto::SendFile(MCONTACT, const wchar_t*, wchar_t**)
-{
- return nullptr; // Failure
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// PS_SendMessage - sends a message
-
-int CIcqProto::SendMsg(MCONTACT hContact, int, const char *pszSrc)
-{
- CMStringA szUserid(GetUserId(hContact));
- if (szUserid.IsEmpty())
- return 0;
-
- int id = InterlockedIncrement(&m_msgId);
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, ICQ_API_SERVER "/im/sendIM", &CIcqProto::OnSendMessage);
-
- auto *pOwn = new IcqOwnMessage(hContact, id, pReq->m_reqId);
- pReq->pUserInfo = pOwn;
- m_arOwnIds.insert(pOwn);
-
- pReq << CHAR_PARAM("a", m_szAToken) << CHAR_PARAM("aimsid", m_aimsid) << CHAR_PARAM("f", "json") << CHAR_PARAM("k", ICQ_APP_ID)
- << CHAR_PARAM("mentions", "") << CHAR_PARAM("message", pszSrc) << CHAR_PARAM("offlineIM", "true") << CHAR_PARAM("r", pReq->m_reqId)
- << CHAR_PARAM("t", szUserid) << INT_PARAM("ts", time(0));
- Push(pReq);
- return id;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// SendUrl
-
-int CIcqProto::SendUrl(MCONTACT, int, const char*)
-{
- 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 (!IsStatusConnecting(m_iStatus)) {
- m_iStatus = ID_STATUS_CONNECTING;
- ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)iOldStatus, m_iStatus);
-
- if (m_dwUin == 0) {
- debugLogA("Thread ended, UIN/password are not configured");
- ConnectionFailed(LOGINERR_BADUSERID);
- return 0;
- }
-
- if (!getByte("PhoneReg") && mir_wstrlen(m_szPassword) == 0) {
- debugLogA("Thread ended, password is not configured");
- ConnectionFailed(LOGINERR_BADUSERID);
- return 0;
- }
-
- CheckPassword();
- }
- 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)
-{
- return nullptr; // Failure
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// PSR_AWAYMSG - processes received status mode message
-
-int CIcqProto::RecvAwayMsg(MCONTACT, int, PROTORECVEVENT*)
-{
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// PS_SetAwayMsg - sets the away status message
-
-int CIcqProto::SetAwayMsg(int, const wchar_t*)
-{
- return 0; // Success
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// PS_UserIsTyping - sends a UTN notification
-
-int CIcqProto::UserIsTyping(MCONTACT hContact, int type)
-{
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/im/setTyping");
- pReq->flags |= NLHRF_NODUMPSEND;
- pReq << CHAR_PARAM("f", "json") << CHAR_PARAM("aimsid", m_aimsid) << CHAR_PARAM("f", "json")
- << CHAR_PARAM("t", GetUserId(hContact)) << CHAR_PARAM("r", pReq->m_reqId)
- << CHAR_PARAM("typingStatus", (type == PROTOTYPE_SELFTYPING_ON) ? "typing" : "typed");
- Push(pReq);
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// PS_SetApparentMode - sets the visibility status
-
-int CIcqProto::SetApparentMode(MCONTACT, int)
-{
- return 1; // Failure
-}
diff --git a/protocols/Icq10/src/proto.h b/protocols/Icq10/src/proto.h
deleted file mode 100644
index 46bcb56e8f..0000000000
--- a/protocols/Icq10/src/proto.h
+++ /dev/null
@@ -1,263 +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-2019 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"
-
-#define ICQ_APP_ID "ic1nmMjqg7Yu-0hL"
-#define ICQ_API_SERVER "https://api.icq.net"
-#define ICQ_ROBUST_SERVER "https://rapi.icq.net"
-
-enum ChatMenuItems
-{
- IDM_INVITE = 10, IDM_LEAVE
-};
-
-struct IcqCacheItem
-{
- IcqCacheItem(DWORD _uin, MCONTACT _contact) :
- m_uin(_uin),
- m_hContact(_contact)
- {}
-
- DWORD m_uin;
- MCONTACT m_hContact;
- bool m_bInList = false;
-};
-
-struct IcqOwnMessage
-{
- IcqOwnMessage(MCONTACT _hContact, int _msgid, const char *guid)
- : m_hContact(_hContact), m_msgid(_msgid)
- {
- strncpy_s(m_guid, guid, _TRUNCATE);
- }
-
- MCONTACT m_hContact;
- int m_msgid;
- char m_guid[50];
-};
-
-struct IcqConn
-{
- HNETLIBCONN s;
- int lastTs, timeout;
-};
-
-class CIcqProto : public PROTO<CIcqProto>
-{
- friend struct CIcqRegistrationDlg;
- friend class CGroupchatInviteDlg;
-
- bool m_bOnline = false, m_bTerminated = false;
- void CheckAvatarChange(MCONTACT hContact, const JSONNode&);
- void CheckLastId(MCONTACT hContact, const JSONNode&);
- void CheckNickChange(MCONTACT hContact, const JSONNode&);
- MCONTACT CheckOwnMessage(const CMStringA &reqId, const CMStringA &msgId, bool bRemove);
- void CheckPassword(void);
- void ConnectionFailed(int iReason);
- CMStringA GetUserId(MCONTACT);
- void MoveContactToGroup(MCONTACT hContact, const wchar_t *pwszGroup, const wchar_t *pwszNewGroup);
- MCONTACT ParseBuddyInfo(const JSONNode &buddy, MCONTACT hContact = -1);
- void ParseMessage(MCONTACT hContact, __int64 &lastMsgId, const JSONNode &msg);
- void RetrieveUserHistory(MCONTACT, __int64 startMsgId, __int64 endMsgId);
- void RetrieveUserInfo(MCONTACT);
- void SetServerStatus(int iNewStatus);
- void ShutdownSession(void);
- void StartSession(void);
-
- void OnLoggedIn(void);
- void OnLoggedOut(void);
-
- mir_cs csMarkReadQueue;
- LIST<IcqCacheItem> arMarkReadQueue;
- static void CALLBACK MarkReadTimerProc(HWND hwnd, UINT, UINT_PTR id, DWORD);
-
- __int64 getId(MCONTACT hContact, const char *szSetting);
- void setId(MCONTACT hContact, const char *szSetting, __int64 iValue);
-
- void OnAddBuddy(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
- void OnAddClient(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
- void OnCheckPassword(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
- void OnCheckPhone(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
- void OnFetchEvents(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
- void OnGetChatInfo(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
- void OnGetUserHistory(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
- void OnGetUserInfo(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
- void OnLoginViaPhone(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
- void OnNormalizePhone(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
- void OnReceiveAvatar(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
- void OnSearchResults(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
- void OnSendMessage(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
- void OnStartSession(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
- void OnValidateSms(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
-
- void ProcessBuddyList(const JSONNode&);
- void ProcessDiff(const JSONNode&);
- void ProcessEvent(const JSONNode&);
- void ProcessGroupChat(const JSONNode&);
- void ProcessHistData(const JSONNode&);
- void ProcessImState(const JSONNode&);
- void ProcessMyInfo(const JSONNode&);
- void ProcessPresence(const JSONNode&);
- void ProcessTyping(const JSONNode&);
-
- IcqConn m_ConnPool[CONN_LAST];
- CMStringA m_szSessionKey;
- CMStringA m_szAToken;
- CMStringA m_szRToken;
- CMStringA m_fetchBaseURL;
- CMStringA m_aimsid;
- LONG m_msgId = 1;
- int m_iRClientId;
- HGENMENU m_hUploadGroups;
-
- OBJLIST<IcqOwnMessage> m_arOwnIds;
-
- ////////////////////////////////////////////////////////////////////////////////////////
- // group chats
-
- int __cdecl GroupchatEventHook(WPARAM, LPARAM);
- int __cdecl GroupchatMenuHook(WPARAM, LPARAM);
-
- void Chat_ProcessLogMenu(SESSION_INFO *si, int);
- void Chat_SendPrivateMessage(GCHOOK *gch);
-
- void InviteUserToChat(SESSION_INFO *si);
- void LeaveDestroyChat(SESSION_INFO *si);
- void LoadChatInfo(SESSION_INFO *si);
-
- ////////////////////////////////////////////////////////////////////////////////////////
- // http queue
-
- mir_cs m_csHttpQueue;
- HANDLE m_evRequestsQueue;
- LIST<AsyncHttpRequest> m_arHttpQueue;
-
- void CalcHash(AsyncHttpRequest*);
- void ExecuteRequest(AsyncHttpRequest*);
- void Push(MHttpRequest*);
- bool RefreshRobustToken();
-
- ////////////////////////////////////////////////////////////////////////////////////////
- // cache
-
- mir_cs m_csCache;
- OBJLIST<IcqCacheItem> m_arCache;
-
- void InitContactCache(void);
- IcqCacheItem* FindContactByUIN(DWORD);
- MCONTACT CreateContact(DWORD dwUin, bool bTemporary);
-
- void GetAvatarFileName(MCONTACT hContact, wchar_t *pszDest, size_t cbLen);
-
- ////////////////////////////////////////////////////////////////////////////////////////
- // threads
-
- HANDLE m_hWorkerThread;
- void __cdecl ServerThread(void*);
-
- HANDLE m_hPollThread;
- void __cdecl PollThread(void*);
-
- ////////////////////////////////////////////////////////////////////////////////////////
- // services
-
- INT_PTR __cdecl GetAvatar(WPARAM, LPARAM);
- INT_PTR __cdecl GetAvatarCaps(WPARAM, LPARAM);
- INT_PTR __cdecl GetAvatarInfo(WPARAM, LPARAM);
- INT_PTR __cdecl SetAvatar(WPARAM, LPARAM);
-
- INT_PTR __cdecl CreateAccMgrUI(WPARAM, LPARAM);
- INT_PTR __cdecl UploadGroups(WPARAM, LPARAM);
-
- ////////////////////////////////////////////////////////////////////////////////////////
- // events
-
- int __cdecl OnGroupChange(WPARAM, LPARAM);
- int __cdecl OnDbEventRead(WPARAM, LPARAM);
- int __cdecl OnOptionsInit(WPARAM, LPARAM);
-
- ////////////////////////////////////////////////////////////////////////////////////////
- // PROTO_INTERFACE
-
- MCONTACT AddToList( int flags, PROTOSEARCHRESULT *psr) 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 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 OnBuildProtoMenu(void) override;
- void OnContactDeleted(MCONTACT) override;
- void OnModulesLoaded() override;
- void OnShutdown() override;
-
-public:
- CIcqProto(const char*, const wchar_t*);
- ~CIcqProto();
-
- CMOption<DWORD> m_dwUin; // our own id
- CMOption<wchar_t*> m_szPassword; // password, if present
- CMOption<BYTE> m_bUseFriendly; // use friendly names instead of old icq nicks
- CMOption<BYTE> m_bHideGroupchats; // don't pop up group chat windows on startup
-};
-
-struct CMPlugin : public ACCPROTOPLUGIN<CIcqProto>
-{
- CMPlugin();
-
- int Load() override;
- int Unload() override;
-};
-
-#endif
diff --git a/protocols/Icq10/src/resource.h b/protocols/Icq10/src/resource.h
deleted file mode 100644
index beeac3d899..0000000000
--- a/protocols/Icq10/src/resource.h
+++ /dev/null
@@ -1,29 +0,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by w:\miranda-ng\protocols\Icq10\res\resources.rc
-//
-#define IDD_OPTIONS_FULL 101
-#define IDD_OPTIONS_ACCMGR 102
-#define IDD_GROUPCHAT_INVITE 103
-#define IDD_REGISTER 105
-#define IDC_PASSWORD 1001
-#define IDC_UIN 1002
-#define IDC_USEFRIENDLY 1003
-#define IDC_USEFRIENDLY2 1004
-#define IDC_HIDECHATS 1004
-#define IDC_REGISTER 1005
-#define IDC_PHONE 1006
-#define IDC_CLIST 1007
-#define IDC_SENDSMS 1008
-#define IDC_CODE 1009
-
-// Next default values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 107
-#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1010
-#define _APS_NEXT_SYMED_VALUE 101
-#endif
-#endif
diff --git a/protocols/Icq10/src/server.cpp b/protocols/Icq10/src/server.cpp
deleted file mode 100644
index d77daf4075..0000000000
--- a/protocols/Icq10/src/server.cpp
+++ /dev/null
@@ -1,859 +0,0 @@
-// -----------------------------------------------------------------------------
-// ICQ plugin for Miranda NG
-// -----------------------------------------------------------------------------
-// Copyright © 2018-19 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, "libeay32.lib")
-
-void CIcqProto::CheckAvatarChange(MCONTACT hContact, const JSONNode &ev)
-{
- CMStringW wszIconId(ev["iconId"].as_mstring());
- CMStringW oldIconID(getMStringW(hContact, "IconId"));
- if (wszIconId != oldIconID) {
- setWString(hContact, "IconId", wszIconId);
-
- CMStringA szUrl(ev["buddyIcon"].as_mstring());
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, szUrl, &CIcqProto::OnReceiveAvatar);
- pReq->hContact = hContact;
- Push(pReq);
- }
-}
-
-void CIcqProto::CheckLastId(MCONTACT hContact, const JSONNode &ev)
-{
- __int64 msgId = _wtoi64(ev["histMsgId"].as_mstring());
- __int64 lastId = getId(hContact, DB_KEY_LASTMSGID);
- if (msgId > lastId)
- setId(hContact, DB_KEY_LASTMSGID, msgId);
-}
-
-void CIcqProto::CheckNickChange(MCONTACT hContact, const JSONNode &ev)
-{
- // if we already set a nick, ignore change when friendly names aren't used
- if (!m_bUseFriendly && !getMStringW(hContact, "Nick").IsEmpty())
- return;
-
- CMStringW wszNick = ev["friendly"].as_mstring();
- if (m_bUseFriendly || !wszNick.IsEmpty())
- setWString(hContact, "Nick", wszNick);
-}
-
-MCONTACT CIcqProto::CheckOwnMessage(const CMStringA &reqId, const CMStringA &msgId, bool bRemove)
-{
- for (auto &own: m_arOwnIds) {
- if (!mir_strcmp(reqId, own->m_guid)) {
- ProtoBroadcastAck(own->m_hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)own->m_msgid, (LPARAM)msgId.c_str());
- MCONTACT ret = own->m_hContact;
- if (bRemove)
- m_arOwnIds.remove(m_arOwnIds.indexOf(&own));
- return ret;
- }
- }
- return 0;
-}
-
-void CIcqProto::CheckPassword()
-{
- char mirVer[100];
- Miranda_GetVersionText(mirVer, _countof(mirVer));
-
- m_szAToken = getMStringA(DB_KEY_ATOKEN);
- m_iRClientId = getDword(DB_KEY_RCLIENTID);
- m_szSessionKey = getMStringA(DB_KEY_SESSIONKEY);
- if (m_szAToken.IsEmpty() || m_szSessionKey.IsEmpty()) {
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, "https://api.login.icq.net/auth/clientLogin", &CIcqProto::OnCheckPassword);
- pReq << CHAR_PARAM("clientName", "Miranda NG") << CHAR_PARAM("clientVersion", mirVer) << CHAR_PARAM("devId", ICQ_APP_ID)
- << CHAR_PARAM("f", "json") << CHAR_PARAM("tokenType", "longTerm") << INT_PARAM("s", m_dwUin) << WCHAR_PARAM("pwd", m_szPassword);
- pReq->flags |= NLHRF_NODUMPSEND;
- Push(pReq);
- }
- else StartSession();
-}
-
-void CIcqProto::ConnectionFailed(int iReason)
-{
- debugLogA("ConnectionFailed -> reason %d", iReason);
-
- ProtoBroadcastAck(0, ACKTYPE_LOGIN, ACKRESULT_FAILED, nullptr, iReason);
- ShutdownSession();
-}
-
-void CIcqProto::MoveContactToGroup(MCONTACT hContact, const wchar_t *pwszGroup, const wchar_t *pwszNewGroup)
-{
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/buddylist/moveBuddy");
- pReq << CHAR_PARAM("f", "json") << CHAR_PARAM("aimsid", m_aimsid) << CHAR_PARAM("r", pReq->m_reqId)
- << CHAR_PARAM("buddy", GetUserId(hContact)) << WCHAR_PARAM("group", pwszGroup) << WCHAR_PARAM("newGroup", pwszNewGroup);
- Push(pReq);
-}
-
-void CIcqProto::OnLoggedIn()
-{
- debugLogA("CIcqProto::OnLoggedIn");
- m_bOnline = true;
- SetServerStatus(m_iDesiredStatus);
- RetrieveUserInfo(0);
-}
-
-void CIcqProto::OnLoggedOut()
-{
- debugLogA("CIcqProto::OnLoggedOut");
- m_bOnline = false;
-
- ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, ID_STATUS_OFFLINE);
- m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
-
- setAllContactStatuses(ID_STATUS_OFFLINE, false);
-}
-
-MCONTACT CIcqProto::ParseBuddyInfo(const JSONNode &buddy, MCONTACT hContact)
-{
- // user chat?
- if (buddy["userType"].as_mstring() == "interop") {
- CMStringW wszChatId(buddy["aimId"].as_mstring());
- CMStringW wszChatName(buddy["friendly"].as_mstring());
-
- SESSION_INFO *si = Chat_NewSession(GCW_CHATROOM, m_szModuleName, wszChatId, wszChatName);
- if (si == nullptr)
- return INVALID_CONTACT_ID;
-
- Chat_AddGroup(si, TranslateT("admin"));
- Chat_AddGroup(si, TranslateT("member"));
- Chat_Control(m_szModuleName, wszChatId, m_bHideGroupchats ? WINDOW_HIDDEN : SESSION_INITDONE);
- Chat_Control(m_szModuleName, wszChatId, SESSION_ONLINE);
- return si->hContact;
- }
-
- DWORD dwUin = _wtol(buddy["aimId"].as_mstring());
-
- if (hContact == -1) {
- hContact = CreateContact(dwUin, false);
- FindContactByUIN(dwUin)->m_bInList = true;
- }
-
- CMStringW str(buddy["state"].as_mstring());
- setDword(hContact, "Status", StatusFromString(str));
-
- const JSONNode &profile = buddy["profile"];
- if (profile) {
- str = profile["firstName"].as_mstring();
- if (!str.IsEmpty())
- setWString(hContact, "FirstName", str);
-
- str = profile["lastName"].as_mstring();
- if (!str.IsEmpty())
- setWString(hContact, "LastName", str);
-
- str = profile["friendlyName"].as_mstring();
- if (!str.IsEmpty())
- if (!m_bUseFriendly || getMStringW("Nick").IsEmpty())
- setWString(hContact, "Nick", str);
-
- time_t birthDate = profile["birthDate"].as_int();
- if (birthDate != 0) {
- struct tm *timeinfo = localtime(&birthDate);
- if (timeinfo != nullptr) {
- setWord(hContact, "BirthDay", timeinfo->tm_mday);
- setWord(hContact, "BirthMonth", timeinfo->tm_mon+1);
- setWord(hContact, "BirthYear", timeinfo->tm_year+1900);
- }
- }
-
- str = profile["gender"].as_mstring();
- if (!str.IsEmpty()) {
- if (str == "male")
- setByte(hContact, "Gender", 'M');
- else if (str == "female")
- setByte(hContact, "Gender", 'F');
- }
-
- for (auto &it : profile["homeAddress"]) {
- str = it["city"].as_mstring();
- if (!str.IsEmpty())
- setWString(hContact, "City", str);
-
- str = it["state"].as_mstring();
- if (!str.IsEmpty())
- setWString(hContact, "State", str);
-
- str = it["country"].as_mstring();
- if (!str.IsEmpty())
- setWString(hContact, "Country", str);
- }
- }
-
- CheckNickChange(hContact, buddy);
-
- int lastLogin = buddy["lastseen"].as_int();
- if (lastLogin)
- setDword(hContact, "LastSeen", lastLogin);
-
- str = buddy["statusMsg"].as_mstring();
- if (str.IsEmpty())
- db_unset(hContact, "CList", "StatusMsg");
- else
- db_set_ws(hContact, "CList", "StatusMsg", str);
-
- CheckAvatarChange(hContact, buddy);
- return hContact;
-}
-
-void CIcqProto::ParseMessage(MCONTACT hContact, __int64 &lastMsgId, const JSONNode &it)
-{
- CMStringA szMsgId(it["msgId"].as_mstring());
- __int64 msgId = _atoi64(szMsgId);
- if (msgId > lastMsgId)
- lastMsgId = msgId;
-
- CMStringW type(it["mediaType"].as_mstring());
- if (type != "text" && !type.IsEmpty())
- return;
-
- CMStringW wszText(it["text"].as_mstring());
- if (isChatRoom(hContact)) {
- CMStringA reqId(it["reqId"].as_mstring());
- CheckOwnMessage(reqId, szMsgId, true);
-
- CMStringW wszSender(it["chat"]["sender"].as_mstring());
- CMStringW wszChatId(getMStringW(hContact, "ChatRoomID"));
-
- GCEVENT gce = { m_szModuleName, wszChatId, GC_EVENT_MESSAGE };
- gce.dwFlags = GCEF_ADDTOLOG;
- gce.ptszUID = wszSender;
- gce.ptszText = wszText;
- gce.time = it["time"].as_int();
- gce.bIsMe = _wtoi(wszSender) == (int)m_dwUin;
- Chat_Event(&gce);
- }
- else {
- // skip own messages, just set the server msgid
- CMStringA reqId(it["reqId"].as_mstring());
- if (CheckOwnMessage(reqId, szMsgId, true))
- return;
-
- // ignore duplicates
- MEVENT hDbEvent = db_event_getById(m_szModuleName, szMsgId);
- if (hDbEvent != 0)
- return;
-
- bool bIsOutgoing = it["outgoing"].as_bool();
- ptrA szUtf(mir_utf8encodeW(wszText));
-
- PROTORECVEVENT pre = {};
- pre.flags = (bIsOutgoing) ? PREF_SENT : 0;
- pre.szMsgId = szMsgId;
- pre.timestamp = it["time"].as_int();
- pre.szMessage = szUtf;
- ProtoChainRecvMsg(hContact, &pre);
- }
-}
-
-bool CIcqProto::RefreshRobustToken()
-{
- if (!m_szRToken.IsEmpty())
- return true;
-
- bool bRet = false;
- auto *tmp = new AsyncHttpRequest(CONN_RAPI, REQUEST_POST, ICQ_ROBUST_SERVER "/genToken");
-
- time_t ts = time(0);
- tmp << CHAR_PARAM("a", m_szAToken) << CHAR_PARAM("k", ICQ_APP_ID)
- << CHAR_PARAM("nonce", CMStringA(FORMAT, "%d-%d", ts, rand() % 10)) << INT_PARAM("ts", ts);
- CalcHash(tmp);
- tmp->flags |= NLHRF_PERSISTENT;
- tmp->nlc = m_ConnPool[CONN_RAPI].s;
- tmp->dataLength = tmp->m_szParam.GetLength();
- tmp->pData = tmp->m_szParam.Detach();
- tmp->szUrl = tmp->m_szUrl.GetBuffer();
-
- CMStringA szAgent(FORMAT, "%d Mail.ru Windows ICQ (version 10.0.1999)", DWORD(m_dwUin));
- tmp->AddHeader("User-Agent", szAgent);
-
- NETLIBHTTPREQUEST *reply = Netlib_HttpTransaction(m_hNetlibUser, tmp);
- if (reply != nullptr) {
- m_ConnPool[CONN_RAPI].s = reply->nlc;
-
- RobustReply result(reply);
- if (result.error() == 20000) {
- const JSONNode &results = result.results();
- m_szRToken = results["authToken"].as_mstring();
-
- // now add this token
- auto *add = new AsyncHttpRequest(CONN_RAPI, REQUEST_POST, ICQ_ROBUST_SERVER, &CIcqProto::OnAddClient);
- JSONNode request, params; params.set_name("params");
- request << CHAR_PARAM("method", "addClient") << CHAR_PARAM("reqId", add->m_reqId) << CHAR_PARAM("authToken", m_szRToken) << params;
- add->m_szParam = ptrW(json_write(&request));
- add->pUserInfo = &bRet;
- ExecuteRequest(add);
- }
-
- Netlib_FreeHttpRequest(reply);
- }
- else m_ConnPool[CONN_RAPI].s = nullptr;
-
- delete tmp;
- return bRet;
-}
-
-void CIcqProto::RetrieveUserInfo(MCONTACT hContact)
-{
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/presence/get", &CIcqProto::OnGetUserInfo);
- pReq->flags |= NLHRF_NODUMPSEND;
- pReq->hContact = hContact;
- pReq << CHAR_PARAM("f", "json") << CHAR_PARAM("aimsid", m_aimsid) << INT_PARAM("mdir", 1) << CHAR_PARAM("t", GetUserId(hContact));
- Push(pReq);
-}
-
-void CIcqProto::RetrieveUserHistory(MCONTACT hContact, __int64 startMsgId, __int64 endMsgId)
-{
- if (startMsgId == 0)
- startMsgId = -1;
- if (endMsgId == 0)
- endMsgId = -1;
-
- if (startMsgId >= endMsgId)
- return;
-
- auto *pReq = new AsyncHttpRequest(CONN_RAPI, REQUEST_POST, ICQ_ROBUST_SERVER, &CIcqProto::OnGetUserHistory);
- pReq->flags |= NLHRF_NODUMPSEND;
- pReq->hContact = hContact;
-
- JSONNode request, params; params.set_name("params");
- params << CHAR_PARAM("sn", GetUserId(hContact)) << INT64_PARAM("fromMsgId", startMsgId);
- if (endMsgId != -1)
- params << INT64_PARAM("tillMsgId", endMsgId);
- params << INT_PARAM("count", 1000) << CHAR_PARAM("aimSid", m_aimsid) << CHAR_PARAM("patchVersion", "1") << CHAR_PARAM("language", "ru-ru");
- request << CHAR_PARAM("method", "getHistory") << CHAR_PARAM("reqId", pReq->m_reqId) << CHAR_PARAM("authToken", m_szRToken)
- << INT_PARAM("clientId", m_iRClientId) << params;
- pReq->m_szParam = ptrW(json_write(&request));
- Push(pReq);
-}
-
-void CIcqProto::SetServerStatus(int iStatus)
-{
- const char *szStatus = "online";
- int invisible = 0;
-
- switch (iStatus) {
- case ID_STATUS_OFFLINE: szStatus = "offline"; break;
- case ID_STATUS_NA: szStatus = "occupied"; break;
- case ID_STATUS_AWAY:
- case ID_STATUS_DND: szStatus = "away"; break;
- case ID_STATUS_INVISIBLE:
- invisible = 1;
- }
-
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/presence/setState");
- pReq->flags |= NLHRF_NODUMPSEND;
- pReq << CHAR_PARAM("f", "json") << CHAR_PARAM("aimsid", m_aimsid) << CHAR_PARAM("r", pReq->m_reqId)
- << CHAR_PARAM("view", szStatus) << INT_PARAM("invisible", invisible);
- Push(pReq);
-
- 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);
-
- OnLoggedOut();
-
- for (auto &it : m_ConnPool)
- if (it.s)
- Netlib_Shutdown(it.s);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-#define CAPS "094613504c7f11d18222444553540000,094613514c7f11d18222444553540000,094613534c7f11d18222444553540000,094613544c7f11d18222444553540000,094613594c7f11d18222444553540000,0946135b4c7f11d18222444553540000,0946135a4c7f11d18222444553540000"
-#define EVENTS "myInfo,presence,buddylist,typing,dataIM,userAddedToBuddyList,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::StartSession()
-{
- 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(CONN_MAIN, REQUEST_POST, ICQ_API_SERVER "/aim/startSession", &CIcqProto::OnStartSession);
-
- pReq << CHAR_PARAM("a", m_szAToken) << INT_PARAM("activeTimeout", 180) << CHAR_PARAM("assertCaps", CAPS)
- << INT_PARAM("buildNumber", __BUILD_NUM) << 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", ICQ_APP_ID) << INT_PARAM("mobile", 0) << CHAR_PARAM("nonce", nonce) << CHAR_PARAM("r", pReq->m_reqId)
- << INT_PARAM("rawMsg", 0) << INT_PARAM("sessionTimeout", 7776000) << INT_PARAM("ts", ts) << CHAR_PARAM("view", "online");
-
- CalcHash(pReq);
-
- Push(pReq);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-void CIcqProto::OnAddBuddy(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
-{
- JsonReply root(pReply);
- if (root.error() == 200) {
- RetrieveUserInfo(pReq->hContact);
- db_unset(pReq->hContact, "CList", "NotOnList");
- }
-}
-
-void CIcqProto::OnAddClient(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
-{
- bool *pRet = (bool*)pReq->pUserInfo;
-
- RobustReply reply(pReply);
- if (reply.error() != 20000) {
- *pRet = false;
- return;
- }
-
- const JSONNode &results = reply.results();
- m_iRClientId = results["clientId"].as_int();
- setDword(DB_KEY_RCLIENTID, m_iRClientId);
- *pRet = true;
-}
-
-void CIcqProto::OnCheckPassword(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*)
-{
- JsonReply root(pReply);
- switch (root.error()) {
- case 200:
- break;
-
- case 330:
- case 440:
- ConnectionFailed(LOGINERR_WRONGPASSWORD);
- return;
-
- default:
- ConnectionFailed(LOGINERR_WRONGPROTOCOL);
- return;
- }
-
- JSONNode &data = root.data();
- m_szAToken = data["token"]["a"].as_mstring();
- m_szAToken = ptrA(mir_urlDecode(m_szAToken));
- setString(DB_KEY_ATOKEN, m_szAToken);
-
- CMStringA szSessionSecret = data["sessionSecret"].as_mstring();
- CMStringA szPassTemp = m_szPassword;
-
- unsigned int len;
- BYTE hashOut[MIR_SHA256_HASH_SIZE];
- HMAC(EVP_sha256(), szPassTemp, szPassTemp.GetLength(), (BYTE*)szSessionSecret.c_str(), szSessionSecret.GetLength(), hashOut, &len);
- m_szSessionKey = ptrA(mir_base64_encode(hashOut, sizeof(hashOut)));
- setString(DB_KEY_SESSIONKEY, m_szSessionKey);
-
- CMStringA szUin = data["loginId"].as_mstring();
- if (szUin)
- m_dwUin = atoi(szUin);
-
- StartSession();
-}
-
-void CIcqProto::OnGetUserHistory(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
-{
- RobustReply root(pReply);
- if (root.error() != 20000)
- return;
-
- __int64 lastMsgId = getId(pReq->hContact, DB_KEY_LASTMSGID);
-
- const JSONNode &results = root.results();
- for (auto &it : results["messages"])
- ParseMessage(pReq->hContact, lastMsgId, it);
-
- setId(pReq->hContact, DB_KEY_LASTMSGID, lastMsgId);
-}
-
-void CIcqProto::OnGetUserInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
-{
- JsonReply root(pReply);
- if (root.error() != 200) {
- ProtoBroadcastAck(pReq->hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, nullptr);
- return;
- }
-
- const JSONNode &data = root.data();
- for (auto &it : data["users"])
- ParseBuddyInfo(it, pReq->hContact);
-
- ProtoBroadcastAck(pReq->hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, nullptr);
-}
-
-void CIcqProto::OnStartSession(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*)
-{
- JsonReply root(pReply);
- switch (root.error()) {
- case 200:
- break;
-
- case 401:
- if (root.detail() == 1002) { // session expired
- delSetting(DB_KEY_ATOKEN);
- delSetting(DB_KEY_SESSIONKEY);
- CheckPassword();
- }
- else ConnectionFailed(LOGINERR_WRONGPASSWORD);
- return;
-
- default:
- ConnectionFailed(LOGINERR_WRONGPROTOCOL);
- return;
- }
-
- JSONNode &data = root.data();
- m_fetchBaseURL = data["fetchBaseURL"].as_mstring();
- m_aimsid = data["aimsid"].as_mstring();
-
- OnLoggedIn();
-
- for (auto &it : data["events"])
- ProcessEvent(it);
-
- if (m_hPollThread == nullptr)
- m_hPollThread = ForkThreadEx(&CIcqProto::PollThread, 0, 0);
-}
-
-void CIcqProto::OnReceiveAvatar(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
-{
- PROTO_AVATAR_INFORMATION ai = {};
- ai.hContact = pReq->hContact;
-
- if (pReply->resultCode != 200 || pReply->pData == nullptr) {
-LBL_Error:
- ProtoBroadcastAck(pReq->hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, HANDLE(&ai), 0);
- return;
- }
-
- const wchar_t *pwszExtension;
- ai.format = ProtoGetBufferFormat(pReply->pData, &pwszExtension);
- setByte(pReq->hContact, "AvatarType", ai.format);
- GetAvatarFileName(pReq->hContact, ai.filename, _countof(ai.filename));
-
- FILE *out = _wfopen(ai.filename, L"wb");
- if (out == nullptr)
- goto LBL_Error;
-
- fwrite(pReply->pData, pReply->dataLength, 1, out);
- fclose(out);
-
- if (pReq->hContact != 0) {
- ProtoBroadcastAck(pReq->hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, HANDLE(&ai), 0);
- debugLogW(L"Broadcast new avatar: %s", ai.filename);
- }
- else CallService(MS_AV_REPORTMYAVATARCHANGED, (WPARAM)m_szModuleName, 0);
-}
-
-void CIcqProto::OnSearchResults(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
-{
- RobustReply root(pReply);
- if (root.error() != 20000) {
- ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_FAILED, (HANDLE)pReq, 0);
- return;
- }
-
- const JSONNode &results = root.results();
-
- PROTOSEARCHRESULT psr = {};
- psr.cbSize = sizeof(psr);
- psr.flags = PSR_UNICODE;
- for (auto &it : results["data"]) {
- const JSONNode &anketa = it["anketa"];
-
- CMStringW wszId = it["sn"].as_mstring();
- CMStringW wszNick = anketa["nickname"].as_mstring();
- CMStringW wszFirst = anketa["firstName"].as_mstring();
- CMStringW wszLast = anketa["lastName"].as_mstring();
-
- psr.id.w = wszId.GetBuffer();
- psr.nick.w = wszNick.GetBuffer();
- psr.firstName.w = wszFirst.GetBuffer();
- psr.lastName.w = wszLast.GetBuffer();
- ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)pReq, LPARAM(&psr));
- }
-
- ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)pReq);
-}
-
-void CIcqProto::OnSendMessage(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
-{
- IcqOwnMessage *ownMsg = (IcqOwnMessage*)pReq->pUserInfo;
-
- JsonReply root(pReply);
- if (root.error() != 200) {
- ProtoBroadcastAck(ownMsg->m_hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)ownMsg->m_msgid, 0);
- for (auto &it : m_arOwnIds) {
- if (it == ownMsg) {
- m_arOwnIds.remove(m_arOwnIds.indexOf(&it));
- break;
- }
- }
- }
-
- const JSONNode &data = root.data();
- CMStringA reqId(root.requestId());
- CMStringA msgId(data["histMsgId"].as_mstring());
- CheckOwnMessage(reqId, msgId, false);
- CheckLastId(ownMsg->m_hContact, data);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-void CIcqProto::ProcessBuddyList(const JSONNode &ev)
-{
- bool bEnableMenu = false;
-
- for (auto &it : ev["groups"]) {
- CMStringW szGroup = it["name"].as_mstring();
- bool bCreated = false;
-
- for (auto &buddy : it["buddies"]) {
- MCONTACT hContact = ParseBuddyInfo(buddy);
- if (hContact == INVALID_CONTACT_ID)
- continue;
-
- setWString(hContact, "IcqGroup", szGroup);
-
- CMStringW mirGroup(db_get_sm(hContact, "CList", "Group"));
- if (mirGroup != szGroup)
- bEnableMenu = true;
-
- if (mirGroup.IsEmpty()) {
- if (!bCreated) {
- Clist_GroupCreate(0, szGroup);
- bCreated = true;
- }
-
- db_set_ws(hContact, "CList", "Group", szGroup);
- }
- }
- }
-
- if (bEnableMenu)
- Menu_ShowItem(m_hUploadGroups, true);
-
- for (auto &it : m_arCache)
- if (!it->m_bInList)
- db_set_b(it->m_hContact, "CList", "NotOnList", 1);
-}
-
-void CIcqProto::ProcessDiff(const JSONNode &ev)
-{
- for (auto &block : ev) {
- CMStringW szType = block["type"].as_mstring();
- if (szType != "updated" && szType != "created")
- continue;
-
- for (auto &it : block["data"]) {
- CMStringW szGroup = it["name"].as_mstring();
- bool bCreated = false;
-
- for (auto &buddy : it["buddies"]) {
- MCONTACT hContact = ParseBuddyInfo(buddy);
- if (hContact == INVALID_CONTACT_ID)
- continue;
-
- setWString(hContact, "IcqGroup", szGroup);
-
- if (db_get_sm(hContact, "CList", "Group").IsEmpty()) {
- if (!bCreated) {
- Clist_GroupCreate(0, szGroup);
- bCreated = true;
- }
-
- db_set_ws(hContact, "CList", "Group", szGroup);
- }
- }
- }
- }
-}
-
-void CIcqProto::ProcessEvent(const JSONNode &ev)
-{
- const JSONNode &pData = ev["eventData"];
- CMStringW szType = ev["type"].as_mstring();
- if (szType == L"buddylist")
- ProcessBuddyList(pData);
- else if (szType == L"diff")
- ProcessDiff(pData);
- else if (szType == L"histDlgState")
- ProcessHistData(pData);
- else if (szType == L"imState")
- ProcessImState(pData);
- else if (szType == L"mchat")
- ProcessGroupChat(pData);
- else if (szType == L"myInfo")
- ProcessMyInfo(pData);
- else if (szType == L"presence")
- ProcessPresence(pData);
- else if (szType == L"typing")
- ProcessTyping(pData);
-}
-
-void CIcqProto::ProcessHistData(const JSONNode &ev)
-{
- MCONTACT hContact;
-
- CMStringW wszId(ev["sn"].as_mstring());
- if (IsChat(wszId)) {
- SESSION_INFO *si = g_chatApi.SM_FindSession(wszId, m_szModuleName);
- if (si == nullptr)
- return;
-
- hContact = si->hContact;
-
- if (si->arUsers.getCount() == 0) {
- __int64 srvInfoVer = _wtoi64(ev["mchatState"]["infoVersion"].as_mstring());
- __int64 srvMembersVer = _wtoi64(ev["mchatState"]["membersVersion"].as_mstring());
- if (srvInfoVer != getId(hContact, "InfoVersion") || srvMembersVer != getId(hContact, "MembersVersion")) {
- auto *pReq = new AsyncHttpRequest(CONN_RAPI, REQUEST_POST, ICQ_ROBUST_SERVER, &CIcqProto::OnGetChatInfo);
- JSONNode request, params; params.set_name("params");
- params << WCHAR_PARAM("sn", wszId) << INT_PARAM("memberLimit", 100) << CHAR_PARAM("aimSid", m_aimsid);
- request << CHAR_PARAM("method", "getChatInfo") << CHAR_PARAM("reqId", pReq->m_reqId) << CHAR_PARAM("authToken", m_szRToken) << INT_PARAM("clientId", m_iRClientId) << params;
- pReq->m_szParam = ptrW(json_write(&request));
- pReq->pUserInfo = si;
- Push(pReq);
- }
- else LoadChatInfo(si);
- }
- }
- else hContact = CreateContact(_wtol(wszId), true);
-
- __int64 lastMsgId = getId(hContact, DB_KEY_LASTMSGID);
- __int64 srvLastId = _wtoi64(ev["lastMsgId"].as_mstring());
- __int64 srvUnreadId = _wtoi64(ev["yours"]["lastRead"].as_mstring());
-
- // on first start we don't load history not to create dups
- if (lastMsgId == 0)
- setId(hContact, DB_KEY_LASTMSGID, srvLastId);
- // or load missing messages if any
- else if (ev["unreadCnt"].as_int() > 0)
- RetrieveUserHistory(hContact, min(srvUnreadId, lastMsgId), srvLastId);
-
- for (auto &it : ev["tail"]["messages"])
- ParseMessage(hContact, lastMsgId, it);
- setId(hContact, DB_KEY_LASTMSGID, lastMsgId);
-}
-
-void CIcqProto::ProcessImState(const JSONNode &ev)
-{
- for (auto &it : ev["imStates"]) {
- if (it["state"].as_mstring() != L"sent")
- continue;
-
- CMStringA reqId(it["sendReqId"].as_mstring());
- CMStringA msgId(it["histMsgId"].as_mstring());
- MCONTACT hContact = CheckOwnMessage(reqId, msgId, false);
- if (hContact)
- CheckLastId(hContact, ev);
- }
-}
-
-void CIcqProto::ProcessMyInfo(const JSONNode &ev)
-{
- CheckNickChange(0, ev);
- CheckAvatarChange(0, ev);
-}
-
-void CIcqProto::ProcessPresence(const JSONNode &ev)
-{
- DWORD dwUin = _wtol(ev["aimId"].as_mstring());
-
- IcqCacheItem *pCache = FindContactByUIN(dwUin);
- if (pCache) {
- setDword(pCache->m_hContact, "Status", StatusFromString(ev["state"].as_mstring()));
-
- CheckNickChange(pCache->m_hContact, ev);
- CheckAvatarChange(pCache->m_hContact, ev);
- }
-}
-
-void CIcqProto::ProcessTyping(const JSONNode &ev)
-{
- DWORD dwUin = _wtol(ev["aimId"].as_mstring());
- CMStringW wszStatus = ev["typingStatus"].as_mstring();
-
- IcqCacheItem *pCache = FindContactByUIN(dwUin);
- if (pCache) {
- if (wszStatus == "typing")
- CallService(MS_PROTO_CONTACTISTYPING, pCache->m_hContact, 60);
- else
- CallService(MS_PROTO_CONTACTISTYPING, pCache->m_hContact, PROTOTYPE_CONTACTTYPING_OFF);
- }
-}
-
-void CIcqProto::OnFetchEvents(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*)
-{
- JsonReply root(pReply);
- if (root.error() != 200) {
- ShutdownSession();
- return;
- }
-
- JSONNode &data = root.data();
- m_fetchBaseURL = data["fetchBaseURL"].as_mstring();
-
- for (auto &it : data["events"])
- ProcessEvent(it);
-}
-
-void __cdecl CIcqProto::PollThread(void*)
-{
- debugLogA("Polling thread started");
- bool bFirst = true;
-
- while (m_bOnline) {
- CMStringA szUrl = m_fetchBaseURL;
- if (bFirst) {
- bFirst = false;
- szUrl.Append("&first=1");
- }
- else szUrl.Append("&timeout=25000");
-
- auto *pReq = new AsyncHttpRequest(CONN_FETCH, REQUEST_GET, szUrl, &CIcqProto::OnFetchEvents);
- if (!bFirst)
- pReq->timeout = 62000;
- ExecuteRequest(pReq);
- }
-
- debugLogA("Polling thread ended");
- m_hPollThread = nullptr;
-}
diff --git a/protocols/Icq10/src/stdafx.cxx b/protocols/Icq10/src/stdafx.cxx
deleted file mode 100644
index 66afad80f1..0000000000
--- a/protocols/Icq10/src/stdafx.cxx
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
-Copyright (C) 2012-19 Miranda NG team (https://miranda-ng.org)
-
-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 version 2
-of the License.
-
-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"
diff --git a/protocols/Icq10/src/stdafx.h b/protocols/Icq10/src/stdafx.h
deleted file mode 100644
index 929854990c..0000000000
--- a/protocols/Icq10/src/stdafx.h
+++ /dev/null
@@ -1,95 +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
-// Copyright © 2012-2019 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:
-//
-// Includes all header files that should be precompiled to speed up compilation.
-// -----------------------------------------------------------------------------
-
-#pragma once
-
-// Windows includes
-#include <windows.h>
-
-// Standard includes
-#include <stdio.h>
-#include <time.h>
-#include <io.h>
-#include <malloc.h>
-#include <direct.h>
-#include <fcntl.h>
-#include <process.h>
-
-// Miranda IM SDK includes
-#include <newpluginapi.h> // This must be included first
-#include <m_avatars.h>
-#include <m_chat_int.h>
-#include <m_clist.h>
-#include <m_database.h>
-#include <m_gui.h>
-#include <m_idle.h>
-#include <m_icolib.h>
-#include <m_ignore.h>
-#include <m_json.h>
-#include <m_langpack.h>
-#include <m_message.h>
-#include <m_netlib.h>
-#include <m_protocols.h>
-#include <m_protosvc.h>
-#include <m_options.h>
-#include <m_popup.h>
-#include <m_skin.h>
-#include <m_system.h>
-#include <m_timezones.h>
-#include <m_userinfo.h>
-#include <m_utils.h>
-#include <win2k.h>
-
-#include <openssl/evp.h>
-#include <openssl/hmac.h>
-#include <openssl/rand.h>
-#include <openssl/sha.h>
-
-// Project resources
-#include "resource.h"
-
-// ICQ plugin includes
-#include "version.h"
-
-#define MODULENAME "ICQ"
-
-#define DB_KEY_UIN "UIN"
-#define DB_KEY_ATOKEN "AToken"
-#define DB_KEY_RCLIENTID "RClientID"
-#define DB_KEY_LASTMSGID "LastMsgId"
-#define DB_KEY_SESSIONKEY "SessionKey"
-
-#include "http.h"
-#include "proto.h"
-
-bool IsChat(const CMStringW &aimid);
-
-int StatusFromString(const CMStringW&);
-
-extern HWND g_hwndHeartbeat; \ No newline at end of file
diff --git a/protocols/Icq10/src/utils.cpp b/protocols/Icq10/src/utils.cpp
deleted file mode 100644
index 6cf6219322..0000000000
--- a/protocols/Icq10/src/utils.cpp
+++ /dev/null
@@ -1,239 +0,0 @@
-// -----------------------------------------------------------------------------
-// ICQ plugin for Miranda NG
-// -----------------------------------------------------------------------------
-// Copyright © 2018-19 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::InitContactCache()
-{
- mir_cslock l(m_csCache);
- for (auto &it : AccContacts())
- if (!isChatRoom(it))
- m_arCache.insert(new IcqCacheItem(getDword(it, DB_KEY_UIN), it));
-}
-
-IcqCacheItem* CIcqProto::FindContactByUIN(DWORD dwUin)
-{
- mir_cslock l(m_csCache);
- return m_arCache.find((IcqCacheItem*)&dwUin);
-}
-
-MCONTACT CIcqProto::CreateContact(DWORD dwUin, bool bTemporary)
-{
- auto *pCache = FindContactByUIN(dwUin);
- if (pCache != nullptr)
- return pCache->m_hContact;
-
- MCONTACT hContact = db_add_contact();
- Proto_AddToContact(hContact, m_szModuleName);
- setDword(hContact, DB_KEY_UIN, dwUin);
- pCache = new IcqCacheItem(dwUin, hContact);
- {
- mir_cslock l(m_csCache);
- m_arCache.insert(pCache);
- }
- RetrieveUserInfo(hContact);
-
- if (bTemporary)
- db_set_b(hContact, "CList", "NotOnList", 1);
-
- return hContact;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-void CIcqProto::CalcHash(AsyncHttpRequest *pReq)
-{
- CMStringA hashData(FORMAT, "POST&%s&%s", ptrA(mir_urlEncode(pReq->m_szUrl)), ptrA(mir_urlEncode(pReq->m_szParam)));
- unsigned int len;
- BYTE hashOut[MIR_SHA256_HASH_SIZE];
- HMAC(EVP_sha256(), m_szSessionKey, m_szSessionKey.GetLength(), (BYTE*)hashData.c_str(), hashData.GetLength(), hashOut, &len);
- pReq << CHAR_PARAM("sig_sha256", ptrA(mir_base64_encode(hashOut, sizeof(hashOut))));
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Avatars
-
-void CIcqProto::GetAvatarFileName(MCONTACT hContact, wchar_t* pszDest, size_t cbLen)
-{
- int tPathLen = mir_snwprintf(pszDest, cbLen, L"%s\\%S", VARSW(L"%miranda_avatarcache%"), m_szModuleName);
-
- DWORD dwAttributes = GetFileAttributes(pszDest);
- if (dwAttributes == 0xffffffff || (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
- CreateDirectoryTreeW(pszDest);
-
- pszDest[tPathLen++] = '\\';
-
- CMStringW wszFileName(getMStringW(hContact, "IconId"));
- const wchar_t* szFileType = ProtoGetAvatarExtension(getByte(hContact, "AvatarType", PA_FORMAT_PNG));
- mir_snwprintf(pszDest + tPathLen, MAX_PATH - tPathLen, L"%s%s", wszFileName.c_str(), szFileType);
-}
-
-INT_PTR __cdecl CIcqProto::GetAvatar(WPARAM wParam, LPARAM lParam)
-{
- wchar_t *buf = (wchar_t*)wParam;
- int size = (int)lParam;
- if (buf == nullptr || size <= 0)
- return -1;
-
- GetAvatarFileName(0, buf, size);
- return 0;
-}
-
-INT_PTR __cdecl CIcqProto::GetAvatarCaps(WPARAM wParam, LPARAM lParam)
-{
- switch (wParam) {
- case AF_MAXSIZE:
- ((POINT*)lParam)->x = -1;
- ((POINT*)lParam)->y = -1;
- return 0;
-
- case AF_FORMATSUPPORTED: // nobody
- return 1;
-
- case AF_DELAYAFTERFAIL:
- return 10 * 60 * 1000;
-
- case AF_ENABLED:
- case AF_FETCHIFPROTONOTVISIBLE:
- case AF_FETCHIFCONTACTOFFLINE:
- return 1;
- }
- return 0;
-}
-
-INT_PTR __cdecl CIcqProto::GetAvatarInfo(WPARAM, LPARAM lParam)
-{
- PROTO_AVATAR_INFORMATION* pai = (PROTO_AVATAR_INFORMATION*)lParam;
-
- ptrW szIconId(getWStringA(pai->hContact, "IconId"));
- if (szIconId == nullptr) {
- debugLogA("No avatar");
- return GAIR_NOAVATAR;
- }
-
- GetAvatarFileName(pai->hContact, pai->filename, _countof(pai->filename));
- pai->format = getByte(pai->hContact, "AvatarType", 0);
-
- if (::_waccess(pai->filename, 0) == 0)
- return GAIR_SUCCESS;
-
- debugLogA("No avatar");
- return GAIR_NOAVATAR;
-}
-
-INT_PTR __cdecl CIcqProto::SetAvatar(WPARAM, LPARAM lParam)
-{
- wchar_t* pwszFileName = (wchar_t*)lParam;
-
- wchar_t wszOldName[MAX_PATH];
- GetAvatarFileName(0, wszOldName, _countof(wszOldName));
- _wremove(wszOldName);
-
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, ICQ_API_SERVER "/expressions/upload");
- pReq->m_szUrl.AppendFormat("?f=json&aimsid=%s&r=%s&type=largeBuddyIcon", ptrA(mir_urlEncode(m_aimsid.c_str())), pReq->m_reqId);
-
- if (pwszFileName == nullptr)
- delSetting("AvatarHash");
- else {
- int fileId = _wopen(pwszFileName, _O_RDONLY | _O_BINARY, _S_IREAD);
- if (fileId < 0) {
- delete pReq;
- return 1;
- }
-
- unsigned dwSize = (unsigned)_filelengthi64(fileId);
- char* pData = (char*)mir_alloc(dwSize);
- if (pData == nullptr) {
- _close(fileId);
- delete pReq;
- return 2;
- }
-
- _read(fileId, pData, dwSize);
- _close(fileId);
-
- pReq->pData = pData;
- pReq->dataLength = dwSize;
-
- int iAvatarType = ProtoGetBufferFormat(pData);
- if (iAvatarType == PA_FORMAT_UNKNOWN) {
- delete pReq;
- delete pData;
- return 3;
- }
-
- pReq->AddHeader("Content-Type", _T2A(ProtoGetAvatarMimeType(iAvatarType)));
- }
- Push(pReq);
-
- return 0; // TODO
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-CMStringA CIcqProto::GetUserId(MCONTACT hContact)
-{
- if (isChatRoom(hContact))
- return getMStringA(hContact, "ChatRoomID");
-
- return CMStringA(FORMAT, "%d", getDword(hContact, DB_KEY_UIN));
-}
-
-bool IsChat(const CMStringW &aimid)
-{
- return aimid.Right(11) == "@chat.agent";
-}
-
-int StatusFromString(const CMStringW &wszStatus)
-{
- if (wszStatus == "online")
- return ID_STATUS_ONLINE;
- if (wszStatus == "n/a")
- return ID_STATUS_NA;
- if (wszStatus == "away")
- return ID_STATUS_AWAY;
- if (wszStatus == "occupied")
- return ID_STATUS_OCCUPIED;
- if (wszStatus == "dnd")
- return ID_STATUS_DND;
-
- return ID_STATUS_OFFLINE;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-__int64 CIcqProto::getId(MCONTACT hContact, const char *szSetting)
-{
- DBVARIANT dbv;
- dbv.type = DBVT_BLOB;
- if (db_get(hContact, m_szModuleName, szSetting, &dbv))
- return 0;
-
- __int64 result = (dbv.cpbVal == sizeof(__int64)) ? *(__int64*)dbv.pbVal : 0;
- db_free(&dbv);
- return result;
-}
-
-void CIcqProto::setId(MCONTACT hContact, const char *szSetting, __int64 iValue)
-{
- __int64 oldVal = getId(hContact, szSetting);
- if (oldVal != iValue)
- db_set_blob(hContact, m_szModuleName, szSetting, &iValue, sizeof(iValue));
-}
diff --git a/protocols/Icq10/src/version.h b/protocols/Icq10/src/version.h
deleted file mode 100644
index fbf8c9aca9..0000000000
--- a/protocols/Icq10/src/version.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#define __MAJOR_VERSION 0
-#define __MINOR_VERSION 95
-#define __RELEASE_NUM 10
-#define __BUILD_NUM 1
-
-#include <stdver.h>
-
-#define __PLUGIN_NAME "ICQ/2018 protocol"
-#define __FILENAME "ICQ.dll"
-#define __DESCRIPTION "ICQ protocol support for Miranda NG."
-#define __AUTHOR "George Hazan"
-#define __AUTHORWEB "https://miranda-ng.org/p/ICQ/"
-#define __COPYRIGHT "© 2018-19 George Hazan"