summaryrefslogtreecommitdiff
path: root/protocols/Discord/src/dispatch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Discord/src/dispatch.cpp')
-rw-r--r--protocols/Discord/src/dispatch.cpp306
1 files changed, 121 insertions, 185 deletions
diff --git a/protocols/Discord/src/dispatch.cpp b/protocols/Discord/src/dispatch.cpp
index d960bf1cac..6a8992322b 100644
--- a/protocols/Discord/src/dispatch.cpp
+++ b/protocols/Discord/src/dispatch.cpp
@@ -76,12 +76,26 @@ GatewayHandlerFunc CDiscordProto::GetHandler(const wchar_t *pwszCommand)
void CDiscordProto::OnCommandChannelCreated(const JSONNode &pRoot)
{
- const JSONNode &members = pRoot["recipients"];
- for (auto it = members.begin(); it != members.end(); ++it) {
- CDiscordUser *pUser = PrepareUser(*it);
- pUser->lastMsg = CDiscordMessage(::getId(pRoot["last_message_id"]));
- pUser->channelId = ::getId(pRoot["id"]);
- setId(pUser->hContact, DB_KEY_CHANNELID, pUser->channelId);
+ SnowFlake guildId = ::getId(pRoot["guild_id"]);
+ if (guildId == 0) {
+ // private channel, created for a contact
+ const JSONNode &members = pRoot["recipients"];
+ for (auto it = members.begin(); it != members.end(); ++it) {
+ CDiscordUser *pUser = PrepareUser(*it);
+ pUser->lastMsg = CDiscordMessage(::getId(pRoot["last_message_id"]));
+ pUser->channelId = ::getId(pRoot["id"]);
+ setId(pUser->hContact, DB_KEY_CHANNELID, pUser->channelId);
+ }
+ }
+ else {
+ CDiscordGuild *pGuild = FindGuild(guildId);
+ if (pGuild == nullptr)
+ return;
+
+ // group channel for a guild
+ CDiscordUser *pUser = ProcessGuildChannel(pGuild, pRoot);
+ if (pUser != nullptr)
+ ApplyUsersToChannel(pGuild, *pUser);
}
}
@@ -141,205 +155,104 @@ void CDiscordProto::OnCommandFriendRemoved(const JSONNode &pRoot)
/////////////////////////////////////////////////////////////////////////////////////////
// guild synchronization
-static int sttGetPresence(const JSONNode &pStatuses, const CMStringW &wszId)
-{
- for (auto it = pStatuses.begin(); it != pStatuses.end(); ++it) {
- const JSONNode &s = *it;
-
- CMStringW wszUserId = s["user"]["id"].as_mstring();
- if (wszUserId == wszId)
- return StrToStatus(s["status"].as_mstring());
- }
-
- return 0;
-}
-
-static SnowFlake sttGetLastRead(const JSONNode &reads, const wchar_t *wszChannelId)
-{
- for (auto it = reads.begin(); it != reads.end(); ++it) {
- const JSONNode &p = *it;
-
- if (p["id"].as_mstring() == wszChannelId)
- return ::getId(p["last_message_id"]);
- }
- return 0;
-}
-
-void CDiscordProto::ProcessRole(SnowFlake guildId, 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->guildId = guildId;
- p->color = role["color"].as_int();
- p->position = role["position"].as_int();
- p->permissions = role["permissions"].as_int();
- p->wszName = role["name"].as_mstring();
-}
-
-void CDiscordProto::ProcessGuild(const JSONNode &readState, const JSONNode &p)
-{
- SnowFlake guildId = ::getId(p["id"]), ownerId = ::getId(p["owner_id"]);
- GatewaySendGuildInfo(guildId);
- CMStringW wszGuildName = p["name"].as_mstring();
-
- GCSessionInfoBase *si = Chat_NewSession(GCW_SERVER, m_szModuleName, wszGuildName, wszGuildName);
- Chat_Control(m_szModuleName, wszGuildName, WINDOW_HIDDEN);
- Chat_Control(m_szModuleName, wszGuildName, SESSION_ONLINE);
- setId(si->hContact, DB_KEY_CHANNELID, guildId);
-
- const JSONNode &roles = p["roles"];
- for (auto itr = roles.begin(); itr != roles.end(); ++itr)
- ProcessRole(guildId, *itr);
-
- const JSONNode &channels = p["channels"];
- for (auto itc = channels.begin(); itc != channels.end(); ++itc) {
- const JSONNode &pch = *itc;
- if (pch["type"].as_int() != 0)
- continue;
-
- CMStringW wszChannelName = pch["name"].as_mstring();
- CMStringW wszChannelId = pch["id"].as_mstring();
- CMStringW wszTopic = pch["topic"].as_mstring();
- SnowFlake channelId = _wtoi64(wszChannelId);
-
- si = Chat_NewSession(GCW_CHATROOM, m_szModuleName, wszChannelId, wszGuildName + L"#" + wszChannelName);
- setId(si->hContact, DB_KEY_OWNERID, ownerId);
- BuildStatusList(guildId, wszChannelId);
-
- Chat_Control(m_szModuleName, wszChannelId, WINDOW_HIDDEN);
- Chat_Control(m_szModuleName, wszChannelId, SESSION_ONLINE);
-
- if (!wszTopic.IsEmpty()) {
- Chat_SetStatusbarText(m_szModuleName, wszChannelId, wszTopic);
-
- GCDEST gcd = { m_szModuleName, wszChannelId, GC_EVENT_TOPIC };
- GCEVENT gce = { &gcd };
- gce.time = time(0);
- gce.ptszText = wszTopic;
- Chat_Event(&gce);
- }
-
- CDiscordUser *pUser = FindUserByChannel(channelId);
- if (pUser == NULL) {
- // missing channel - create it
- pUser = new CDiscordUser(channelId);
- pUser->bIsPrivate = false;
- pUser->hContact = si->hContact;
- pUser->id = channelId;
- pUser->channelId = channelId;
- arUsers.insert(pUser);
- }
- pUser->wszUsername = wszChannelId;
- pUser->guildId = guildId;
- pUser->lastMsg = CDiscordMessage(::getId(pch["last_message_id"]));
- pUser->lastReadId = sttGetLastRead(readState, wszChannelId);
-
- setId(pUser->hContact, DB_KEY_ID, channelId);
- setId(pUser->hContact, DB_KEY_CHANNELID, channelId);
-
- SnowFlake oldMsgId = getId(pUser->hContact, DB_KEY_LASTMSGID);
- if (oldMsgId != 0 && pUser->lastMsg.id > oldMsgId)
- RetrieveHistory(pUser->hContact, MSG_AFTER, oldMsgId, 99);
- }
-}
-
void CDiscordProto::OnCommandGuildCreated(const JSONNode &pRoot)
{
- ProcessGuild(JSONNode(), pRoot);
+ ProcessGuild(pRoot);
OnCommandGuildSync(pRoot);
}
void CDiscordProto::OnCommandGuildSync(const JSONNode &pRoot)
{
- const JSONNode &pStatuses = pRoot["presences"];
- const JSONNode &pMembers = pRoot["members"];
-
- SnowFlake guildId = ::getId(pRoot["id"]);
-
- for (int i = 0; i < arUsers.getCount(); i++) {
- CDiscordUser &pUser = arUsers[i];
- if (pUser.guildId != guildId)
- continue;
-
- SESSION_INFO *si = pci->SM_FindSession(pUser.wszUsername, m_szModuleName);
- if (si == NULL)
- continue;
+ CDiscordGuild *pGuild = FindGuild(::getId(pRoot["id"]));
+ if (pGuild == nullptr)
+ return;
- GCDEST gcd = { m_szModuleName, pUser.wszUsername, GC_EVENT_JOIN };
- GCEVENT gce = { &gcd };
- gce.time = time(0);
- gce.dwFlags = GCEF_SILENT;
+ // store all guild members
+ const JSONNode &pMembers = pRoot["members"];
+ for (auto it = pMembers.begin(); it != pMembers.end(); ++it) {
+ const JSONNode &m = *it;
+
+ CMStringW wszUserId = m["user"]["id"].as_mstring();
+ SnowFlake userId = _wtoi64(wszUserId);
+ CDiscordGuildMember *pm = pGuild->FindUser(userId);
+ if (pm == nullptr) {
+ pm = new CDiscordGuildMember(userId);
+ pGuild->arChatUsers.insert(pm);
+ }
- for (auto it = pMembers.begin(); it != pMembers.end(); ++it) {
- const JSONNode &m = *it;
+ pm->wszNick = m["nick"].as_mstring();
+ if (pm->wszNick.IsEmpty())
+ pm->wszNick = m["user"]["username"].as_mstring() + L"#" + m["user"]["discriminator"].as_mstring();
+ if (userId == pGuild->ownerId)
+ pm->wszRole = L"@owner";
+ else {
CDiscordRole *pRole = nullptr;
const JSONNode &pRoles = m["roles"];
for (auto itr = pRoles.begin(); itr != pRoles.end(); ++itr) {
SnowFlake roleId = ::getId(*itr);
- if (pRole = arRoles.find((CDiscordRole*)&roleId))
+ if (pRole = pGuild->arRoles.find((CDiscordRole*)&roleId))
break;
}
-
- CMStringW wszNick = m["nick"].as_mstring();
- CMStringW wszUsername = m["user"]["username"].as_mstring() + L"#" + m["user"]["discriminator"].as_mstring();
- CMStringW wszUserId = m["user"]["id"].as_mstring();
- SnowFlake userId = _wtoi64(wszUserId);
- if (userId == getId(pUser.hContact, DB_KEY_OWNERID))
- gce.ptszStatus = L"@owner";
- else
- gce.ptszStatus = (pRole == nullptr) ? L"@everyone" : pRole->wszName;
-
- gce.bIsMe = (userId == m_ownId);
- gce.ptszUID = wszUserId;
- gce.ptszNick = wszNick.IsEmpty() ? wszUsername : wszNick;
- Chat_Event(&gce);
-
- int flags = GC_SSE_ONLYLISTED;
- switch (sttGetPresence(pStatuses, wszUserId)) {
- case ID_STATUS_ONLINE: case ID_STATUS_NA: case ID_STATUS_DND:
- flags += GC_SSE_ONLINE;
- break;
- default:
- flags += GC_SSE_OFFLINE;
- }
- Chat_SetStatusEx(m_szModuleName, pUser.wszUsername, flags, wszUserId);
+ pm->wszRole = (pRole == nullptr) ? L"@everyone" : pRole->wszName;
}
+ pm->iStatus = ID_STATUS_OFFLINE;
+ }
+
+ // parse online statuses
+ const JSONNode &pStatuses = pRoot["presences"];
+ for (auto it = pStatuses.begin(); it != pStatuses.end(); ++it) {
+ const JSONNode &s = *it;
+ CDiscordGuildMember *gm = pGuild->FindUser(::getId(s["user"]["id"]));
+ if (gm != nullptr)
+ gm->iStatus = StrToStatus(s["status"].as_mstring());
+ }
+
+ // append users to all chat rooms
+ for (int i = 0; i < arUsers.getCount(); i++) {
+ CDiscordUser &pUser = arUsers[i];
+ if (pUser.guildId == pGuild->id)
+ ApplyUsersToChannel(pGuild, pUser);
}
}
void CDiscordProto::OnCommandGuildDeleted(const JSONNode &pRoot)
{
- SnowFlake guildId = ::getId(pRoot["id"]);
+ CDiscordGuild *pGuild = FindGuild(::getId(pRoot["id"]));
+ if (pGuild == nullptr)
+ return;
for (int i = arUsers.getCount()-1; i >= 0; i--) {
CDiscordUser &pUser = arUsers[i];
- if (pUser.guildId == guildId) {
+ if (pUser.guildId == pGuild->id) {
Chat_Terminate(m_szModuleName, pUser.wszUsername, true);
arUsers.remove(i);
}
}
Chat_Terminate(m_szModuleName, pRoot["name"].as_mstring(), true);
+
+ arGuilds.remove(pGuild);
}
+/////////////////////////////////////////////////////////////////////////////////////////
+// guild members
+
void CDiscordProto::OnCommandGuildMemberAdded(const JSONNode &pRoot)
{
}
void CDiscordProto::OnCommandGuildMemberRemoved(const JSONNode &pRoot)
{
- SnowFlake guildId = ::getId(pRoot["guild_id"]);
+ CDiscordGuild *pGuild = FindGuild(::getId(pRoot["guild_id"]));
+ if (pGuild == nullptr)
+ return;
+
CMStringW wszUserId = pRoot["user"]["id"].as_mstring();
for (int i = 0; i < arUsers.getCount(); i++) {
CDiscordUser &pUser = arUsers[i];
- if (pUser.guildId != guildId)
+ if (pUser.guildId != pGuild->id)
continue;
GCDEST gcd = { m_szModuleName, pUser.wszUsername, GC_EVENT_PART };
@@ -352,17 +265,25 @@ void CDiscordProto::OnCommandGuildMemberRemoved(const JSONNode &pRoot)
void CDiscordProto::OnCommandGuildMemberUpdated(const JSONNode &pRoot)
{
- SnowFlake guildId = ::getId(pRoot["guild_id"]);
+ CDiscordGuild *pGuild = FindGuild(::getId(pRoot["guild_id"]));
+ if (pGuild == nullptr)
+ return;
+
CMStringW wszUserId = pRoot["user"]["id"].as_mstring();
- CMStringW wszUserNick = pRoot["nick"].as_mstring(), wszOldNick;
- if (wszUserNick.IsEmpty())
- wszUserNick = pRoot["user"]["username"].as_mstring() + L"#" + pRoot["user"]["discriminator"].as_mstring();
+ CDiscordGuildMember *gm = pGuild->FindUser(_wtoi64(wszUserId));
+ if (gm == NULL)
+ return;
+
+ gm->wszNick = pRoot["nick"].as_mstring();
+ if (gm->wszNick.IsEmpty())
+ gm->wszNick = pRoot["user"]["username"].as_mstring() + L"#" + pRoot["user"]["discriminator"].as_mstring();
for (int i = 0; i < arUsers.getCount(); i++) {
CDiscordUser &pUser = arUsers[i];
- if (pUser.guildId != guildId)
+ if (pUser.guildId != pGuild->id)
continue;
+ CMStringW wszOldNick;
SESSION_INFO *si = pci->SM_FindSession(pUser.wszUsername, m_szModuleName);
if (si != nullptr) {
USERINFO *ui = pci->UM_FindUser(si->pUsers, wszUserId);
@@ -375,7 +296,7 @@ void CDiscordProto::OnCommandGuildMemberUpdated(const JSONNode &pRoot)
gce.time = time(0);
gce.ptszUID = wszUserId;
gce.ptszNick = wszOldNick;
- gce.ptszText = wszUserNick;
+ gce.ptszText = gm->wszNick;
Chat_Event(&gce);
}
}
@@ -385,34 +306,40 @@ void CDiscordProto::OnCommandGuildMemberUpdated(const JSONNode &pRoot)
void CDiscordProto::OnCommandRoleCreated(const JSONNode &pRoot)
{
- ProcessRole(::getId(pRoot["guild_id"]), pRoot["role"]);
+ CDiscordGuild *pGuild = FindGuild(::getId(pRoot["guild_id"]));
+ if (pGuild != nullptr)
+ ProcessRole(pGuild, pRoot["role"]);
}
void CDiscordProto::OnCommandRoleDeleted(const JSONNode &pRoot)
{
- SnowFlake id = ::getId(pRoot["role_id"]), guildId = ::getId(pRoot["guild_id"]);
- CDiscordRole *pRole = arRoles.find((CDiscordRole*)&id);
+ CDiscordGuild *pGuild = FindGuild(::getId(pRoot["guild_id"]));
+ if (pGuild == nullptr)
+ return;
+
+ SnowFlake id = ::getId(pRoot["role_id"]);
+ CDiscordRole *pRole = pGuild->arRoles.find((CDiscordRole*)&id);
if (pRole == nullptr)
return;
int iOldPosition = pRole->position;
- arRoles.remove(pRole);
+ pGuild->arRoles.remove(pRole);
- for (int i = 0; i < arRoles.getCount(); i++) {
- CDiscordRole &p = arRoles[i];
- if (p.guildId == guildId && p.position > iOldPosition)
+ for (int i = 0; i < pGuild->arRoles.getCount(); i++) {
+ CDiscordRole &p = pGuild->arRoles[i];
+ if (p.position > iOldPosition)
p.position--;
}
for (int i = 0; i < arUsers.getCount(); i++) {
CDiscordUser &p = arUsers[i];
- if (p.guildId != guildId)
+ if (p.guildId != pGuild->id)
continue;
SESSION_INFO *si = pci->SM_FindSession(p.wszUsername, m_szModuleName);
if (si != nullptr) {
pci->TM_RemoveAll(&si->pStatuses);
- BuildStatusList(guildId, p.wszUsername);
+ BuildStatusList(pGuild, p.wszUsername);
}
}
}
@@ -543,12 +470,9 @@ void CDiscordProto::OnCommandReady(const JSONNode &pRoot)
m_szGatewaySessionId = pRoot["session_id"].as_mstring();
- const JSONNode &readState = pRoot["read_state"];
- const JSONNode &pStatuses = pRoot["presences"];
-
const JSONNode &guilds = pRoot["guilds"];
for (auto it = guilds.begin(); it != guilds.end(); ++it)
- ProcessGuild(readState, *it);
+ ProcessGuild(*it);
const JSONNode &relations = pRoot["relationships"];
for (auto it = relations.begin(); it != relations.end(); ++it) {
@@ -556,10 +480,15 @@ void CDiscordProto::OnCommandReady(const JSONNode &pRoot)
CDiscordUser *pUser = PrepareUser(p["user"]);
ProcessType(pUser, p);
+ }
- int iStatus = sttGetPresence(pStatuses, p["user"]["id"].as_mstring());
- if (iStatus)
- setWord(pUser->hContact, "Status", iStatus);
+ const JSONNode &pStatuses = pRoot["presences"];
+ for (auto it = pStatuses.begin(); it != pStatuses.end(); ++it) {
+ const JSONNode &p = *it;
+
+ CDiscordUser *pUser = FindUser(::getId(p["user"]["id"]));
+ if (pUser != nullptr)
+ setWord(pUser->hContact, "Status", StrToStatus(p["status"].as_mstring()));
}
const JSONNode &channels = pRoot["private_channels"];
@@ -577,7 +506,6 @@ void CDiscordProto::OnCommandReady(const JSONNode &pRoot)
CMStringW wszChannelId = p["id"].as_mstring();
pUser->channelId = _wtoi64(wszChannelId);
pUser->lastMsg = CDiscordMessage(::getId(p["last_message_id"]));
- pUser->lastReadId = sttGetLastRead(readState, wszChannelId);
pUser->bIsPrivate = true;
setId(pUser->hContact, DB_KEY_CHANNELID, pUser->channelId);
@@ -586,6 +514,14 @@ void CDiscordProto::OnCommandReady(const JSONNode &pRoot)
if (pUser->lastMsg.id > oldMsgId)
RetrieveHistory(pUser->hContact, MSG_AFTER, oldMsgId, 99);
}
+
+ const JSONNode &readState = pRoot["read_state"];
+ for (auto it = readState.begin(); it != readState.end(); ++it) {
+ const JSONNode &p = *it;
+ CDiscordUser *pUser = FindUserByChannel(::getId(p["id"]));
+ if (pUser != nullptr)
+ pUser->lastReadId = ::getId(p["last_message_id"]);
+ }
}
/////////////////////////////////////////////////////////////////////////////////////////