summaryrefslogtreecommitdiff
path: root/protocols
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2020-01-15 23:27:07 +0300
committerGeorge Hazan <ghazan@miranda.im>2020-01-15 23:27:07 +0300
commit28880a272962ca55298b4304bf6f5512bda901d2 (patch)
treebb7e23bf6daa82456981084ff6d96c7d9f6e4746 /protocols
parent53aab07f1ee1dc3fe8c48dbe95a434079013f260 (diff)
Discord voice calls - packet processing
Diffstat (limited to 'protocols')
-rw-r--r--protocols/Discord/res/discord.rc3
-rw-r--r--protocols/Discord/res/voiceCall.icobin0 -> 2038 bytes
-rw-r--r--protocols/Discord/res/voiceEnded.icobin0 -> 2038 bytes
-rw-r--r--protocols/Discord/src/dispatch.cpp72
-rw-r--r--protocols/Discord/src/main.cpp4
-rw-r--r--protocols/Discord/src/proto.cpp16
-rw-r--r--protocols/Discord/src/proto.h57
-rw-r--r--protocols/Discord/src/resource.h2
8 files changed, 132 insertions, 22 deletions
diff --git a/protocols/Discord/res/discord.rc b/protocols/Discord/res/discord.rc
index 47156ab6c7..93febddec9 100644
--- a/protocols/Discord/res/discord.rc
+++ b/protocols/Discord/res/discord.rc
@@ -56,6 +56,9 @@ IDI_MAIN ICON "discord.ico"
IDI_GROUPCHAT ICON "groupchat.ico"
+IDI_VOICE_CALL ICON "voiceCall.ico"
+
+IDI_VOICE_ENDED ICON "voiceEnded.ico"
/////////////////////////////////////////////////////////////////////////////
//
diff --git a/protocols/Discord/res/voiceCall.ico b/protocols/Discord/res/voiceCall.ico
new file mode 100644
index 0000000000..6559874da9
--- /dev/null
+++ b/protocols/Discord/res/voiceCall.ico
Binary files differ
diff --git a/protocols/Discord/res/voiceEnded.ico b/protocols/Discord/res/voiceEnded.ico
new file mode 100644
index 0000000000..397ecb2b12
--- /dev/null
+++ b/protocols/Discord/res/voiceEnded.ico
Binary files differ
diff --git a/protocols/Discord/src/dispatch.cpp b/protocols/Discord/src/dispatch.cpp
index 3766361a4b..b22e76f583 100644
--- a/protocols/Discord/src/dispatch.cpp
+++ b/protocols/Discord/src/dispatch.cpp
@@ -28,6 +28,10 @@ struct CDiscordCommand
}
static handlers[] = // these structures must me sorted alphabetically
{
+ { L"CALL_CREATE", &CDiscordProto::OnCommandCallCreated },
+ { L"CALL_DELETE", &CDiscordProto::OnCommandCallDeleted },
+ { L"CALL_UPDATE", &CDiscordProto::OnCommandCallUpdated },
+
{ L"CHANNEL_CREATE", &CDiscordProto::OnCommandChannelCreated },
{ L"CHANNEL_DELETE", &CDiscordProto::OnCommandChannelDeleted },
{ L"CHANNEL_UPDATE", &CDiscordProto::OnCommandChannelUpdated },
@@ -72,6 +76,74 @@ GatewayHandlerFunc CDiscordProto::GetHandler(const wchar_t *pwszCommand)
}
/////////////////////////////////////////////////////////////////////////////////////////
+// call operations (voice & video)
+
+void CDiscordProto::OnCommandCallCreated(const JSONNode &pRoot)
+{
+ for (auto &it : pRoot["voice_states"]) {
+ SnowFlake channelId = ::getId(pRoot["channel_id"]);
+ auto *pUser = FindUserByChannel(channelId);
+ if (pUser == nullptr) {
+ debugLogA("Call from unknown channel %lld, skipping", channelId);
+ continue;
+ }
+
+ auto *pCall = new CDiscordVoiceCall();
+ pCall->szId = it["session_id"].as_mstring();
+ pCall->channelId = channelId;
+ pCall->startTime = time(0);
+ arVoiceCalls.insert(pCall);
+
+ char *szMessage = TranslateU("Incoming voice call");
+ DBEVENTINFO dbei = {};
+ dbei.szModule = m_szModuleName;
+ dbei.timestamp = pCall->startTime;
+ dbei.eventType = EVENT_INCOMING_CALL;
+ dbei.cbBlob = DWORD(mir_strlen(szMessage)+1);
+ dbei.pBlob = (BYTE*)szMessage;
+ dbei.flags = DBEF_UTF;
+ db_event_add(pUser->hContact, &dbei);
+ }
+}
+
+void CDiscordProto::OnCommandCallDeleted(const JSONNode &pRoot)
+{
+ SnowFlake channelId = ::getId(pRoot["channel_id"]);
+ auto *pUser = FindUserByChannel(channelId);
+ if (pUser == nullptr) {
+ debugLogA("Call from unknown channel %lld, skipping", channelId);
+ return;
+ }
+
+ int elapsed = 0, currTime = time(0);
+ for (auto &call : arVoiceCalls.rev_iter())
+ if (call->channelId == channelId) {
+ elapsed = currTime - call->startTime;
+ arVoiceCalls.remove(arVoiceCalls.indexOf(&call));
+ break;
+ }
+
+ if (!elapsed) {
+ debugLogA("Call from channel %lld isn't registered, skipping", channelId);
+ return;
+ }
+
+ CMStringA szMessage(FORMAT, TranslateU("Voice call ended, %d seconds long"), elapsed);
+ DBEVENTINFO dbei = {};
+ dbei.szModule = m_szModuleName;
+ dbei.timestamp = currTime;
+ dbei.eventType = EVENT_CALL_FINISHED;
+ dbei.cbBlob = DWORD(szMessage.GetLength() + 1);
+ dbei.pBlob = (BYTE *)szMessage.c_str();
+ dbei.flags = DBEF_UTF;
+ db_event_add(pUser->hContact, &dbei);
+}
+
+void CDiscordProto::OnCommandCallUpdated(const JSONNode &pRoot)
+{
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
// channel operations
void CDiscordProto::OnCommandChannelCreated(const JSONNode &pRoot)
diff --git a/protocols/Discord/src/main.cpp b/protocols/Discord/src/main.cpp
index 559a0da4da..80d45c62f0 100644
--- a/protocols/Discord/src/main.cpp
+++ b/protocols/Discord/src/main.cpp
@@ -51,7 +51,9 @@ extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOC
IconItem g_iconList[] =
{
{ LPGEN("Main icon"), "main", IDI_MAIN },
- { LPGEN("Group chats"), "groupchat", IDI_GROUPCHAT }
+ { LPGEN("Group chats"), "groupchat", IDI_GROUPCHAT },
+ { LPGEN("Voice call"), "voicecall", IDI_VOICE_CALL },
+ { LPGEN("Call ended"), "voiceend", IDI_VOICE_ENDED }
};
int CMPlugin::Load()
diff --git a/protocols/Discord/src/proto.cpp b/protocols/Discord/src/proto.cpp
index 1051b57005..f07fa1bfab 100644
--- a/protocols/Discord/src/proto.cpp
+++ b/protocols/Discord/src/proto.cpp
@@ -46,6 +46,7 @@ CDiscordProto::CDiscordProto(const char *proto_name, const wchar_t *username) :
arGuilds(1, compareGuilds),
arMarkReadQueue(1, compareUsers),
arOwnMessages(1, compareMessages),
+ arVoiceCalls(1),
m_wszEmail(this, "Email", L""),
m_wszDefaultGroup(this, "GroupName", DB_KEYVAL_GROUP),
@@ -71,6 +72,21 @@ CDiscordProto::CDiscordProto(const char *proto_name, const wchar_t *username) :
// database
db_set_resident(m_szModuleName, "XStatusMsg");
+ // custom events
+ DBEVENTTYPEDESCR dbEventType = {};
+ dbEventType.module = m_szModuleName;
+ dbEventType.flags = DETF_HISTORY | DETF_MSGWINDOW;
+
+ dbEventType.eventType = EVENT_INCOMING_CALL;
+ dbEventType.descr = Translate("Incoming voice call");
+ dbEventType.eventIcon = g_plugin.getIconHandle(IDI_VOICE_CALL);
+ DbEvent_RegisterType(&dbEventType);
+
+ dbEventType.eventType = EVENT_CALL_FINISHED;
+ dbEventType.descr = Translate("Voice call ended");
+ dbEventType.eventIcon = g_plugin.getIconHandle(IDI_VOICE_ENDED);
+ DbEvent_RegisterType(&dbEventType);
+
// Network initialization
CMStringW descr;
NETLIBUSER nlu = {};
diff --git a/protocols/Discord/src/proto.h b/protocols/Discord/src/proto.h
index a25da70c5d..95e6f48d6b 100644
--- a/protocols/Discord/src/proto.h
+++ b/protocols/Discord/src/proto.h
@@ -1,5 +1,8 @@
#pragma once
+#define EVENT_INCOMING_CALL 10001
+#define EVENT_CALL_FINISHED 10002
+
typedef __int64 SnowFlake;
__forceinline int compareInt64(const SnowFlake i1, const SnowFlake i2)
@@ -111,6 +114,13 @@ struct CDiscordGuild : public MZeroedObject
OBJLIST<CDiscordRole> arRoles; // guild roles
};
+struct CDiscordVoiceCall
+{
+ CMStringA szId;
+ SnowFlake channelId;
+ time_t startTime;
+};
+
/////////////////////////////////////////////////////////////////////////////////////////
class CDiscordProto : public PROTO<CDiscordProto>
@@ -223,6 +233,7 @@ class CDiscordProto : public PROTO<CDiscordProto>
OBJLIST<CDiscordUser> arUsers;
OBJLIST<COwnMessage> arOwnMessages;
+ OBJLIST<CDiscordVoiceCall> arVoiceCalls;
CDiscordUser* FindUser(SnowFlake id);
CDiscordUser* FindUser(const wchar_t *pwszUsername, int iDiscriminator);
@@ -326,6 +337,7 @@ public:
INT_PTR __cdecl RequestFriendship(WPARAM, LPARAM);
INT_PTR __cdecl SvcCreateAccMgrUI(WPARAM, LPARAM);
+ INT_PTR __cdecl SvcGetEventIcon(WPARAM, LPARAM);
INT_PTR __cdecl GetAvatarCaps(WPARAM, LPARAM);
INT_PTR __cdecl GetAvatarInfo(WPARAM, LPARAM);
@@ -342,28 +354,31 @@ public:
//////////////////////////////////////////////////////////////////////////////////////
// dispatch commands
- void OnCommandChannelCreated(const JSONNode&);
- void OnCommandChannelDeleted(const JSONNode&);
- void OnCommandChannelUpdated(const JSONNode&);
- void OnCommandGuildCreated(const JSONNode&);
- void OnCommandGuildDeleted(const JSONNode&);
- void OnCommandGuildMemberAdded(const JSONNode&);
- void OnCommandGuildMemberRemoved(const JSONNode&);
- void OnCommandGuildMemberUpdated(const JSONNode&);
- void OnCommandGuildSync(const JSONNode&);
- void OnCommandFriendAdded(const JSONNode&);
- void OnCommandFriendRemoved(const JSONNode&);
+ void OnCommandCallCreated(const JSONNode &json);
+ void OnCommandCallDeleted(const JSONNode &json);
+ void OnCommandCallUpdated(const JSONNode &json);
+ void OnCommandChannelCreated(const JSONNode &json);
+ void OnCommandChannelDeleted(const JSONNode &json);
+ void OnCommandChannelUpdated(const JSONNode &json);
+ void OnCommandGuildCreated(const JSONNode &json);
+ void OnCommandGuildDeleted(const JSONNode &json);
+ void OnCommandGuildMemberAdded(const JSONNode &json);
+ void OnCommandGuildMemberRemoved(const JSONNode &json);
+ void OnCommandGuildMemberUpdated(const JSONNode &json);
+ void OnCommandGuildSync(const JSONNode &json);
+ void OnCommandFriendAdded(const JSONNode &json);
+ void OnCommandFriendRemoved(const JSONNode &json);
void OnCommandMessage(const JSONNode&, bool);
- void OnCommandMessageCreate(const JSONNode&);
- void OnCommandMessageUpdate(const JSONNode&);
- void OnCommandMessageAck(const JSONNode&);
- void OnCommandPresence(const JSONNode&);
- void OnCommandReady(const JSONNode&);
- void OnCommandRoleCreated(const JSONNode&);
- void OnCommandRoleDeleted(const JSONNode&);
- void OnCommandTyping(const JSONNode&);
- void OnCommandUserUpdate(const JSONNode&);
- void OnCommandUserSettingsUpdate(const JSONNode&);
+ void OnCommandMessageCreate(const JSONNode &json);
+ void OnCommandMessageUpdate(const JSONNode &json);
+ void OnCommandMessageAck(const JSONNode &json);
+ void OnCommandPresence(const JSONNode &json);
+ void OnCommandReady(const JSONNode &json);
+ void OnCommandRoleCreated(const JSONNode &json);
+ void OnCommandRoleDeleted(const JSONNode &json);
+ void OnCommandTyping(const JSONNode &json);
+ void OnCommandUserUpdate(const JSONNode &json);
+ void OnCommandUserSettingsUpdate(const JSONNode &json);
void OnLoggedIn();
void OnLoggedOut();
diff --git a/protocols/Discord/src/resource.h b/protocols/Discord/src/resource.h
index a434f423de..b979e4775b 100644
--- a/protocols/Discord/src/resource.h
+++ b/protocols/Discord/src/resource.h
@@ -7,6 +7,8 @@
#define IDD_OPTIONS_ACCOUNT 103
#define IDD_EXTSEARCH 104
#define IDD_OPTIONS_ACCMGR 105
+#define IDI_VOICE_CALL 106
+#define IDI_VOICE_ENDED 107
#define IDC_PASSWORD 1001
#define IDC_USERNAME 1002
#define IDC_GROUP 1003