summaryrefslogtreecommitdiff
path: root/protocols/Discord/src/dispatch.cpp
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2017-01-07 22:57:57 +0300
committerGeorge Hazan <ghazan@miranda.im>2017-01-07 22:57:57 +0300
commitf1a204292b895a94f142c32b2f3dc69fcc053e67 (patch)
tree465127e97ce90f457c90b8cfc78ae8f0e00b5064 /protocols/Discord/src/dispatch.cpp
parente012650957335d5f4295441debf849b3b9b2f4ef (diff)
first version of Discord that sends messages, catches presence packets and displays typing notification
version bump
Diffstat (limited to 'protocols/Discord/src/dispatch.cpp')
-rw-r--r--protocols/Discord/src/dispatch.cpp120
1 files changed, 120 insertions, 0 deletions
diff --git a/protocols/Discord/src/dispatch.cpp b/protocols/Discord/src/dispatch.cpp
index f9cf006a09..e96471f116 100644
--- a/protocols/Discord/src/dispatch.cpp
+++ b/protocols/Discord/src/dispatch.cpp
@@ -19,6 +19,102 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
extern HWND g_hwndHeartbeat;
+#pragma pack(4)
+
+struct CDiscordCommand
+{
+ const wchar_t *szCommandId;
+ GatewayHandlerFunc pFunc;
+}
+static handlers[] = // these structures must me sorted alphabetically
+{
+ { L"MESSAGE_CREATE", &CDiscordProto::OnCommandMessage },
+ { L"MESSAGE_UPDATE", &CDiscordProto::OnCommandMessage },
+
+ { L"PRESENCE_UPDATE", &CDiscordProto::OnCommandPresence },
+
+ { L"READY", &CDiscordProto::OnCommandReady },
+
+ { L"TYPING_START", &CDiscordProto::OnCommandTyping },
+};
+
+static int __cdecl pSearchFunc(const void *p1, const void *p2)
+{
+ return wcscmp(((CDiscordCommand*)p1)->szCommandId, ((CDiscordCommand*)p2)->szCommandId);
+}
+
+GatewayHandlerFunc CDiscordProto::GetHandler(const wchar_t *pwszCommand)
+{
+ CDiscordCommand tmp = { pwszCommand, NULL };
+ CDiscordCommand *p = (CDiscordCommand*)bsearch(&tmp, handlers, _countof(handlers), sizeof(handlers[0]), pSearchFunc);
+ return (p != NULL) ? p->pFunc : NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+// reading a new message
+
+void CDiscordProto::OnCommandMessage(const JSONNode &pRoot)
+{
+ PROTORECVEVENT recv = {};
+
+ CDiscordUser *pUser = PrepareUser(pRoot["author"]);
+ SnowFlake channelId = _wtoi64(pRoot["channel_id"].as_mstring());
+ CMStringW msgId = pRoot["id"].as_mstring();
+ CMStringW wszText = pRoot["content"].as_mstring();
+
+ // if a message has myself as an author, mark it as sent
+ if (pUser->id == 0)
+ return;
+
+ const JSONNode &edited = pRoot["edited_timestamp"];
+ if (!edited.isnull())
+ wszText.AppendFormat(L" (%s %s)", TranslateT("edited at"), edited.as_mstring().c_str());
+
+ if (pUser->channelId != channelId) {
+ debugLogA("failed to process a groupchat message, exiting");
+ return;
+ }
+
+ ptrA buf(mir_utf8encodeW(wszText));
+ recv.timestamp = (DWORD)StringToDate(pRoot["timestamp"].as_mstring());
+ recv.szMessage = buf;
+ recv.lParam = (LPARAM)msgId.c_str();
+ ProtoChainRecvMsg(pUser->hContact, &recv);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+// someone changed its status
+
+void CDiscordProto::OnCommandPresence(const JSONNode &pRoot)
+{
+ CDiscordUser *pUser = PrepareUser(pRoot["user"]);
+ if (pUser == NULL)
+ return;
+
+ int iStatus;
+ CMStringW wszStatus = pRoot["status"].as_mstring();
+ if (wszStatus == L"idle")
+ iStatus = ID_STATUS_IDLE;
+ else if (wszStatus == L"online")
+ iStatus = ID_STATUS_ONLINE;
+ else if (wszStatus == L"offline")
+ iStatus = ID_STATUS_OFFLINE;
+ else
+ iStatus = 0;
+
+ if (iStatus != 0)
+ setWord(pUser->hContact, "Status", iStatus);
+
+ CMStringW wszGame = pRoot["game"]["name"].as_mstring();
+ if (!wszGame.IsEmpty())
+ setWString(pUser->hContact, "XStatusMsg", wszGame);
+ else
+ delSetting(pUser->hContact, "XStatusMsg");
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+// gateway session start
+
void CALLBACK CDiscordProto::HeartbeatTimerProc(HWND, UINT, UINT_PTR id, DWORD)
{
((CDiscordProto*)id)->GatewaySendHeartbeat();
@@ -62,3 +158,27 @@ void CDiscordProto::OnCommandReady(const JSONNode &pRoot)
setId(pUser->hContact, DB_KEY_CHANNELID, pUser->channelId);
}
}
+
+//////////////////////////////////////////////////////////////////////////////////////
+// UTN support
+
+void CDiscordProto::OnCommandTyping(const JSONNode &pRoot)
+{
+ SnowFlake userId = _wtoi64(pRoot["user_id"].as_mstring());
+ SnowFlake channelId = _wtoi64(pRoot["channel_id"].as_mstring());
+ debugLogA("user typing notification: userid=%lld, channelid=%lld", userId, channelId);
+
+ CDiscordUser *pUser = FindUser(userId);
+ if (pUser == NULL) {
+ debugLogA("user with id=%lld is not found", userId);
+ return;
+ }
+
+ if (pUser->channelId == channelId) {
+ debugLogA("user is typing in his private channel");
+ CallService(MS_PROTO_CONTACTISTYPING, pUser->hContact, 20);
+ }
+ else {
+ debugLogA("user is typing in a group channel, skipped");
+ }
+}