summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2024-01-02 15:49:18 +0300
committerGeorge Hazan <george.hazan@gmail.com>2024-01-02 15:49:18 +0300
commit0f77b6f84b7fb4eca715ef3191a13ed0291f37c0 (patch)
tree069c86fd2bcce2205bbe8fab3e894b120c3d7b87
parent17c826aefd05391688341acb9784995958510dd6 (diff)
fixes #4091 (Discord: do not display hidden channels)
-rw-r--r--protocols/Discord/src/dispatch.cpp9
-rw-r--r--protocols/Discord/src/gateway.cpp2
-rw-r--r--protocols/Discord/src/groupchat.cpp11
-rw-r--r--protocols/Discord/src/guilds.cpp224
-rw-r--r--protocols/Discord/src/proto.cpp2
-rw-r--r--protocols/Discord/src/proto.h85
-rw-r--r--protocols/Discord/src/stdafx.h1
-rw-r--r--protocols/Discord/src/version.h6
8 files changed, 248 insertions, 92 deletions
diff --git a/protocols/Discord/src/dispatch.cpp b/protocols/Discord/src/dispatch.cpp
index 2f3686af46..536eff688f 100644
--- a/protocols/Discord/src/dispatch.cpp
+++ b/protocols/Discord/src/dispatch.cpp
@@ -131,7 +131,7 @@ void CDiscordProto::OnCommandChannelUpdated(const JSONNode &pRoot)
CMStringW wszName = pRoot["name"].as_mstring();
if (!wszName.IsEmpty()) {
- CMStringW wszNewName = pGuild->wszName + L"#" + wszName;
+ CMStringW wszNewName = pGuild->m_wszName + L"#" + wszName;
Chat_ChangeSessionName(pUser->si, wszNewName);
}
@@ -245,7 +245,7 @@ void CDiscordProto::OnCommandGuildMemberListUpdate(const JSONNode &pRoot)
}
}
- pGuild->bSynced = true;
+ pGuild->m_bSynced = true;
}
void CDiscordProto::OnCommandGuildMemberRemoved(const JSONNode &pRoot)
@@ -310,9 +310,8 @@ void CDiscordProto::OnCommandGuildMemberUpdated(const JSONNode &pRoot)
void CDiscordProto::OnCommandRoleCreated(const JSONNode &pRoot)
{
- CDiscordGuild *pGuild = FindGuild(::getId(pRoot["guild_id"]));
- if (pGuild != nullptr)
- ProcessRole(pGuild, pRoot["role"]);
+ if (auto *pGuild = FindGuild(::getId(pRoot["guild_id"])))
+ pGuild->ProcessRole(pRoot["role"]);
}
void CDiscordProto::OnCommandRoleDeleted(const JSONNode &pRoot)
diff --git a/protocols/Discord/src/gateway.cpp b/protocols/Discord/src/gateway.cpp
index 04958142be..543020f105 100644
--- a/protocols/Discord/src/gateway.cpp
+++ b/protocols/Discord/src/gateway.cpp
@@ -257,7 +257,7 @@ void CDiscordProto::GatewaySendGuildInfo(CDiscordGuild *pGuild)
JSONNode channels; channels.set_name("channels"); channels << chl;
JSONNode payload; payload.set_name("d");
- payload << SINT64_PARAM("guild_id", pGuild->id) << BOOL_PARAM("typing", true) << BOOL_PARAM("activities", true) << BOOL_PARAM("presences", true) << channels;
+ payload << SINT64_PARAM("guild_id", pGuild->m_id) << BOOL_PARAM("typing", true) << BOOL_PARAM("activities", true) << BOOL_PARAM("presences", true) << channels;
JSONNode root;
root << INT_PARAM("op", OPCODE_REQUEST_SYNC_CHANNEL) << payload;
diff --git a/protocols/Discord/src/groupchat.cpp b/protocols/Discord/src/groupchat.cpp
index 67cf07d2fb..22f2981858 100644
--- a/protocols/Discord/src/groupchat.cpp
+++ b/protocols/Discord/src/groupchat.cpp
@@ -26,11 +26,20 @@ enum {
/////////////////////////////////////////////////////////////////////////////////////////
+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<CDiscordRole> roles(pGuild->arRoles.getCount(), SortRolesByPosition);
for (auto &it : pGuild->arRoles)
+ roles.insert(it);
+
+ for (auto &it : roles)
Chat_AddGroup(si, it->wszName);
}
@@ -146,7 +155,7 @@ void CDiscordProto::Chat_ProcessLogMenu(GCHOOK *gch)
es.recentCount = 5;
if (EnterString(&es)) {
JSONNode root; root << WCHAR_PARAM("nick", es.ptszResult);
- CMStringA szUrl(FORMAT, "/guilds/%lld/members/@me/nick", pUser->pGuild->id);
+ 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);
}
diff --git a/protocols/Discord/src/guilds.cpp b/protocols/Discord/src/guilds.cpp
index d4b8999a13..a8f76bbfbe 100644
--- a/protocols/Discord/src/guilds.cpp
+++ b/protocols/Discord/src/guilds.cpp
@@ -17,36 +17,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdafx.h"
-int compareUsers(const CDiscordUser *p1, const CDiscordUser *p2);
-
-static int compareRoles(const CDiscordRole *p1, const CDiscordRole *p2)
-{
- return compareInt64(p1->id, p2->id);
-}
-
-static int compareChatUsers(const CDiscordGuildMember *p1, const CDiscordGuildMember *p2)
-{
- return compareInt64(p1->userId, p2->userId);
-}
-
-CDiscordGuild::CDiscordGuild(SnowFlake _id) :
- id(_id),
- arChannels(10, compareUsers),
- arChatUsers(30, compareChatUsers),
- arRoles(10, compareRoles)
-{
-}
-
-CDiscordGuild::~CDiscordGuild()
-{
-}
-
-CDiscordUser::~CDiscordUser()
-{
- if (pGuild != nullptr)
- pGuild->arChannels.remove(this);
-}
-
/////////////////////////////////////////////////////////////////////////////////////////
// reads a presence block from json
@@ -71,25 +41,6 @@ void CDiscordProto::ProcessPresence(const JSONNode &root)
}
/////////////////////////////////////////////////////////////////////////////////////////
-// reads a role from json
-
-void CDiscordProto::ProcessRole(CDiscordGuild *guild, const JSONNode &role)
-{
- SnowFlake id = ::getId(role["id"]);
- CDiscordRole *p = guild->arRoles.find((CDiscordRole*)&id);
- if (p == nullptr) {
- p = new CDiscordRole();
- p->id = id;
- guild->arRoles.insert(p);
- }
-
- p->color = role["color"].as_int();
- p->position = role["position"].as_int();
- p->permissions = role["permissions"].as_int();
- p->wszName = role["name"].as_mstring();
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
static void sttSetGroupName(MCONTACT hContact, const wchar_t *pwszGroupName)
{
@@ -134,7 +85,7 @@ void CDiscordProto::CreateChat(CDiscordGuild *pGuild, CDiscordUser *pUser)
if (pParent != nullptr)
sttSetGroupName(pUser->hContact, pParent->wszChannelName);
}
- else sttSetGroupName(pUser->hContact, Clist_GroupGetName(pGuild->groupId));
+ else sttSetGroupName(pUser->hContact, Clist_GroupGetName(pGuild->m_groupId));
}
BuildStatusList(pGuild, si);
@@ -163,31 +114,28 @@ void CDiscordProto::ProcessGuild(const JSONNode &pRoot)
arGuilds.insert(pGuild);
}
- pGuild->ownerId = ::getId(pRoot["owner_id"]);
- pGuild->wszName = pRoot["name"].as_mstring();
+ pGuild->m_ownerId = ::getId(pRoot["owner_id"]);
+ pGuild->m_wszName = pRoot["name"].as_mstring();
if (m_bUseGuildGroups)
- pGuild->groupId = Clist_GroupCreate(Clist_GroupExists(m_wszDefaultGroup), pGuild->wszName);
+ pGuild->m_groupId = Clist_GroupCreate(Clist_GroupExists(m_wszDefaultGroup), pGuild->m_wszName);
- SESSION_INFO *si = Chat_NewSession(GCW_SERVER, m_szModuleName, pGuild->wszName, pGuild->wszName, pGuild);
+ SESSION_INFO *si = Chat_NewSession(GCW_SERVER, m_szModuleName, pGuild->m_wszName, pGuild->m_wszName, pGuild);
if (si == nullptr)
return;
pGuild->pParentSi = (SESSION_INFO*)si;
- pGuild->hContact = si->hContact;
- setId(pGuild->hContact, DB_KEY_CHANNELID, guildId);
+ pGuild->m_hContact = si->hContact;
+ setId(pGuild->m_hContact, DB_KEY_CHANNELID, guildId);
Chat_Control(si, WINDOW_HIDDEN);
Chat_Control(si, SESSION_ONLINE);
for (auto &it : pRoot["roles"])
- ProcessRole(pGuild, it);
+ pGuild->ProcessRole(it);
BuildStatusList(pGuild, si);
- for (auto &it : pRoot["channels"])
- ProcessGuildChannel(pGuild, it);
-
- if (!pGuild->bSynced && getByte(si->hContact, "EnableSync"))
+ if (!pGuild->m_bSynced && getByte(si->hContact, "EnableSync"))
GatewaySendGuildInfo(pGuild);
// store all guild members
@@ -201,6 +149,10 @@ void CDiscordProto::ProcessGuild(const JSONNode &pRoot)
pm->iStatus = ID_STATUS_OFFLINE;
}
+ // parse channels
+ for (auto &it : pRoot["channels"])
+ ProcessGuildChannel(pGuild, it);
+
// parse online statuses
for (auto &it : pRoot["presences"]) {
CDiscordGuildMember *gm = pGuild->FindUser(::getId(it["user"]["id"]));
@@ -214,7 +166,7 @@ void CDiscordProto::ProcessGuild(const JSONNode &pRoot)
if (!m_bTerminated)
ForkThread(&CDiscordProto::BatchChatCreate, pGuild);
- pGuild->bSynced = true;
+ pGuild->m_bSynced = true;
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -226,6 +178,11 @@ CDiscordUser* CDiscordProto::ProcessGuildChannel(CDiscordGuild *pGuild, const JS
CMStringW wszName = pch["name"].as_mstring();
CDiscordUser *pUser;
+ // check permissions to enter the channel
+ auto permissions = pGuild->CalcPermissionOverride(m_ownId, pch["permission_overwrites"]);
+ if (!(permissions & Permission::VIEW_CHANNEL))
+ return nullptr;
+
// filter our all channels but the text ones
switch (pch["type"].as_int()) {
case 4: // channel group
@@ -243,7 +200,7 @@ CDiscordUser* CDiscordProto::ProcessGuildChannel(CDiscordGuild *pGuild, const JS
pGuild->arChannels.insert(pUser);
- MGROUP grpId = Clist_GroupCreate(pGuild->groupId, wszName);
+ MGROUP grpId = Clist_GroupCreate(pGuild->m_groupId, wszName);
pUser->wszChannelName = Clist_GroupGetName(grpId);
}
return pUser;
@@ -265,7 +222,7 @@ CDiscordUser* CDiscordProto::ProcessGuildChannel(CDiscordGuild *pGuild, const JS
if (m_bUseGuildGroups)
pUser->wszChannelName = L"#" + wszName;
else
- pUser->wszChannelName = pGuild->wszName + L"#" + wszName;
+ pUser->wszChannelName = pGuild->m_wszName + L"#" + wszName;
pUser->wszTopic = pch["topic"].as_mstring();
pUser->pGuild = pGuild;
pUser->lastMsgId = ::getId(pch["last_message_id"]);
@@ -282,9 +239,10 @@ CDiscordGuildMember* CDiscordProto::ProcessGuildUser(CDiscordGuild *pGuild, cons
{
auto& pUser = pRoot["user"];
- bool bNew = false;
CMStringW wszUserId = pUser["id"].as_mstring();
SnowFlake userId = _wtoi64(wszUserId);
+ bool bNew = false, bIsMe = userId == m_ownId;
+
CDiscordGuildMember *pm = pGuild->FindUser(userId);
if (pm == nullptr) {
pm = new CDiscordGuildMember(userId);
@@ -299,14 +257,25 @@ CDiscordGuildMember* CDiscordProto::ProcessGuildUser(CDiscordGuild *pGuild, cons
else
bNew = true;
- if (userId == pGuild->ownerId)
+ if (userId == pGuild->m_ownerId) {
pm->wszRole = L"@owner";
+ pm->permissions = Permission::ALL;
+ }
else {
+ pm->permissions = pGuild->m_permissions;
+
CDiscordRole *pRole = nullptr;
for (auto &itr : pRoot["roles"]) {
SnowFlake roleId = ::getId(itr);
- if (pRole = pGuild->arRoles.find((CDiscordRole *)&roleId))
- break;
+
+ if (auto *p = pGuild->arRoles.find((CDiscordRole *)&roleId)) {
+ pm->permissions |= p->permissions;
+ if (pRole == nullptr)
+ pRole = p;
+
+ if (bIsMe)
+ p->bIsMe = true;
+ }
}
pm->wszRole = (pRole == nullptr) ? L"@everyone" : pRole->wszName;
}
@@ -365,6 +334,125 @@ void CDiscordProto::AddGuildUser(CDiscordGuild *pGuild, const CDiscordGuildMembe
}
/////////////////////////////////////////////////////////////////////////////////////////
+// CDiscordGuild members
+
+int compareUsers(const CDiscordUser *p1, const CDiscordUser *p2);
+
+static int compareRoles(const CDiscordRole *p1, const CDiscordRole *p2)
+{
+ return compareInt64(p1->id, p2->id);
+}
+
+static int compareChatUsers(const CDiscordGuildMember *p1, const CDiscordGuildMember *p2)
+{
+ return compareInt64(p1->userId, p2->userId);
+}
+
+CDiscordGuild::CDiscordGuild(SnowFlake _id) :
+ m_id(_id),
+ arChannels(10, compareUsers),
+ arChatUsers(30, compareChatUsers),
+ arRoles(10, compareRoles)
+{}
+
+CDiscordGuild::~CDiscordGuild()
+{}
+
+CDiscordUser::~CDiscordUser()
+{
+ if (pGuild != nullptr)
+ pGuild->arChannels.remove(this);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// calculates effective rights
+
+uint64_t CDiscordGuild::CalcPermissionOverride(SnowFlake myUserId, const JSONNode &json)
+{
+ if (myUserId == m_ownerId)
+ return Permission::ALL;
+
+ uint64_t permissions = m_permissions;
+
+ if (auto *pUser = FindUser(myUserId)) {
+ if (pUser->permissions & Permission::ADMIN)
+ return Permission::ALL;
+
+ permissions = pUser->permissions;
+ }
+
+ struct Item
+ {
+ Item() :
+ allow(0),
+ deny(0)
+ {}
+
+ Item(SnowFlake _1, SnowFlake _2) :
+ allow(_1),
+ deny(_2)
+ {}
+
+ SnowFlake allow, deny;
+ };
+ std::map<SnowFlake, Item> items;
+
+ // verify permissions
+ for (auto &it : json) {
+ if (it["type"].as_int() != 0)
+ continue;
+
+ SnowFlake id = ::getId(it["id"]);
+ items[id] = Item(::getId(it["allow"]), ::getId(it["deny"]));
+ }
+
+ auto everyone = items[m_id];
+ permissions &= ~everyone.deny;
+ permissions |= everyone.allow;
+
+ uint64_t allow = 0, deny = 0;
+ for (auto &it : arRoles) {
+ if (it->bIsMe) {
+ auto role = items[it->id];
+ deny |= role.deny;
+ allow |= role.allow;
+ }
+ }
+
+ permissions &= ~deny;
+ permissions |= allow;
+
+ auto personal = items[myUserId];
+ permissions &= ~personal.deny;
+ permissions |= personal.allow;
+
+ return permissions;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// reads a role from json
+
+void CDiscordGuild::ProcessRole(const JSONNode &role)
+{
+ SnowFlake id = ::getId(role["id"]);
+ CDiscordRole *p = arRoles.find((CDiscordRole *)&id);
+ if (p == nullptr) {
+ p = new CDiscordRole();
+ p->id = id;
+ arRoles.insert(p);
+ }
+
+ p->color = role["color"].as_int();
+ p->position = role["position"].as_int();
+ p->permissions = ::getId(role["permissions"]);
+ p->wszName = role["name"].as_mstring();
+
+ if (m_id == id)
+ m_permissions = p->permissions;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Persistence manager
void CDiscordGuild::LoadFromFile()
{
diff --git a/protocols/Discord/src/proto.cpp b/protocols/Discord/src/proto.cpp
index 7e55ea5d65..1e76ead10d 100644
--- a/protocols/Discord/src/proto.cpp
+++ b/protocols/Discord/src/proto.cpp
@@ -34,7 +34,7 @@ int compareUsers(const CDiscordUser *p1, const CDiscordUser *p2)
static int compareGuilds(const CDiscordGuild *p1, const CDiscordGuild *p2)
{
- return compareInt64(p1->id, p2->id);
+ return compareInt64(p1->m_id, p2->m_id);
}
CDiscordProto::CDiscordProto(const char *proto_name, const wchar_t *username) :
diff --git a/protocols/Discord/src/proto.h b/protocols/Discord/src/proto.h
index 3ff1f626e5..e34f6cbfa9 100644
--- a/protocols/Discord/src/proto.h
+++ b/protocols/Discord/src/proto.h
@@ -3,6 +3,58 @@
#define EVENT_INCOMING_CALL 10001
#define EVENT_CALL_FINISHED 10002
+enum Permission : uint64_t
+{
+ CREATE_INVITE = (1ll << 0), // Allows creation of instant invites
+ KICK_MEMBERS = (1ll << 1), // Allows kicking members
+ BAN_MEMBERS = (1ll << 2), // Allows banning members
+ ADMIN = (1ll << 3), // Allows all permissions and bypasses channel permission overwrites
+ MANAGE_CHANNELS = (1ll << 4), // Allows management and editing of channels
+ MANAGE_GUILD = (1ll << 5), // Allows management and editing of the guild
+ ADD_REACTIONS = (1ll << 6), // Allows for the addition of reactions to messages
+ VIEW_AUDIT_LOG = (1ll << 7), // Allows for viewing of audit logs
+ PRIORITY_SPEAKER = (1ll << 8), // Allows for using priority speaker in a voice channel
+ STREAM = (1ll << 9), // Allows the user to go live
+ VIEW_CHANNEL = (1ll << 10), // Allows guild members to view a channel, which includes reading messages in text channels and joining voice channels
+ SEND_MESSAGES = (1ll << 11), // Allows for sending messages in a channel and creating threads in a forum (does not allow sending messages in threads)
+ SEND_TTS_MESSAGES = (1ll << 12), // Allows for sending of /tts messages
+ MANAGE_MESSAGES = (1ll << 13), // Allows for deletion of other users messages
+ EMBED_LINKS = (1ll << 14), // Links sent by users with this permission will be auto-embedded
+ ATTACH_FILES = (1ll << 15), // Allows for uploading images and files
+ READ_HISTORY = (1ll << 16), // Allows for reading of message history
+ MENTION_EVERYONE = (1ll << 17), // Allows for using the @everyone tag to notify all users in a channel, and the @here tag to notify all online users in a channel
+ USE_EXT_EMOJI = (1ll << 18), // Allows the usage of custom emojis from other servers
+ VIEW_INSIGHTS = (1ll << 19), // Allows for viewing guild insights
+ VOICE_CONNECT = (1ll << 20), // Allows for joining of a voice channel
+ VOICE_SPEAK = (1ll << 21), // Allows for speaking in a voice channel
+ VOICE_MUTE = (1ll << 22), // Allows for muting members in a voice channel
+ VOICE_DEAFEN = (1ll << 23), // Allows for deafening of members in a voice channel
+ VOICE_MOVE = (1ll << 24), // Allows for moving of members between voice channels
+ USE_VAD = (1ll << 25), // Allows for using voice-activity-detection in a voice channel
+ CHANGE_NICKNAME = (1ll << 26), // Allows for modification of own nickname
+ MANAGE_NICKS = (1ll << 27), // Allows for modification of other users nicknames
+ MANAGE_ROLES = (1ll << 28), // Allows management and editing of roles
+ MANAGE_WEBHOOKS = (1ll << 29), //
+ MANAGE_EMOJI = (1ll << 30), // Allows for editing and deleting emojis, stickers, and soundboard sounds created by all users
+ USE_APP_COMMANDS = (1ll << 31), // Allows members to use application commands, including slash commands and context menu commands.
+ REQUEST_TO_SPEAK = (1ll << 32), // Allows for requesting to speak in stage channels.
+ MANAGE_EVENTS = (1ll << 33), // Allows for editing and deleting scheduled events created by all users
+ MANAGE_THREADS = (1ll << 34), // Allows for deleting and archiving threads, and viewing all private threads
+ PUBLIC_THREADS = (1ll << 35), // Allows for creating public and announcement threads
+ PRIVATE_THREADS = (1ll << 36), // Allows for creating private threads
+ USE_EXT_STICKERS = (1ll << 37), // Allows the usage of custom stickers from other servers
+ SEND_THREADS = (1ll << 38), // Allows for sending messages in threads
+ EMBED_ACTIVITY = (1ll << 39), // Allows for using Activities (applications with the EMBEDDED flag) in a voice channel
+ MODERATE_MEMBERS = (1ll << 40), // Allows for timing out users to prevent them from sending or reacting to messages in chat and threads, and from speaking in voice and stage channels
+ VIEW_MONETIZATION = (1ll << 41), // Allows for viewing role subscription insights
+ USE_SOUNDBOARD = (1ll << 42), // Allows for using soundboard in a voice channel
+ CREATE_EXPRESSIONS = (1ll << 43), // Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting those created by the current user.
+ CREATE_EVEMTS = (1ll << 44), // Allows for creating scheduled events, and editing and deleting those created by the current user.
+ USE_EXT_SOUNDS = (1ll << 45), // Allows the usage of custom soundboard sounds from other servers
+ SEND_VOICE = (1ll << 46), // Allows sending voice messages
+ ALL = -1ll
+};
+
typedef __int64 SnowFlake;
__forceinline int compareInt64(const SnowFlake i1, const SnowFlake i2)
@@ -41,9 +93,10 @@ public:
struct CDiscordRole : public MZeroedObject
{
SnowFlake id;
+ uint64_t permissions;
COLORREF color;
- uint32_t permissions;
int position;
+ bool bIsMe;
CMStringW wszName;
};
@@ -104,6 +157,7 @@ struct CDiscordGuildMember : public MZeroedObject
{}
SnowFlake userId;
+ uint64_t permissions;
CMStringW wszDiscordId, wszNick, wszRole;
int iStatus;
};
@@ -113,27 +167,33 @@ struct CDiscordGuild : public MZeroedObject
CDiscordGuild(SnowFlake _id);
~CDiscordGuild();
- __forceinline CDiscordGuildMember* FindUser(SnowFlake userId)
- {
+ __forceinline CDiscordGuildMember* FindUser(SnowFlake userId) {
return arChatUsers.find((CDiscordGuildMember *)&userId);
}
- __inline CMStringW GetCacheFile() const
- {
- return CMStringW(FORMAT, L"%s\\DiscordCache\\%lld.json", VARSW(L"%miranda_userdata%").get(), id);
+ __forceinline CDiscordRole* FindRole(SnowFlake id) {
+ return arRoles.find((CDiscordRole *)&id);
}
- SnowFlake id, ownerId;
- CMStringW wszName;
- MCONTACT hContact;
- MGROUP groupId;
- bool bSynced = false;
- LIST<CDiscordUser> arChannels;
+ __forceinline CMStringW GetCacheFile() const {
+ return CMStringW(FORMAT, L"%s\\DiscordCache\\%lld.json", VARSW(L"%miranda_userdata%").get(), m_id);
+ }
+ SnowFlake m_id, m_ownerId;
+ uint64_t m_permissions = 0; // my effective permissions
+ CMStringW m_wszName;
+ MCONTACT m_hContact;
+ MGROUP m_groupId;
+ bool m_bSynced = false;
+
SESSION_INFO *pParentSi;
+ LIST<CDiscordUser> arChannels;
OBJLIST<CDiscordGuildMember> arChatUsers;
OBJLIST<CDiscordRole> arRoles; // guild roles
+ uint64_t CalcPermissionOverride(SnowFlake myUserId, const JSONNode &json);
+ void ProcessRole(const JSONNode &json);
+
void LoadFromFile();
void SaveToFile();
};
@@ -315,7 +375,6 @@ class CDiscordProto : public PROTO<CDiscordProto>
void AddGuildUser(CDiscordGuild *guild, const CDiscordGuildMember &pUser);
void ProcessGuild(const JSONNode &json);
void ProcessPresence(const JSONNode &json);
- void ProcessRole(CDiscordGuild *guild, const JSONNode &json);
void ProcessType(CDiscordUser *pUser, const JSONNode &json);
CDiscordUser* ProcessGuildChannel(CDiscordGuild *guild, const JSONNode &json);
diff --git a/protocols/Discord/src/stdafx.h b/protocols/Discord/src/stdafx.h
index 48d68292dd..7588a978d8 100644
--- a/protocols/Discord/src/stdafx.h
+++ b/protocols/Discord/src/stdafx.h
@@ -16,6 +16,7 @@
#include <direct.h>
#include <time.h>
+#include <map>
#include <vector>
#include "resource.h"
diff --git a/protocols/Discord/src/version.h b/protocols/Discord/src/version.h
index 1a33efa401..e1bdff0418 100644
--- a/protocols/Discord/src/version.h
+++ b/protocols/Discord/src/version.h
@@ -1,7 +1,7 @@
#define __MAJOR_VERSION 0
-#define __MINOR_VERSION 6
-#define __RELEASE_NUM 2
-#define __BUILD_NUM 11
+#define __MINOR_VERSION 96
+#define __RELEASE_NUM 5
+#define __BUILD_NUM 1
#include <stdver.h>