diff options
author | George Hazan <ghazan@miranda.im> | 2019-01-16 18:06:52 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2019-01-16 18:06:52 +0300 |
commit | aa514a9f95c8cd95c01952250f7cdb670a66af9a (patch) | |
tree | ecb84e10fc3af008e1a8ac9027f1b526634c8d65 /protocols/Icq10/src | |
parent | 4f0a4ae4724fdfe65f63ee41dc1790ccbb0668f7 (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.cpp | 303 | ||||
-rw-r--r-- | protocols/Icq10/src/http.cpp | 289 | ||||
-rw-r--r-- | protocols/Icq10/src/http.h | 51 | ||||
-rw-r--r-- | protocols/Icq10/src/main.cpp | 77 | ||||
-rw-r--r-- | protocols/Icq10/src/options.cpp | 226 | ||||
-rw-r--r-- | protocols/Icq10/src/proto.cpp | 479 | ||||
-rw-r--r-- | protocols/Icq10/src/proto.h | 263 | ||||
-rw-r--r-- | protocols/Icq10/src/resource.h | 29 | ||||
-rw-r--r-- | protocols/Icq10/src/server.cpp | 859 | ||||
-rw-r--r-- | protocols/Icq10/src/stdafx.cxx | 18 | ||||
-rw-r--r-- | protocols/Icq10/src/stdafx.h | 95 | ||||
-rw-r--r-- | protocols/Icq10/src/utils.cpp | 239 | ||||
-rw-r--r-- | protocols/Icq10/src/version.h | 13 |
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" |