summaryrefslogtreecommitdiff
path: root/protocols/ICQ-WIM
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2019-02-04 19:40:10 +0300
committerGeorge Hazan <ghazan@miranda.im>2019-02-04 19:40:10 +0300
commit66f476ebe438f7d4ccfb3c88cb8c423f22e08d4d (patch)
treee723e937ea347d955e9b1da19e704d74512d2a84 /protocols/ICQ-WIM
parentae5912910a16d90b61b36b85cf9ca39fc1097bf2 (diff)
ICQ10:
- fixes #1821 (ICQ10: add Ignore list); - code reordering;
Diffstat (limited to 'protocols/ICQ-WIM')
-rw-r--r--protocols/ICQ-WIM/res/resources.rc23
-rw-r--r--protocols/ICQ-WIM/src/ignore.cpp216
-rw-r--r--protocols/ICQ-WIM/src/main.cpp2
-rw-r--r--protocols/ICQ-WIM/src/poll.cpp253
-rw-r--r--protocols/ICQ-WIM/src/proto.cpp9
-rw-r--r--protocols/ICQ-WIM/src/proto.h11
-rw-r--r--protocols/ICQ-WIM/src/resource.h4
-rw-r--r--protocols/ICQ-WIM/src/server.cpp283
8 files changed, 513 insertions, 288 deletions
diff --git a/protocols/ICQ-WIM/res/resources.rc b/protocols/ICQ-WIM/res/resources.rc
index 1ebad6ea51..a5644efe4d 100644
--- a/protocols/ICQ-WIM/res/resources.rc
+++ b/protocols/ICQ-WIM/res/resources.rc
@@ -49,7 +49,8 @@ BEGIN
EDITTEXT IDC_EMAIL,68,27,106,12,ES_AUTOHSCROLL
RTEXT "Password:",IDC_STATIC,12,43,51,8
EDITTEXT IDC_PASSWORD,68,42,106,12,ES_PASSWORD | ES_AUTOHSCROLL
- CONTROL "Do not open chat windows on creation",IDC_HIDECHATS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,61,285,10
+ CONTROL "Do not open chat windows on creation",IDC_HIDECHATS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,61,285,10
PUSHBUTTON "Sign in/sign up using phone",IDC_REGISTER,163,79,142,14
END
@@ -97,6 +98,16 @@ BEGIN
EDITTEXT IDC_LASTSEEN,74,32,139,10,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
END
+IDD_EDITIGNORE DIALOGEX 0, 0, 270, 160
+STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT
+CAPTION "Ignore list editor"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,5,261,136
+ DEFPUSHBUTTON "OK",IDOK,217,144,50,14
+END
+
/////////////////////////////////////////////////////////////////////////////
//
@@ -130,6 +141,11 @@ BEGIN
IDD_INFO_ICQ, DIALOG
BEGIN
END
+
+ IDD_EDITIGNORE, DIALOG
+ BEGIN
+ RIGHTMARGIN, 208
+ END
END
#endif // APSTUDIO_INVOKED
@@ -164,6 +180,11 @@ BEGIN
0
END
+IDD_EDITIGNORE AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
diff --git a/protocols/ICQ-WIM/src/ignore.cpp b/protocols/ICQ-WIM/src/ignore.cpp
new file mode 100644
index 0000000000..a7617506d6
--- /dev/null
+++ b/protocols/ICQ-WIM/src/ignore.cpp
@@ -0,0 +1,216 @@
+// -----------------------------------------------------------------------------
+// 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.
+// -----------------------------------------------------------------------------
+// Server permissions
+
+#include "stdafx.h"
+
+class CEditIgnoreListDlg : public CIcqDlgBase
+{
+ typedef CIcqDlgBase CSuper;
+
+ CCtrlListView m_list;
+
+public:
+ CEditIgnoreListDlg(CIcqProto *ppro) :
+ CSuper(ppro, IDD_EDITIGNORE),
+ m_list(this, IDC_LIST)
+ {
+ m_list.OnClick = Callback(this, &CEditIgnoreListDlg::list_OnClick);
+ }
+
+ bool OnInitDialog() override
+ {
+ HIMAGELIST hImageList = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 2, 0);
+ ImageList_AddIcon(hImageList, IcoLib_GetIcon(Skin_GetIconName(SKINICON_OTHER_DELETE)));
+ m_list.SetImageList(hImageList, LVSIL_SMALL);
+
+ m_list.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_SUBITEMIMAGES | LVS_EX_GRIDLINES);
+
+ RECT rc;
+ GetClientRect(m_list.GetHwnd(), &rc);
+
+ LVCOLUMN lvc = {};
+ lvc.mask = LVCF_WIDTH;
+ lvc.cx = rc.right;
+ m_list.InsertColumn(0, &lvc);
+
+ auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/preference/getPermitDeny", &CIcqProto::OnRefreshEditIgnore);
+ pReq->flags |= NLHRF_NODUMPHEADERS;
+ pReq->pUserInfo = this;
+ pReq << CHAR_PARAM("f", "json") << CHAR_PARAM("aimsid", m_proto->m_aimsid) << CHAR_PARAM("r", pReq->m_reqId);
+ m_proto->ExecuteRequest(pReq);
+
+ Utils_RestoreWindowPosition(m_hwnd, 0, m_proto->m_szModuleName, "editIgnore_");
+ return true;
+ }
+
+ void OnDestroy() override
+ {
+ m_proto->m_pdlgEditIgnore = nullptr;
+ Utils_SaveWindowPosition(m_hwnd, 0, m_proto->m_szModuleName, "editIgnore_");
+ }
+
+ INT_PTR DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam) override
+ {
+ INT_PTR ret = CSuper::DlgProc(uMsg, wParam, lParam);
+ if (uMsg == WM_SIZE) {
+ RECT rc;
+ GetClientRect(m_list.GetHeader(), &rc);
+ m_list.SetColumnWidth(0, rc.right - rc.left);
+ }
+
+ return ret;
+ }
+
+ int Resizer(UTILRESIZECONTROL *urc) override
+ {
+ switch (urc->wId) {
+ case IDC_LIST:
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT;
+ }
+ return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM;
+ }
+
+ void Refresh(const JSONNode &pData)
+ {
+ LVITEM lvi = {};
+ lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
+
+ for (auto &it : pData["ignores"]) {
+ CMStringW wszId(it.as_mstring());
+ auto *p = m_proto->FindContactByUIN(_wtoi(wszId));
+ if (p) {
+ lvi.pszText = Clist_GetContactDisplayName(p->m_hContact);
+ lvi.lParam = p->m_hContact;
+ }
+ else {
+ lvi.pszText = wszId.GetBuffer();
+ lvi.lParam = -1;
+ }
+
+ m_list.InsertItem(&lvi);
+ lvi.iItem++;
+ }
+ }
+
+ void list_OnClick(CCtrlListView::TEventInfo*)
+ {
+ LVHITTESTINFO hti;
+ hti.pt.x = (short)LOWORD(GetMessagePos());
+ hti.pt.y = (short)HIWORD(GetMessagePos());
+ ScreenToClient(m_list.GetHwnd(), &hti.pt);
+ if (m_list.SubItemHitTest(&hti) == -1)
+ return;
+
+ if (!(hti.flags & LVHT_ONITEMICON))
+ return;
+
+ bool bCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
+ if (!bCtrl)
+ if (IDYES != MessageBoxW(m_hwnd, TranslateT("Do you really want to remove it from ignore list?"), m_proto->m_tszUserName, MB_YESNO))
+ return;
+
+ CMStringA userId;
+ INT_PTR data = m_list.GetItemData(hti.iItem);
+ if (data == -1) {
+ wchar_t buf[100];
+ m_list.GetItemText(hti.iItem, 0, buf, _countof(buf));
+ userId = buf;
+ }
+ else userId = m_proto->GetUserId((MCONTACT)data);
+
+ m_proto->SetPermitDeny(userId, true);
+ m_list.DeleteItem(hti.iItem);
+ }
+};
+
+void CIcqProto::OnRefreshEditIgnore(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
+{
+ JsonReply root(pReply);
+ if (root.error() != 200)
+ return;
+
+ auto *pDlg = (CEditIgnoreListDlg*)pReq->pUserInfo;
+ pDlg->Refresh(root.data());
+}
+
+INT_PTR CIcqProto::EditIgnoreList(WPARAM, LPARAM)
+{
+ if (m_pdlgEditIgnore == nullptr) {
+ m_pdlgEditIgnore = new CEditIgnoreListDlg(this);
+ m_pdlgEditIgnore->Show();
+ }
+ else SetForegroundWindow(m_pdlgEditIgnore->GetHwnd());
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CIcqProto::GetPermitDeny()
+{
+ auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/preference/getPermitDeny", &CIcqProto::OnGetPermitDeny);
+ pReq->flags |= NLHRF_NODUMPHEADERS;
+ pReq << CHAR_PARAM("f", "json") << CHAR_PARAM("aimsid", m_aimsid) << CHAR_PARAM("r", pReq->m_reqId);
+ Push(pReq);
+}
+
+void CIcqProto::OnGetPermitDeny(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*)
+{
+ JsonReply root(pReply);
+ if (root.error() == 200)
+ ProcessPermissions(root.data());
+}
+
+void CIcqProto::ProcessPermissions(const JSONNode &ev)
+{
+ for (auto &it : m_arCache)
+ it->m_iApparentMode = 0;
+
+ for (auto &it : ev["allows"]) {
+ auto *p = FindContactByUIN(_wtoi(it.as_mstring()));
+ if (p)
+ p->m_iApparentMode = ID_STATUS_ONLINE;
+ }
+
+ for (auto &it : ev["ignores"]) {
+ auto *p = FindContactByUIN(_wtoi(it.as_mstring()));
+ if (p)
+ p->m_iApparentMode = ID_STATUS_OFFLINE;
+ }
+
+ for (auto &it: m_arCache) {
+ int oldMode = getDword(it->m_hContact, "ApparentMode");
+ if (oldMode != it->m_iApparentMode) {
+ if (it->m_iApparentMode == 0)
+ delSetting(it->m_hContact, "ApparentMode");
+ else
+ setDword(it->m_hContact, "ApparentMode", it->m_iApparentMode);
+ }
+ }
+}
+
+void CIcqProto::SetPermitDeny(const CMStringA &userId, bool bAllow)
+{
+ auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/preference/setPermitDeny");
+ pReq << CHAR_PARAM("f", "json") << CHAR_PARAM("aimsid", m_aimsid) << CHAR_PARAM("r", pReq->m_reqId)
+ << CHAR_PARAM((bAllow) ? "pdIgnoreRemove" : "pdIgnore", userId);
+ Push(pReq);
+}
diff --git a/protocols/ICQ-WIM/src/main.cpp b/protocols/ICQ-WIM/src/main.cpp
index 6667a90ea1..c0428cb7d0 100644
--- a/protocols/ICQ-WIM/src/main.cpp
+++ b/protocols/ICQ-WIM/src/main.cpp
@@ -66,7 +66,7 @@ static INT_PTR ICQPermitDeny(WPARAM hContact, LPARAM, LPARAM bAllow)
{
CIcqProto *proto = CMPlugin::getInstance(hContact);
if (proto)
- proto->SetPermitDeny(hContact, bAllow != 0);
+ proto->SetPermitDeny(proto->GetUserId(hContact), bAllow != 0);
return 0;
}
diff --git a/protocols/ICQ-WIM/src/poll.cpp b/protocols/ICQ-WIM/src/poll.cpp
new file mode 100644
index 0000000000..3d987b334b
--- /dev/null
+++ b/protocols/ICQ-WIM/src/poll.cpp
@@ -0,0 +1,253 @@
+// -----------------------------------------------------------------------------
+// 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.
+// -----------------------------------------------------------------------------
+// Long-poll thread and its item handlers
+
+#include "stdafx.h"
+
+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"permitDeny")
+ ProcessPermissions(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);
+ if (lastMsgId == 0) {
+ lastMsgId = _wtoi64(ev["yours"]["lastRead"].as_mstring());
+ setId(hContact, DB_KEY_LASTMSGID, lastMsgId);
+ }
+
+ // or load missing messages if any
+ if (ev["unreadCnt"].as_int() > 0)
+ RetrieveUserHistory(hContact, lastMsgId);
+
+ // check remote read
+ if (g_bMessageState) {
+ __int64 srvRemoteRead = _wtoi64(ev["theirs"]["lastRead"].as_mstring());
+ __int64 lastRemoteRead = getId(hContact, DB_KEY_REMOTEREAD);
+ if (srvRemoteRead > lastRemoteRead) {
+ setId(hContact, DB_KEY_REMOTEREAD, srvRemoteRead);
+
+ MessageReadData data(time(0), MRD_TYPE_READTIME);
+ CallService(MS_MESSAGESTATE_UPDATE, hContact, (LPARAM)&data);
+ }
+ }
+}
+
+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)
+{
+ Json2string(0, ev, "friendly", "Nick");
+ 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()));
+
+ Json2string(pCache->m_hContact, ev, "friendly", "Nick");
+ 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");
+ m_bFirstBos = true;
+
+ while (m_bOnline) {
+ CMStringA szUrl = m_fetchBaseURL;
+ if (m_bFirstBos)
+ szUrl.Append("&first=1");
+ else
+ szUrl.Append("&timeout=25000");
+
+ auto *pReq = new AsyncHttpRequest(CONN_FETCH, REQUEST_GET, szUrl, &CIcqProto::OnFetchEvents);
+ if (!m_bFirstBos)
+ pReq->timeout = 62000;
+ ExecuteRequest(pReq);
+
+ m_bFirstBos = false;
+ }
+
+ debugLogA("Polling thread ended");
+ m_hPollThread = nullptr;
+}
diff --git a/protocols/ICQ-WIM/src/proto.cpp b/protocols/ICQ-WIM/src/proto.cpp
index 8047bd52bd..38d65bf345 100644
--- a/protocols/ICQ-WIM/src/proto.cpp
+++ b/protocols/ICQ-WIM/src/proto.cpp
@@ -97,6 +97,8 @@ void CIcqProto::OnModulesLoaded()
void CIcqProto::OnShutdown()
{
+ UI_SAFE_CLOSE(m_pdlgEditIgnore);
+
m_bTerminated = true;
}
@@ -129,6 +131,13 @@ void CIcqProto::OnBuildProtoMenu()
mi.hIcolibItem = Skin_GetIconHandle(SKINICON_OTHER_GROUP);
m_hUploadGroups = Menu_AddProtoMenuItem(&mi, m_szModuleName);
+ mi.pszService = "/EditIgnore";
+ CreateProtoService(mi.pszService, &CIcqProto::EditIgnoreList);
+ mi.name.a = LPGEN("Edit ignore list");
+ mi.position++;
+ mi.hIcolibItem = Skin_GetIconHandle(SKINICON_OTHER_USERDETAILS);
+ Menu_AddProtoMenuItem(&mi, m_szModuleName);
+
Menu_ShowItem(m_hUploadGroups, false);
}
diff --git a/protocols/ICQ-WIM/src/proto.h b/protocols/ICQ-WIM/src/proto.h
index 98017ed5a3..7fe801df0b 100644
--- a/protocols/ICQ-WIM/src/proto.h
+++ b/protocols/ICQ-WIM/src/proto.h
@@ -37,6 +37,8 @@
#define ICQ_API_SERVER "https://api.icq.net"
#define ICQ_ROBUST_SERVER "https://rapi.icq.net"
+typedef CProtoDlgBase<CIcqProto> CIcqDlgBase;
+
enum ChatMenuItems
{
IDM_INVITE = 10, IDM_LEAVE
@@ -129,12 +131,13 @@ class CIcqProto : public PROTO<CIcqProto>
{
friend struct CIcqRegistrationDlg;
friend class CGroupchatInviteDlg;
+ friend class CEditIgnoreListDlg;
bool m_bOnline, m_bTerminated, m_bFirstBos;
MCONTACT CheckOwnMessage(const CMStringA &reqId, const CMStringA &msgId, bool bRemove);
void CheckPassword(void);
void ConnectionFailed(int iReason, int iErrorCode = 0);
- void GetPermitDeny(void);
+ void GetPermitDeny();
void MoveContactToGroup(MCONTACT hContact, const wchar_t *pwszGroup, const wchar_t *pwszNewGroup);
void RetrieveUserHistory(MCONTACT, __int64 startMsgId, __int64 endMsgId = -1);
void RetrieveUserInfo(MCONTACT);
@@ -173,6 +176,7 @@ class CIcqProto : public PROTO<CIcqProto>
void OnLoginViaPhone(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
void OnNormalizePhone(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
void OnReceiveAvatar(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
+ void OnRefreshEditIgnore(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
void OnSearchResults(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
void OnSendMessage(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
void OnStartSession(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
@@ -202,6 +206,8 @@ class CIcqProto : public PROTO<CIcqProto>
mir_cs m_csOwnIds;
OBJLIST<IcqOwnMessage> m_arOwnIds;
+ CIcqDlgBase *m_pdlgEditIgnore;
+
////////////////////////////////////////////////////////////////////////////////////////
// group chats
@@ -257,6 +263,7 @@ class CIcqProto : public PROTO<CIcqProto>
INT_PTR __cdecl SetAvatar(WPARAM, LPARAM);
INT_PTR __cdecl CreateAccMgrUI(WPARAM, LPARAM);
+ INT_PTR __cdecl EditIgnoreList(WPARAM, LPARAM);
INT_PTR __cdecl UploadGroups(WPARAM, LPARAM);
////////////////////////////////////////////////////////////////////////////////////////
@@ -308,7 +315,7 @@ public:
CMStringA GetUserId(MCONTACT);
int __cdecl OnContactMenu(WPARAM, LPARAM);
- void SetPermitDeny(MCONTACT hContact, bool bAllow);
+ void SetPermitDeny(const CMStringA &userId, bool bAllow);
};
struct CMPlugin : public ACCPROTOPLUGIN<CIcqProto>
diff --git a/protocols/ICQ-WIM/src/resource.h b/protocols/ICQ-WIM/src/resource.h
index 7af9c260d7..b38a314f8f 100644
--- a/protocols/ICQ-WIM/src/resource.h
+++ b/protocols/ICQ-WIM/src/resource.h
@@ -7,6 +7,7 @@
#define IDD_GROUPCHAT_INVITE 103
#define IDD_INFO_ICQ 104
#define IDD_REGISTER 105
+#define IDD_EDITIGNORE 106
#define IDC_PASSWORD 1001
#define IDC_UIN 1002
#define IDC_UIN2 1003
@@ -23,6 +24,7 @@
#define IDC_MEMBERSINCE 1013
#define IDC_LASTSEEN 1014
#define IDC_EMAIL 1015
+#define IDC_LIST 1016
// Next default values for new objects
//
@@ -30,7 +32,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 108
#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1016
+#define _APS_NEXT_CONTROL_VALUE 1017
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
diff --git a/protocols/ICQ-WIM/src/server.cpp b/protocols/ICQ-WIM/src/server.cpp
index 12a4befbd5..9f7a36ef15 100644
--- a/protocols/ICQ-WIM/src/server.cpp
+++ b/protocols/ICQ-WIM/src/server.cpp
@@ -128,13 +128,6 @@ void CIcqProto::ConnectionFailed(int iReason, int iErrorCode)
ShutdownSession();
}
-void CIcqProto::GetPermitDeny()
-{
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/preference/getPermitDeny", &CIcqProto::OnGetPermitDeny);
- pReq << CHAR_PARAM("f", "json") << CHAR_PARAM("aimsid", m_aimsid) << CHAR_PARAM("r", pReq->m_reqId);
- Push(pReq);
-}
-
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");
@@ -391,14 +384,6 @@ void CIcqProto::RetrieveUserHistory(MCONTACT hContact, __int64 startMsgId, __int
Push(pReq);
}
-void CIcqProto::SetPermitDeny(MCONTACT hContact, bool bAllow)
-{
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/preference/setPermitDeny");
- pReq << CHAR_PARAM("f", "json") << CHAR_PARAM("aimsid", m_aimsid) << CHAR_PARAM("r", pReq->m_reqId)
- << CHAR_PARAM((bAllow) ? "pdIgnoreRemove" : "pdIgnore", GetUserId(hContact));
- Push(pReq);
-}
-
void CIcqProto::SetServerStatus(int iStatus)
{
const char *szStatus = "online";
@@ -609,13 +594,6 @@ void CIcqProto::OnFileInit(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pOld)
ProtoBroadcastAck(pTransfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_DATA, pTransfer, (LPARAM)&pTransfer->pfts);
}
-void CIcqProto::OnGetPermitDeny(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*)
-{
- JsonReply root(pReply);
- if (root.error() == 200)
- ProcessPermissions(root.data());
-}
-
void CIcqProto::OnGetUserHistory(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
{
RobustReply root(pReply);
@@ -759,264 +737,3 @@ void CIcqProto::OnSendMessage(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
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"permitDeny")
- ProcessPermissions(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);
- if (lastMsgId == 0) {
- lastMsgId = _wtoi64(ev["yours"]["lastRead"].as_mstring());
- setId(hContact, DB_KEY_LASTMSGID, lastMsgId);
- }
-
- // or load missing messages if any
- if (ev["unreadCnt"].as_int() > 0)
- RetrieveUserHistory(hContact, lastMsgId);
-
- // check remote read
- if (g_bMessageState) {
- __int64 srvRemoteRead = _wtoi64(ev["theirs"]["lastRead"].as_mstring());
- __int64 lastRemoteRead = getId(hContact, DB_KEY_REMOTEREAD);
- if (srvRemoteRead > lastRemoteRead) {
- setId(hContact, DB_KEY_REMOTEREAD, srvRemoteRead);
-
- MessageReadData data(time(0), MRD_TYPE_READTIME);
- CallService(MS_MESSAGESTATE_UPDATE, hContact, (LPARAM)&data);
- }
- }
-}
-
-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)
-{
- Json2string(0, ev, "friendly", "Nick");
- CheckAvatarChange(0, ev);
-}
-
-void CIcqProto::ProcessPermissions(const JSONNode &ev)
-{
- for (auto &it : m_arCache)
- it->m_iApparentMode = 0;
-
- for (auto &it : ev["allows"]) {
- auto *p = FindContactByUIN(_wtoi(it.as_mstring()));
- if (p)
- p->m_iApparentMode = ID_STATUS_ONLINE;
- }
-
- for (auto &it : ev["ignores"]) {
- auto *p = FindContactByUIN(_wtoi(it.as_mstring()));
- if (p)
- p->m_iApparentMode = ID_STATUS_OFFLINE;
- }
-
- for (auto &it: m_arCache) {
- int oldMode = getDword(it->m_hContact, "ApparentMode");
- if (oldMode != it->m_iApparentMode) {
- if (it->m_iApparentMode == 0)
- delSetting(it->m_hContact, "ApparentMode");
- else
- setDword(it->m_hContact, "ApparentMode", it->m_iApparentMode);
- }
- }
-}
-
-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()));
-
- Json2string(pCache->m_hContact, ev, "friendly", "Nick");
- 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");
- m_bFirstBos = true;
-
- while (m_bOnline) {
- CMStringA szUrl = m_fetchBaseURL;
- if (m_bFirstBos)
- szUrl.Append("&first=1");
- else
- szUrl.Append("&timeout=25000");
-
- auto *pReq = new AsyncHttpRequest(CONN_FETCH, REQUEST_GET, szUrl, &CIcqProto::OnFetchEvents);
- if (!m_bFirstBos)
- pReq->timeout = 62000;
- ExecuteRequest(pReq);
-
- m_bFirstBos = false;
- }
-
- debugLogA("Polling thread ended");
- m_hPollThread = nullptr;
-}