From 7e1ecf7d6f1006e6e74c5c726cd873032948a141 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Sat, 4 May 2024 17:29:25 +0300 Subject: =?UTF-8?q?fixes=20#4400=20(Discord:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B8=20=D0=B8=D0=B7?= =?UTF-8?q?=D0=B3=D0=BD=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B4=D1=80=D1=83=D0=B3?= =?UTF-8?q?=D0=B8=D1=85=20=D0=BB=D1=8E=D0=B4=D0=B5=D0=B9=20=D0=B8=D0=B7=20?= =?UTF-8?q?=D1=87=D0=B0=D1=82=D0=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- protocols/Discord/res/discord.rc | 19 ++++ protocols/Discord/src/groupchat.cpp | 167 +++++++++++++++++++++++++++++------- protocols/Discord/src/proto.h | 2 + protocols/Discord/src/resource.h | 4 +- 4 files changed, 160 insertions(+), 32 deletions(-) diff --git a/protocols/Discord/res/discord.rc b/protocols/Discord/res/discord.rc index 3f4796137e..b272538e49 100644 --- a/protocols/Discord/res/discord.rc +++ b/protocols/Discord/res/discord.rc @@ -126,6 +126,16 @@ BEGIN COMBOBOX IDC_ANOTHER,7,32,133,30,CBS_DROPDOWNLIST | WS_TABSTOP END +IDD_GROUPCHAT_INVITE DIALOGEX 0, 0, 215, 260 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Send group chat invitation" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "",IDC_CLIST,"CListControl",WS_TABSTOP | 0x1,4,6,204,232,WS_EX_CLIENTEDGE + DEFPUSHBUTTON "&Invite",IDOK,106,243,50,14 + PUSHBUTTON "Cancel",IDCANCEL,160,243,50,14 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -150,6 +160,10 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 45 END + + IDD_GROUPCHAT_INVITE, DIALOG + BEGIN + END END #endif // APSTUDIO_INVOKED @@ -169,6 +183,11 @@ BEGIN 0 END +IDD_GROUPCHAT_INVITE AFX_DIALOG_LAYOUT +BEGIN + 0 +END + #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/protocols/Discord/src/groupchat.cpp b/protocols/Discord/src/groupchat.cpp index 4918e5c2c7..95948fc5f3 100644 --- a/protocols/Discord/src/groupchat.cpp +++ b/protocols/Discord/src/groupchat.cpp @@ -21,9 +21,25 @@ enum { IDM_CANCEL, IDM_COPY_ID, - IDM_CHANGENICK, IDM_CHANGETOPIC, IDM_RENAME, IDM_DESTROY, IDM_LEAVE + IDM_CHANGENICK, IDM_CHANGETOPIC, IDM_RENAME, IDM_DESTROY, IDM_LEAVE, + + IDM_KICK, IDM_INVITE }; +static void sttDisableMenuItem(int nItems, gc_item *items, uint32_t id, bool disabled) +{ + for (int i = 0; i < nItems; i++) + if (items[i].dwID == id) + items[i].bDisabled = disabled; +} + +static void sttShowGcMenuItem(int nItems, gc_item *items, uint32_t id, int type) +{ + for (int i = 0; i < nItems; i++) + if (items[i].dwID == id) + items[i].uType = type; +} + ///////////////////////////////////////////////////////////////////////////////////////// static int SortRolesByPosition(const CDiscordRole *p1, const CDiscordRole *p2) @@ -48,6 +64,8 @@ void BuildStatusList(const CDiscordGuild *pGuild, SESSION_INFO *si) static gc_item sttLogListItems[] = { { LPGENW("Change &nickname"), IDM_CHANGENICK, MENU_ITEM }, + { nullptr, 0, MENU_SEPARATOR }, + { LPGENW("Invite users"), IDM_INVITE, MENU_ITEM }, { LPGENW("Channel control"), FALSE, MENU_NEWPOPUP }, { LPGENW("Change &topic"), IDM_CHANGETOPIC, MENU_POPUPITEM }, { LPGENW("&Rename channel"), IDM_RENAME, MENU_POPUPITEM }, @@ -59,6 +77,8 @@ static gc_item sttLogListItems[] = static gc_item sttNicklistItems[] = { { LPGENW("Copy ID"), IDM_COPY_ID, MENU_ITEM }, + { nullptr, 0, MENU_SEPARATOR }, + { LPGENW("Kick user"), IDM_KICK, MENU_ITEM }, }; int CDiscordProto::GroupchatMenuHook(WPARAM, LPARAM lParam) @@ -71,22 +91,25 @@ int CDiscordProto::GroupchatMenuHook(WPARAM, LPARAM lParam) return 0; CDiscordUser *pChat = FindUserByChannel(_wtoi64(gcmi->pszID)); - if (pChat == nullptr) + if (pChat == nullptr || pChat->si == nullptr) return 0; + bool isOwner = getId(pChat->hContact, DB_KEY_OWNERID) == m_ownId; + if (gcmi->Type == MENU_ON_LOG) { if (pChat->pGuild == nullptr) - sttLogListItems[0].uType = 0; - - if (getId(pChat->hContact, DB_KEY_OWNERID) == m_ownId) - sttLogListItems[6].uType = 0; - else - sttLogListItems[5].uType = 0; + sttShowGcMenuItem(_countof(sttLogListItems), sttLogListItems, IDM_CHANGENICK, 0); + + sttShowGcMenuItem(_countof(sttLogListItems), sttLogListItems, IDM_LEAVE, isOwner ? 0 : MENU_POPUPITEM); + sttShowGcMenuItem(_countof(sttLogListItems), sttLogListItems, IDM_DESTROY, isOwner ? 0 : MENU_POPUPITEM); Chat_AddMenuItems(gcmi->hMenu, _countof(sttLogListItems), sttLogListItems, &g_plugin); } - else if (gcmi->Type == MENU_ON_NICKLIST) + else if (gcmi->Type == MENU_ON_NICKLIST) { + sttDisableMenuItem(_countof(sttNicklistItems), sttNicklistItems, IDM_KICK, !isOwner); + Chat_AddMenuItems(gcmi->hMenu, _countof(sttNicklistItems), sttNicklistItems, &g_plugin); + } return 0; } @@ -117,6 +140,86 @@ void CDiscordProto::Chat_SendPrivateMessage(GCHOOK *gch) CallService(MS_MSG_SENDMESSAGE, hContact, 0); } +///////////////////////////////////////////////////////////////////////////////////////// +// Invitation dialog + +class CGroupchatInviteDlg : public CDiscordDlgBase +{ + CCtrlClc m_clc; + SnowFlake m_iChatId; + + void FilterList(CCtrlClc *) + { + for (auto &hContact : Contacts()) { + char *proto = Proto_GetBaseAccountName(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.SetHideEmptyGroups(true); + m_clc.SetHideOfflineRoot(true); + } + +public: + CGroupchatInviteDlg(CDiscordProto *ppro, SnowFlake chatId) : + CDiscordDlgBase(ppro, IDD_GROUPCHAT_INVITE), + m_clc(this, IDC_CLIST), + m_iChatId(chatId) + { + 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_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 + { + // invite users from roster + for (auto &hContact : m_proto->AccContacts()) { + if (m_proto->isChatRoom(hContact)) + continue; + + if (HANDLE hItem = m_clc.FindContact(hContact)) { + if (m_clc.GetCheck(hItem)) { + CMStringA szUrl(FORMAT, "/channels/%lld/recipients/%lld", m_iChatId, m_proto->getId(hContact, DB_KEY_ID)); + m_proto->Push(new AsyncHttpRequest(m_proto, REQUEST_PUT, szUrl, 0)); + } + } + } + return true; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Log menu + +void CDiscordProto::LeaveChat(CDiscordUser *pChat) +{ + CMStringA szUrl(FORMAT, "/channels/%S", pChat->wszUsername.c_str()); + Push(new AsyncHttpRequest(this, REQUEST_DELETE, szUrl, nullptr)); +} + +INT_PTR CDiscordProto::SvcLeaveChat(WPARAM hContact, LPARAM) +{ + if (auto *pUser = FindUserByChannel(getId(hContact, DB_KEY_CHANNELID))) + if (pUser->si) + LeaveChat(pUser); + return 0; +} + void CDiscordProto::Chat_ProcessLogMenu(GCHOOK *gch) { CDiscordUser *pUser = FindUserByChannel(_wtoi64(gch->si->ptszID)); @@ -172,26 +275,44 @@ void CDiscordProto::Chat_ProcessLogMenu(GCHOOK *gch) mir_free(es.ptszResult); } break; + + case IDM_INVITE: + CGroupchatInviteDlg dlg(this, pUser->channelId); + if (gch->si->pDlg) + dlg.SetParent(gch->si->pDlg->GetHwnd()); + dlg.DoModal(); + break; } } +///////////////////////////////////////////////////////////////////////////////////////// +// Nick list menu + +void CDiscordProto::KickChatUser(CDiscordUser *pChat, const wchar_t *pszUID) +{ + CMStringA szUrl(FORMAT, "/channels/%lld/recipients/%S", pChat->channelId, pszUID); + Push(new AsyncHttpRequest(this, REQUEST_DELETE, szUrl, 0)); +} + void CDiscordProto::Chat_ProcessNickMenu(GCHOOK* gch) { auto *pChannel = FindUserByChannel(_wtoi64(gch->si->ptszID)); - if (pChannel == nullptr || pChannel->pGuild == nullptr) - return; - - auto* pUser = pChannel->pGuild->FindUser(_wtoi64(gch->ptszUID)); - if (pUser == nullptr) + if (pChannel == nullptr) return; switch (gch->dwData) { case IDM_COPY_ID: - CopyId(pUser->wszDiscordId); + CopyId(gch->ptszUID); + break; + + case IDM_KICK: + KickChatUser(pChannel, gch->ptszUID); break; } } +///////////////////////////////////////////////////////////////////////////////////////// + int CDiscordProto::GroupchatEventHook(WPARAM, LPARAM lParam) { GCHOOK *gch = (GCHOOK*)lParam; @@ -254,19 +375,3 @@ int CDiscordProto::GroupchatEventHook(WPARAM, LPARAM lParam) return 1; } - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDiscordProto::LeaveChat(CDiscordUser *pChat) -{ - CMStringA szUrl(FORMAT, "/channels/%S", pChat->wszUsername.c_str()); - Push(new AsyncHttpRequest(this, REQUEST_DELETE, szUrl, nullptr)); -} - -INT_PTR CDiscordProto::SvcLeaveChat(WPARAM hContact, LPARAM) -{ - if (auto *pUser = FindUserByChannel(getId(hContact, DB_KEY_CHANNELID))) - if (pUser->si) - LeaveChat(pUser); - return 0; -} diff --git a/protocols/Discord/src/proto.h b/protocols/Discord/src/proto.h index 8c6e045b5c..aafc627b4f 100644 --- a/protocols/Discord/src/proto.h +++ b/protocols/Discord/src/proto.h @@ -228,6 +228,7 @@ class CDiscordProto : public PROTO friend struct AsyncHttpRequest; friend class CDiscardAccountOptions; friend class CMfaDialog; + friend class CGroupchatInviteDlg; class CDiscordProtoImpl { @@ -394,6 +395,7 @@ class CDiscordProto : public PROTO void Chat_ProcessNickMenu(GCHOOK* gch); void CreateChat(CDiscordGuild *pGuild, CDiscordUser *pUser); + void KickChatUser(CDiscordUser *pChat, const wchar_t *pszUID); void LeaveChat(CDiscordUser *pChat); void ProcessChatUser(CDiscordUser *pChat, SnowFlake userId, const JSONNode &pRoot); void ParseSpecialChars(SESSION_INFO *si, CMStringW &str); diff --git a/protocols/Discord/src/resource.h b/protocols/Discord/src/resource.h index b7f625fa1e..cf6c1a467d 100644 --- a/protocols/Discord/src/resource.h +++ b/protocols/Discord/src/resource.h @@ -10,6 +10,7 @@ #define IDI_VOICE_CALL 106 #define IDI_VOICE_ENDED 107 #define IDD_MFA 108 +#define IDD_GROUPCHAT_INVITE 109 #define IDC_PASSWORD 1001 #define IDC_USERNAME 1002 #define IDC_GROUP 1003 @@ -22,7 +23,8 @@ #define IDC_ANOTHER 1009 #define IDC_LABEL 1010 #define IDC_LOGOUT 1011 -#define IDC_COMBO1 1012 +#define IDC_CLIST 1012 + // Next default values for new objects // -- cgit v1.2.3