summaryrefslogtreecommitdiff
path: root/protocols/Discord
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2017-01-03 19:10:33 +0300
committerGeorge Hazan <ghazan@miranda.im>2017-01-03 19:10:33 +0300
commit1b5e5bbb9f7abc2d56cf0ef0ffe7cd281854c874 (patch)
tree45c59c30b55c117807a964b120ef6df253fa1296 /protocols/Discord
parente8ccd6330c478c4196dd1cedeeddf14add597784 (diff)
server history syncing support
Diffstat (limited to 'protocols/Discord')
-rw-r--r--protocols/Discord/proto_discord/res/Invisible.icobin4150 -> 5430 bytes
-rw-r--r--protocols/Discord/src/proto.cpp18
-rw-r--r--protocols/Discord/src/proto.h11
-rw-r--r--protocols/Discord/src/server.cpp72
-rw-r--r--protocols/Discord/src/stdafx.h2
-rw-r--r--protocols/Discord/src/utils.cpp18
6 files changed, 120 insertions, 1 deletions
diff --git a/protocols/Discord/proto_discord/res/Invisible.ico b/protocols/Discord/proto_discord/res/Invisible.ico
index c2830ed132..3c27bb3f03 100644
--- a/protocols/Discord/proto_discord/res/Invisible.ico
+++ b/protocols/Discord/proto_discord/res/Invisible.ico
Binary files differ
diff --git a/protocols/Discord/src/proto.cpp b/protocols/Discord/src/proto.cpp
index 358f4e7bf6..41179a5a2d 100644
--- a/protocols/Discord/src/proto.cpp
+++ b/protocols/Discord/src/proto.cpp
@@ -40,6 +40,7 @@ CDiscordProto::CDiscordProto(const char *proto_name, const wchar_t *username) :
// Events
HookProtoEvent(ME_OPT_INITIALISE, &CDiscordProto::OnOptionsInit);
+ HookProtoEvent(ME_MSG_WINDOWEVENT, &CDiscordProto::OnSrmmEvent);
// Clist
Clist_GroupCreate(NULL, m_wszDefaultGroup);
@@ -267,6 +268,23 @@ int CDiscordProto::OnPreShutdown(WPARAM, LPARAM)
/////////////////////////////////////////////////////////////////////////////////////////
+int CDiscordProto::OnSrmmEvent(WPARAM, LPARAM lParam)
+{
+ MessageWindowEventData *MWeventdata = (MessageWindowEventData*)lParam;
+
+ if (MWeventdata->uType == MSG_WINDOW_EVT_OPENING && MWeventdata->hContact) {
+ SnowFlake oldid = getId(MWeventdata->hContact, DB_KEY_LASTMSGID);
+ if (oldid > 0)
+ RetrieveHistory(MWeventdata->hContact, MSG_AFTER, oldid, 99);
+ else
+ RetrieveHistory(MWeventdata->hContact, MSG_NOFILTER, 0, 99);
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
int CDiscordProto::OnEvent(PROTOEVENTTYPE event, WPARAM wParam, LPARAM lParam)
{
switch (event) {
diff --git a/protocols/Discord/src/proto.h b/protocols/Discord/src/proto.h
index ee9569781c..8d0e6c24fb 100644
--- a/protocols/Discord/src/proto.h
+++ b/protocols/Discord/src/proto.h
@@ -59,6 +59,11 @@ JSONNode& operator<<(JSONNode &json, const WCHAR_PARAM &param);
/////////////////////////////////////////////////////////////////////////////////////////
+enum CDiscordHitoryOp
+{
+ MSG_NOFILTER, MSG_AFTER, MSG_BEFORE
+};
+
struct CDiscordUser : public MZeroedObject
{
CDiscordUser(SnowFlake _id) :
@@ -161,18 +166,22 @@ public:
int __cdecl OnModulesLoaded(WPARAM, LPARAM);
int __cdecl OnPreShutdown(WPARAM, LPARAM);
int __cdecl OnOptionsInit(WPARAM, LPARAM);
+ int __cdecl OnSrmmEvent(WPARAM, LPARAM);
void OnLoggedIn();
void OnLoggedOut();
void OnReceiveAuth(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
void OnReceiveToken(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
- void OnReceiveUserInfo(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
void OnReceiveGuilds(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
void OnReceiveChannels(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
void OnReceiveFriends(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
void RetrieveUserInfo(MCONTACT hContact);
+ void OnReceiveUserInfo(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
+
+ void RetrieveHistory(MCONTACT hContact, CDiscordHitoryOp iOp = MSG_NOFILTER, SnowFlake msgid = 0, int iLimit = 50);
+ void OnReceiveHistory(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
// Misc
void SetServerStatus(int iStatus);
diff --git a/protocols/Discord/src/server.cpp b/protocols/Discord/src/server.cpp
index b8af77f8cb..a5ac8e215a 100644
--- a/protocols/Discord/src/server.cpp
+++ b/protocols/Discord/src/server.cpp
@@ -17,6 +17,76 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdafx.h"
+/////////////////////////////////////////////////////////////////////////////////////////
+// retrieves server history
+
+void CDiscordProto::RetrieveHistory(MCONTACT hContact, CDiscordHitoryOp iOp, SnowFlake msgid, int iLimit)
+{
+ CDiscordUser *pUser = FindUser(getId(hContact, DB_KEY_ID));
+ if (pUser == NULL)
+ return;
+
+ CMStringA szUrl(FORMAT, "/channels/%lld/messages", pUser->channelId);
+ AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_GET, szUrl, &CDiscordProto::OnReceiveHistory);
+ pReq << INT_PARAM("limit", iLimit);
+ switch (iOp) {
+ case MSG_AFTER:
+ pReq << CHAR_PARAM("after", CMStringA(FORMAT, "%lld", msgid)); break;
+ case MSG_BEFORE:
+ pReq << CHAR_PARAM("before", CMStringA(FORMAT, "%lld", msgid)); break;
+ }
+ pReq->pUserInfo = pUser;
+ Push(pReq);
+}
+
+void CDiscordProto::OnReceiveHistory(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
+{
+ CDiscordUser *pUser = (CDiscordUser*)pReq->pUserInfo;
+
+ if (pReply->resultCode != 200)
+ return;
+
+ JSONNode root = JSONNode::parse(pReply->pData);
+ if (!root)
+ return;
+
+ DBEVENTINFO dbei = {};
+ dbei.cbSize = sizeof(dbei);
+ dbei.szModule = m_szModuleName;
+ dbei.flags = DBEF_READ | DBEF_UTF;
+ dbei.eventType = EVENTTYPE_MESSAGE;
+
+ SnowFlake lastId = getId(pUser->hContact, DB_KEY_LASTMSGID); // as stored in a database
+
+ for (auto it = root.begin(); it != root.end(); ++it) {
+ JSONNode &p = *it;
+
+ SnowFlake authorid = _wtoi64(p["author"]["id"].as_mstring());
+ if (authorid == m_ownId)
+ dbei.flags |= DBEF_SENT;
+ else
+ dbei.flags &= ~DBEF_SENT;
+
+ SnowFlake msgid = _wtoi64(p["id"].as_mstring());
+
+ CMStringA szBody(ptrA(mir_utf8encodeW(p["content"].as_mstring())));
+ szBody.AppendFormat("%c%lld", 0, msgid);
+
+ dbei.timestamp = StringToDate(p["timestamp"].as_mstring());
+ dbei.pBlob = (PBYTE)szBody.GetBuffer();
+ dbei.cbBlob = szBody.GetLength();
+ db_event_add(pUser->hContact, &dbei);
+
+ if (lastId < msgid)
+ lastId = msgid;
+ }
+
+ setId(pUser->hContact, DB_KEY_LASTMSGID, lastId);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// retrieves user info
+
void CDiscordProto::RetrieveUserInfo(MCONTACT hContact)
{
AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_GET, "/users/@me", &CDiscordProto::OnReceiveUserInfo);
@@ -96,6 +166,8 @@ void CDiscordProto::OnReceiveChannels(NETLIBHTTPREQUEST *pReply, AsyncHttpReques
pUser->lastMessageId = _wtoi64(p["last_message_id"].as_mstring());
pUser->channelId = _wtoi64(p["id"].as_mstring());
pUser->bIsPrivate = p["is_private"].as_bool();
+
+ setId(pUser->hContact, DB_KEY_CHANNELID, pUser->channelId);
}
}
diff --git a/protocols/Discord/src/stdafx.h b/protocols/Discord/src/stdafx.h
index e0177716ab..43d0077d7c 100644
--- a/protocols/Discord/src/stdafx.h
+++ b/protocols/Discord/src/stdafx.h
@@ -56,3 +56,5 @@ extern HINSTANCE g_hInstance;
#define DB_KEY_GROUP "GroupName"
#define DB_KEYVAL_GROUP L"Discord"
+
+time_t StringToDate(const CMStringW &str);
diff --git a/protocols/Discord/src/utils.cpp b/protocols/Discord/src/utils.cpp
index 5913f6ef33..0513e49aac 100644
--- a/protocols/Discord/src/utils.cpp
+++ b/protocols/Discord/src/utils.cpp
@@ -46,6 +46,24 @@ JSONNode& operator<<(JSONNode &json, const WCHAR_PARAM &param)
/////////////////////////////////////////////////////////////////////////////////////////
+time_t StringToDate(const CMStringW &str)
+{
+ struct tm T = { 0 };
+ int boo;
+ if (swscanf(str, L"%04d-%02d-%02dT%02d:%02d:%02d.%d", &T.tm_year, &T.tm_mon, &T.tm_mday, &T.tm_hour, &T.tm_min, &T.tm_sec, &boo) != 7)
+ return 0;
+
+ T.tm_year -= 1900;
+ T.tm_mon--;
+ time_t t = mktime(&T);
+
+ _tzset();
+ t -= _timezone;
+ return (t >= 0) ? t : 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
SnowFlake CDiscordProto::getId(const char *szSetting)
{
DBVARIANT dbv;