diff options
-rw-r--r-- | protocols/ICQ-WIM/res/resources.rc | 23 | ||||
-rw-r--r-- | protocols/ICQ-WIM/src/ignore.cpp | 216 | ||||
-rw-r--r-- | protocols/ICQ-WIM/src/main.cpp | 2 | ||||
-rw-r--r-- | protocols/ICQ-WIM/src/poll.cpp | 253 | ||||
-rw-r--r-- | protocols/ICQ-WIM/src/proto.cpp | 9 | ||||
-rw-r--r-- | protocols/ICQ-WIM/src/proto.h | 11 | ||||
-rw-r--r-- | protocols/ICQ-WIM/src/resource.h | 4 | ||||
-rw-r--r-- | protocols/ICQ-WIM/src/server.cpp | 283 |
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; -} |