/*
Copyright © 2016-22 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, see .
*/
#include "stdafx.h"
enum {
IDM_CANCEL,
IDM_COPY_ID,
IDM_CHANGENICK, IDM_CHANGETOPIC, IDM_RENAME, IDM_DESTROY
};
/////////////////////////////////////////////////////////////////////////////////////////
static int SortRolesByPosition(const CDiscordRole *p1, const CDiscordRole *p2)
{
return p1->position - p2->position;
}
void BuildStatusList(const CDiscordGuild *pGuild, SESSION_INFO *si)
{
Chat_AddGroup(si, L"@owner");
LIST roles(pGuild->arRoles.getCount(), SortRolesByPosition);
for (auto &it : pGuild->arRoles)
roles.insert(it);
for (auto &it : roles)
Chat_AddGroup(si, it->wszName);
}
/////////////////////////////////////////////////////////////////////////////////////////
static gc_item sttLogListItems[] =
{
{ LPGENW("Change &nickname"), IDM_CHANGENICK, MENU_ITEM },
{ LPGENW("Channel control"), FALSE, MENU_NEWPOPUP },
{ LPGENW("Change &topic"), IDM_CHANGETOPIC, MENU_POPUPITEM },
{ LPGENW("&Rename channel"), IDM_RENAME, MENU_POPUPITEM },
{ nullptr, 0, MENU_POPUPSEPARATOR },
{ LPGENW("&Destroy channel"), IDM_DESTROY, MENU_POPUPITEM },
};
static gc_item sttNicklistItems[] =
{
{ LPGENW("Copy ID"), IDM_COPY_ID, MENU_ITEM },
};
int CDiscordProto::GroupchatMenuHook(WPARAM, LPARAM lParam)
{
GCMENUITEMS* gcmi = (GCMENUITEMS*)lParam;
if (gcmi == nullptr)
return 0;
if (mir_strcmpi(gcmi->pszModule, m_szModuleName))
return 0;
CDiscordUser *pChat = FindUserByChannel(_wtoi64(gcmi->pszID));
if (pChat == nullptr)
return 0;
if (gcmi->Type == MENU_ON_LOG)
Chat_AddMenuItems(gcmi->hMenu, _countof(sttLogListItems), sttLogListItems, &g_plugin);
else if (gcmi->Type == MENU_ON_NICKLIST)
Chat_AddMenuItems(gcmi->hMenu, _countof(sttNicklistItems), sttNicklistItems, &g_plugin);
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////
void CDiscordProto::Chat_SendPrivateMessage(GCHOOK *gch)
{
SnowFlake userId = _wtoi64(gch->ptszUID);
MCONTACT hContact;
CDiscordUser *pUser = FindUser(userId);
if (pUser == nullptr) {
PROTOSEARCHRESULT psr = { sizeof(psr) };
psr.id.w = (wchar_t*)gch->ptszUID;
psr.nick.w = (wchar_t*)gch->ptszNick;
if ((hContact = AddToList(PALF_TEMPORARY, &psr)) == 0)
return;
setId(hContact, DB_KEY_ID, userId);
setId(hContact, DB_KEY_CHANNELID, _wtoi64(gch->si->ptszID));
setWString(hContact, DB_KEY_NICK, gch->ptszNick);
Contact::Hide(hContact);
db_set_dw(hContact, "Ignore", "Mask1", 0);
}
else hContact = pUser->hContact;
CallService(MS_MSG_SENDMESSAGE, hContact, 0);
}
void CDiscordProto::Chat_ProcessLogMenu(GCHOOK *gch)
{
CDiscordUser *pUser = FindUserByChannel(_wtoi64(gch->si->ptszID));
if (pUser == nullptr)
return;
ENTER_STRING es = {};
es.szModuleName = m_szModuleName;
switch (gch->dwData) {
case IDM_DESTROY:
if (IDYES == MessageBox(nullptr, TranslateT("Do you really want to destroy this channel? This action is non-revertable."), m_tszUserName, MB_YESNO | MB_ICONQUESTION)) {
CMStringA szUrl(FORMAT, "/channels/%S", pUser->wszUsername.c_str());
Push(new AsyncHttpRequest(this, REQUEST_DELETE, szUrl, nullptr));
}
break;
case IDM_RENAME:
es.caption = TranslateT("Enter new channel name:");
es.type = ESF_COMBO;
es.szDataPrefix = "chat_rename";
if (EnterString(&es)) {
JSONNode root; root << WCHAR_PARAM("name", es.ptszResult);
CMStringA szUrl(FORMAT, "/channels/%S", pUser->wszUsername.c_str());
Push(new AsyncHttpRequest(this, REQUEST_PATCH, szUrl, nullptr, &root));
mir_free(es.ptszResult);
}
break;
case IDM_CHANGETOPIC:
es.caption = TranslateT("Enter new topic:");
es.type = ESF_RICHEDIT;
es.szDataPrefix = "chat_topic";
if (EnterString(&es)) {
JSONNode root; root << WCHAR_PARAM("topic", es.ptszResult);
CMStringA szUrl(FORMAT, "/channels/%S", pUser->wszUsername.c_str());
Push(new AsyncHttpRequest(this, REQUEST_PATCH, szUrl, nullptr, &root));
mir_free(es.ptszResult);
}
break;
case IDM_CHANGENICK:
es.caption = TranslateT("Enter your new nick name:");
es.type = ESF_COMBO;
es.szDataPrefix = "chat_nick";
es.recentCount = 5;
if (EnterString(&es)) {
JSONNode root; root << WCHAR_PARAM("nick", es.ptszResult);
CMStringA szUrl(FORMAT, "/guilds/%lld/members/@me/nick", pUser->pGuild->m_id);
Push(new AsyncHttpRequest(this, REQUEST_PATCH, szUrl, nullptr, &root));
mir_free(es.ptszResult);
}
break;
}
}
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)
return;
switch (gch->dwData) {
case IDM_COPY_ID:
CopyId(pUser->wszDiscordId);
break;
}
}
int CDiscordProto::GroupchatEventHook(WPARAM, LPARAM lParam)
{
GCHOOK *gch = (GCHOOK*)lParam;
if (gch == nullptr)
return 0;
if (mir_strcmpi(gch->si->pszModule, m_szModuleName))
return 0;
switch (gch->iType) {
case GC_USER_MESSAGE:
if (m_bOnline && mir_wstrlen(gch->ptszText) > 0) {
CMStringW wszText(gch->ptszText);
wszText.TrimRight();
int pos = wszText.Find(':');
if (pos != -1) {
auto wszWord = wszText.Left(pos);
wszWord.Trim();
if (auto *si = Chat_Find(gch->si->ptszID, gch->si->pszModule)) {
USERINFO *pUser = nullptr;
for (auto &U : si->getUserList())
if (wszWord == U->pszNick) {
pUser = U;
break;
}
if (pUser) {
wszText.Delete(0, pos);
wszText.Insert(0, L"<@" + CMStringW(pUser->pszUID) + L">");
}
}
}
Chat_UnescapeTags(wszText.GetBuffer());
JSONNode body; body << WCHAR_PARAM("content", wszText);
CMStringA szUrl(FORMAT, "/channels/%S/messages", gch->si->ptszID);
Push(new AsyncHttpRequest(this, REQUEST_POST, szUrl, nullptr, &body));
}
break;
case GC_USER_PRIVMESS:
Chat_SendPrivateMessage(gch);
break;
case GC_USER_LOGMENU:
Chat_ProcessLogMenu(gch);
break;
case GC_USER_NICKLISTMENU:
Chat_ProcessNickMenu(gch);
break;
case GC_USER_TYPNOTIFY:
UserIsTyping(gch->si->hContact, (int)gch->dwData);
break;
}
return 1;
}