summaryrefslogtreecommitdiff
path: root/protocols/Discord
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2016-12-30 00:49:15 +0300
committerGeorge Hazan <ghazan@miranda.im>2016-12-30 00:49:15 +0300
commit37ae1c46680e624dddddfee816f19cf920f95348 (patch)
tree0a32c5252055340cc8b11c6833173706902eee1d /protocols/Discord
parent50e87bcbf1b3a716f155e504a09df1c0ff1a66f5 (diff)
Discord:
- user search works; - friend list support; - channel list support; - various fixes
Diffstat (limited to 'protocols/Discord')
-rw-r--r--protocols/Discord/res/discord.rc9
-rw-r--r--protocols/Discord/src/connection.cpp3
-rw-r--r--protocols/Discord/src/options.cpp4
-rw-r--r--protocols/Discord/src/proto.cpp145
-rw-r--r--protocols/Discord/src/proto.h55
-rw-r--r--protocols/Discord/src/resource.h4
-rw-r--r--protocols/Discord/src/server.cpp88
-rw-r--r--protocols/Discord/src/stdafx.h11
-rw-r--r--protocols/Discord/src/utils.cpp70
-rw-r--r--protocols/Discord/src/version.h2
10 files changed, 349 insertions, 42 deletions
diff --git a/protocols/Discord/res/discord.rc b/protocols/Discord/res/discord.rc
index 41366bcd7b..fc31363075 100644
--- a/protocols/Discord/res/discord.rc
+++ b/protocols/Discord/res/discord.rc
@@ -76,6 +76,15 @@ BEGIN
EDITTEXT IDC_GROUP,84,89,123,13,ES_AUTOHSCROLL
END
+IDD_EXTSEARCH DIALOGEX 0, 0, 114, 55
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
+EXSTYLE WS_EX_TRANSPARENT | WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Nick:",IDC_STATIC,6,7,99,8
+ EDITTEXT IDC_NICK,3,18,103,12,0,WS_EX_CLIENTEDGE
+END
+
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
diff --git a/protocols/Discord/src/connection.cpp b/protocols/Discord/src/connection.cpp
index df3dbfa440..7b2cc097c9 100644
--- a/protocols/Discord/src/connection.cpp
+++ b/protocols/Discord/src/connection.cpp
@@ -66,6 +66,7 @@ void CDiscordProto::OnLoggedIn()
Push(new AsyncHttpRequest(this, REQUEST_GET, "/users/@me/guilds", &CDiscordProto::OnReceiveGuilds));
Push(new AsyncHttpRequest(this, REQUEST_GET, "/users/@me/channels", &CDiscordProto::OnReceiveChannels));
+ Push(new AsyncHttpRequest(this, REQUEST_GET, "/users/@me/relationships", &CDiscordProto::OnReceiveFriends));
}
void CDiscordProto::OnLoggedOut()
@@ -109,7 +110,7 @@ void CDiscordProto::ServerThread(void*)
if (m_szAccessToken != NULL)
// try to receive a response from server
- RetrieveMyInfo();
+ RetrieveUserInfo(NULL);
else {
if (mir_wstrlen(m_wszEmail) == NULL) {
ConnectionFailed(LOGINERR_BADUSERID);
diff --git a/protocols/Discord/src/options.cpp b/protocols/Discord/src/options.cpp
index d57f8d27af..b6cde0f39d 100644
--- a/protocols/Discord/src/options.cpp
+++ b/protocols/Discord/src/options.cpp
@@ -17,6 +17,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdafx.h"
+/////////////////////////////////////////////////////////////////////////////////////////
+
class CDiscardAccountOptions : public CProtoDlgBase<CDiscordProto>
{
CCtrlEdit m_edGroup, m_edUserName, m_edPassword;
@@ -51,6 +53,8 @@ public:
}
};
+/////////////////////////////////////////////////////////////////////////////////////////
+
int CDiscordProto::OnOptionsInit(WPARAM wParam, LPARAM)
{
OPTIONSDIALOGPAGE odp = { 0 };
diff --git a/protocols/Discord/src/proto.cpp b/protocols/Discord/src/proto.cpp
index 39ec101779..e2947e0594 100644
--- a/protocols/Discord/src/proto.cpp
+++ b/protocols/Discord/src/proto.cpp
@@ -22,12 +22,18 @@ static int compareRequests(const AsyncHttpRequest *p1, const AsyncHttpRequest *p
return p1->m_iReqNum - p2->m_iReqNum;
}
+static int compareUsers(const CDiscordUser *p1, const CDiscordUser *p2)
+{
+ return p1->id - p2->id;
+}
+
CDiscordProto::CDiscordProto(const char *proto_name, const wchar_t *username) :
PROTO<CDiscordProto>(proto_name, username),
m_arHttpQueue(10, compareRequests),
m_evRequestsQueue(CreateEvent(NULL, FALSE, FALSE, NULL)),
m_wszDefaultGroup(this, DB_KEY_GROUP, DB_KEYVAL_GROUP),
- m_wszEmail(this, DB_KEY_EMAIL, L"")
+ m_wszEmail(this, DB_KEY_EMAIL, L""),
+ arUsers(50, compareUsers)
{
// Services
CreateProtoService(PS_GETNAME, &CDiscordProto::GetName);
@@ -39,6 +45,17 @@ CDiscordProto::CDiscordProto(const char *proto_name, const wchar_t *username) :
// Clist
Clist_GroupCreate(NULL, m_wszDefaultGroup);
+ // Fill users list
+ for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
+ CDiscordUser *pNew = new CDiscordUser(getId(hContact, DB_KEY_ID));
+ pNew->hContact = hContact;
+ pNew->channelId = getId(hContact, DB_KEY_CHANNELID);
+ pNew->lastMessageId = getId(hContact, DB_KEY_LASTMSGID);
+ pNew->wszUsername = ptrW(getWStringA(hContact, DB_KEY_NICK));
+ pNew->iDiscriminator = getDword(hContact, DB_KEY_DISCR);
+ arUsers.insert(pNew);
+ }
+
// Network initialization
CMStringW descr(FORMAT, TranslateT("%s server connection"), m_tszUserName);
@@ -63,15 +80,14 @@ DWORD_PTR CDiscordProto::GetCaps(int type, MCONTACT)
{
switch (type) {
case PFLAGNUM_1:
- return PF1_IM | PF1_MODEMSGRECV | PF1_SERVERCLIST;
+ return PF1_IM | PF1_MODEMSGRECV | PF1_SERVERCLIST | PF1_BASICSEARCH | PF1_EXTSEARCH | PF1_ADDSEARCHRES;
case PFLAGNUM_2:
- return PF2_ONLINE;
case PFLAGNUM_3:
- return PF2_ONLINE;
+ return PF2_ONLINE | PF2_HEAVYDND | PF2_INVISIBLE | PF2_IDLE;
case PFLAGNUM_4:
- return PF4_NOCUSTOMAUTH | PF4_AVATARS;
+ return PF4_FORCEADDED | PF4_FORCEAUTH | PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_SUPPORTTYPING | PF4_SUPPORTIDLE | PF4_AVATARS | PF4_IMSENDOFFLINE;
case PFLAG_UNIQUEIDTEXT:
- return (DWORD_PTR)"E-mail";
+ return (DWORD_PTR)Translate("User ID");
case PFLAG_UNIQUEIDSETTING:
return (DWORD_PTR)DB_KEY_EMAIL;
}
@@ -125,6 +141,123 @@ int CDiscordProto::SetStatus(int iNewStatus)
/////////////////////////////////////////////////////////////////////////////////////////
+static INT_PTR CALLBACK AdvancedSearchDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetFocus(GetDlgItem(hwndDlg, IDC_NICK));
+ return TRUE;
+
+ case WM_COMMAND:
+ if (HIWORD(wParam) == EN_SETFOCUS)
+ PostMessage(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndDlg);
+ }
+ return FALSE;
+}
+
+HWND CDiscordProto::CreateExtendedSearchUI(HWND hwndParent)
+{
+ if (hwndParent)
+ return CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_EXTSEARCH), hwndParent, AdvancedSearchDlgProc, 0);
+
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDiscordProto::SearchThread(void *param)
+{
+ Sleep(100);
+
+ PROTOSEARCHRESULT psr = { 0 };
+ psr.cbSize = sizeof(psr);
+ psr.flags = PSR_UNICODE;
+ psr.nick.w = (wchar_t*)param;
+ psr.firstName.w = L"";
+ psr.lastName.w = L"";
+ psr.id.w = (wchar_t*)param;
+ ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)param, (LPARAM)&psr);
+
+ ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)param, 0);
+ mir_free(param);
+}
+
+HWND CDiscordProto::SearchAdvanced(HWND hwndDlg)
+{
+ if (!m_bOnline || !IsWindow(hwndDlg))
+ return NULL;
+
+ wchar_t wszNick[200];
+ GetDlgItemTextW(hwndDlg, IDC_NICK, wszNick, _countof(wszNick));
+ if (wszNick[0] == 0) // empty string? reject
+ return NULL;
+
+ wchar_t *p = wcschr(wszNick, '#');
+ if (p == NULL) // wrong user id
+ return NULL;
+
+ p = mir_wstrdup(wszNick);
+ ForkThread(&CDiscordProto::SearchThread, p);
+ return (HWND)p;
+}
+
+HANDLE CDiscordProto::SearchBasic(const wchar_t *wszId)
+{
+ if (!m_bOnline)
+ return NULL;
+
+ CMStringA szUrl = "/users/";
+ szUrl.AppendFormat(ptrA(mir_utf8encodeW(wszId)));
+ AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_GET, szUrl, &CDiscordProto::OnReceiveUserInfo);
+ pReq->pUserInfo = (void*)-1;
+ Push(pReq);
+ return (HANDLE)1; // Success
+}
+
+int CDiscordProto::AuthRequest(MCONTACT hContact, const wchar_t*)
+{
+ ptrW wszUsername(getWStringA(hContact, DB_KEY_NICK));
+ int iDiscriminator(getDword(hContact, DB_KEY_DISCR, -1));
+ if (wszUsername == NULL || iDiscriminator == -1)
+ return 1; // error
+
+ JSONNode root; root << WCHAR_PARAM("username", wszUsername) << INT_PARAM("discriminator", iDiscriminator);
+ AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_POST, "/users/@me/relationships", &CDiscordProto::OnReceiveAuth, &root);
+ pReq->pUserInfo = (void*)hContact;
+ Push(pReq);
+ return 0;
+}
+
+MCONTACT CDiscordProto::AddToList(int flags, PROTOSEARCHRESULT *psr)
+{
+ if (psr->id.w == NULL)
+ return 0;
+
+ wchar_t *p = wcschr(psr->id.w, '#');
+ if (p == NULL)
+ return 0;
+
+ MCONTACT hContact = db_add_contact();
+ Proto_AddToContact(hContact, m_szModuleName);
+ if (flags & PALF_TEMPORARY)
+ db_set_b(hContact, "CList", "NotOnList", 1);
+
+ *p = 0;
+ CDiscordUser *pUser = new CDiscordUser(0);
+ pUser->hContact = hContact;
+ pUser->wszUsername = psr->id.w;
+ pUser->iDiscriminator = _wtoi(p + 1);
+ *p = '#';
+
+ setWString(hContact, DB_KEY_NICK, pUser->wszUsername);
+ setDword(hContact, DB_KEY_DISCR, pUser->iDiscriminator);
+
+ return hContact;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
int CDiscordProto::OnModulesLoaded(WPARAM, LPARAM)
{
return 0;
diff --git a/protocols/Discord/src/proto.h b/protocols/Discord/src/proto.h
index fe525284f3..83046a9c5c 100644
--- a/protocols/Discord/src/proto.h
+++ b/protocols/Discord/src/proto.h
@@ -59,12 +59,36 @@ JSONNode& operator<<(JSONNode &json, const WCHAR_PARAM &param);
/////////////////////////////////////////////////////////////////////////////////////////
+struct CDiscordUser : public MZeroedObject
+{
+ CDiscordUser(SnowFlake _id) :
+ id(_id)
+ {}
+
+ SnowFlake id;
+ MCONTACT hContact;
+
+ SnowFlake channelId;
+ SnowFlake lastMessageId;
+ bool bIsPrivate;
+
+ CMStringW wszUsername;
+ int iDiscriminator;
+};
+
class CDiscordProto : public PROTO<CDiscordProto>
{
friend struct AsyncHttpRequest;
friend class CDiscardAccountOptions;
+ //////////////////////////////////////////////////////////////////////////////////////
+ // threads
+
void __cdecl ServerThread(void*);
+ void __cdecl SearchThread(void *param);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // session control
void SetAllContactStatuses(int iStatus);
void ConnectionFailed(int iReason);
@@ -87,11 +111,25 @@ class CDiscordProto : public PROTO<CDiscordProto>
m_bOnline, // protocol is online
m_bTerminated; // Miranda's going down
+ //////////////////////////////////////////////////////////////////////////////////////
+ // options
+
CMOption<wchar_t*> m_wszEmail; // my own email
CMOption<wchar_t*> m_wszDefaultGroup; // clist group to store contacts
+ //////////////////////////////////////////////////////////////////////////////////////
+ // common data
+
SnowFlake m_ownId;
+ OBJLIST<CDiscordUser> arUsers;
+ CDiscordUser* FindUser(SnowFlake id);
+ CDiscordUser* FindUser(const wchar_t *pwszUsername, int iDiscriminator);
+ CDiscordUser* PrepareUser(const JSONNode&);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // misc methods
+
SnowFlake getId(const char *szName);
SnowFlake getId(MCONTACT hContact, const char *szName);
@@ -105,8 +143,15 @@ public:
// PROTO_INTERFACE
virtual DWORD_PTR __cdecl GetCaps(int, MCONTACT = 0) override;
- virtual int __cdecl SetStatus(int iNewStatus) override;
+ virtual HWND __cdecl CreateExtendedSearchUI(HWND owner) override;
+ virtual HWND __cdecl SearchAdvanced(HWND owner) override;
+ virtual HANDLE __cdecl SearchBasic(const wchar_t* id) override;
+ virtual MCONTACT __cdecl AddToList(int flags, PROTOSEARCHRESULT* psr) override;
+
+ virtual int __cdecl AuthRequest(MCONTACT hContact, const wchar_t*) override;
+
+ virtual int __cdecl SetStatus(int iNewStatus) override;
virtual int __cdecl OnEvent(PROTOEVENTTYPE, WPARAM, LPARAM) override;
// Services
@@ -120,13 +165,15 @@ public:
void OnLoggedIn();
void OnLoggedOut();
-
+
+ void OnReceiveAuth(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
void OnReceiveToken(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
- void OnReceiveMyInfo(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
+ void OnReceiveUserInfo(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
void OnReceiveGuilds(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
void OnReceiveChannels(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
+ void OnReceiveFriends(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
- void RetrieveMyInfo();
+ void RetrieveUserInfo(MCONTACT hContact);
// Misc
void SetServerStatus(int iStatus);
diff --git a/protocols/Discord/src/resource.h b/protocols/Discord/src/resource.h
index 44d79b91ae..840b444d17 100644
--- a/protocols/Discord/src/resource.h
+++ b/protocols/Discord/src/resource.h
@@ -6,10 +6,12 @@
#define IDI_MAIN 101
#define IDI_OFFLINE 102
#define IDD_OPTIONS_ACCOUNT 103
+#define IDD_EXTSEARCH 104
#define IDC_PASSWORD 1001
#define IDC_USERNAME 1002
#define IDC_GROUP 1003
+#define IDC_NICK 1004
// Next default values for new objects
//
@@ -17,7 +19,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 103
#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1004
+#define _APS_NEXT_CONTROL_VALUE 1005
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
diff --git a/protocols/Discord/src/server.cpp b/protocols/Discord/src/server.cpp
index 8f8f551890..3997742ccd 100644
--- a/protocols/Discord/src/server.cpp
+++ b/protocols/Discord/src/server.cpp
@@ -17,34 +17,40 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdafx.h"
-void CDiscordProto::RetrieveMyInfo()
+void CDiscordProto::RetrieveUserInfo(MCONTACT hContact)
{
- Push(new AsyncHttpRequest(this, REQUEST_GET, "/users/@me", &CDiscordProto::OnReceiveMyInfo));
+ AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_GET, "/users/@me", &CDiscordProto::OnReceiveUserInfo);
+ pReq->pUserInfo = (void*)hContact;
+ Push(pReq);
}
-void CDiscordProto::OnReceiveMyInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*)
+void CDiscordProto::OnReceiveUserInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
{
+ MCONTACT hContact = (MCONTACT)pReq->pUserInfo;
if (pReply->resultCode != 200) {
- ConnectionFailed(LOGINERR_WRONGPASSWORD);
+ if (hContact == NULL)
+ ConnectionFailed(LOGINERR_WRONGPASSWORD);
return;
}
- JSONNode *root = json_parse(pReply->pData);
- if (root == NULL) {
- ConnectionFailed(LOGINERR_NOSERVER);
+ JSONNode root = JSONNode::parse(pReply->pData);
+ if (!root) {
+ if (hContact == NULL)
+ ConnectionFailed(LOGINERR_NOSERVER);
return;
}
- m_ownId = _wtoi64(root->at("id").as_mstring());
- setId("id", m_ownId);
+ m_ownId = _wtoi64(root["id"].as_mstring());
+ setId(hContact, DB_KEY_ID, m_ownId);
- setWString("Username", root->at("username").as_mstring());
- setByte("MfaEnabled", root->at("mfa_enabled").as_bool());
- setWString("AvatarHash", root->at("avatar").as_mstring());
- setDword("Discriminator", root->at("discriminator").as_int());
- setWString("Email", root->at("email").as_mstring());
+ setByte(hContact, DB_KEY_MFA, root["mfa_enabled"].as_bool());
+ setDword(hContact, DB_KEY_DISCR, root["discriminator"].as_int());
+ setWString(hContact, DB_KEY_NICK, root["username"].as_mstring());
+ setWString(hContact, DB_KEY_AVHASH, root["avatar"].as_mstring());
+ setWString(hContact, DB_KEY_EMAIL, root["email"].as_mstring());
- OnLoggedIn();
+ if (hContact == NULL)
+ OnLoggedIn();
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -61,12 +67,56 @@ void CDiscordProto::SetServerStatus(int iStatus)
ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)iOldStatus, m_iStatus);
}
+void CDiscordProto::OnReceiveAuth(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
+{
+ MCONTACT hContact = (MCONTACT)pReq->pUserInfo;
+ if (pReply->resultCode == 204)
+ RetrieveUserInfo(hContact);
+}
+
/////////////////////////////////////////////////////////////////////////////////////////
void CDiscordProto::OnReceiveChannels(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*)
{
if (pReply->resultCode != 200)
return;
+
+ JSONNode root = JSONNode::parse(pReply->pData);
+ if (!root)
+ return;
+
+ for (auto it = root.begin(); it != root.end(); ++it) {
+ JSONNode &p = *it;
+
+ JSONNode &user = p["recipient"];
+ if (!user)
+ continue;
+
+ CDiscordUser *pUser = PrepareUser(user);
+ pUser->lastMessageId = _wtoi64(p["last_message_id"].as_mstring());
+ pUser->channelId = _wtoi64(p["id"].as_mstring());
+ pUser->bIsPrivate = p["is_private"].as_bool();
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDiscordProto::OnReceiveFriends(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*)
+{
+ if (pReply->resultCode != 200)
+ return;
+
+ JSONNode root = JSONNode::parse(pReply->pData);
+ if (!root)
+ return;
+
+ for (auto it = root.begin(); it != root.end(); ++it) {
+ JSONNode &p = *it;
+
+ JSONNode &user = p["user"];
+ if (user)
+ PrepareUser(user);
+ }
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -86,21 +136,21 @@ void CDiscordProto::OnReceiveToken(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*)
return;
}
- JSONNode *root = json_parse(pReply->pData);
- if (root == NULL) {
+ JSONNode root = JSONNode::parse(pReply->pData);
+ if (!root) {
LBL_Error:
ConnectionFailed(LOGINERR_NOSERVER);
return;
}
- CMStringA szToken = root->at("token").as_mstring();
+ CMStringA szToken = root["token"].as_mstring();
if (szToken.IsEmpty())
goto LBL_Error;
m_szAccessToken = szToken.Detach();
setString("AccessToken", m_szAccessToken);
- RetrieveMyInfo();
+ RetrieveUserInfo(NULL);
}
/////////////////////////////////////////////////////////////////////////////////////////
diff --git a/protocols/Discord/src/stdafx.h b/protocols/Discord/src/stdafx.h
index 414b542c0f..e0177716ab 100644
--- a/protocols/Discord/src/stdafx.h
+++ b/protocols/Discord/src/stdafx.h
@@ -44,8 +44,15 @@ extern HINSTANCE g_hInstance;
#include "version.h"
#include "proto.h"
-#define DB_KEY_EMAIL "Email"
-#define DB_KEY_PASSWORD "Password"
+#define DB_KEY_ID "id"
+#define DB_KEY_EMAIL "Email"
+#define DB_KEY_PASSWORD "Password"
+#define DB_KEY_DISCR "Discriminator"
+#define DB_KEY_MFA "MfaEnabled"
+#define DB_KEY_NICK "Nick"
+#define DB_KEY_AVHASH "AvatarHash"
+#define DB_KEY_CHANNELID "ChannelID"
+#define DB_KEY_LASTMSGID "LastMessageID"
#define DB_KEY_GROUP "GroupName"
#define DB_KEYVAL_GROUP L"Discord"
diff --git a/protocols/Discord/src/utils.cpp b/protocols/Discord/src/utils.cpp
index 4d69a6f40f..1074291b36 100644
--- a/protocols/Discord/src/utils.cpp
+++ b/protocols/Discord/src/utils.cpp
@@ -48,22 +48,26 @@ JSONNode& operator<<(JSONNode &json, const WCHAR_PARAM &param)
SnowFlake CDiscordProto::getId(const char *szSetting)
{
- SnowFlake result;
DBVARIANT dbv;
dbv.type = DBVT_BLOB;
- dbv.pbVal = (BYTE*)&result;
- dbv.cpbVal = sizeof(result);
- return (db_get(NULL, m_szModuleName, szSetting, &dbv)) ? 0 : result;
+ if (db_get(NULL, m_szModuleName, szSetting, &dbv))
+ return 0;
+
+ SnowFlake result = (dbv.cpbVal == sizeof(SnowFlake)) ? *(SnowFlake*)dbv.pbVal : 0;
+ db_free(&dbv);
+ return result;
}
SnowFlake CDiscordProto::getId(MCONTACT hContact, const char *szSetting)
{
- SnowFlake result;
DBVARIANT dbv;
dbv.type = DBVT_BLOB;
- dbv.pbVal = (BYTE*)&result;
- dbv.cpbVal = sizeof(result);
- return (db_get(hContact, m_szModuleName, szSetting, &dbv)) ? 0 : result;
+ if (db_get(hContact, m_szModuleName, szSetting, &dbv))
+ return 0;
+
+ SnowFlake result = (dbv.cpbVal == sizeof(SnowFlake)) ? *(SnowFlake*)dbv.pbVal : 0;
+ db_free(&dbv);
+ return result;
}
void CDiscordProto::setId(const char *szSetting, SnowFlake iValue)
@@ -75,3 +79,53 @@ void CDiscordProto::setId(MCONTACT hContact, const char *szSetting, SnowFlake iV
{
db_set_blob(hContact, m_szModuleName, szSetting, &iValue, sizeof(iValue));
}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CDiscordUser* CDiscordProto::FindUser(SnowFlake id)
+{
+ return arUsers.find((CDiscordUser*)&id);
+}
+
+CDiscordUser* CDiscordProto::FindUser(const wchar_t *pwszUsername, int iDiscriminator)
+{
+ for (int i = 0; i < arUsers.getCount(); i++) {
+ CDiscordUser &p = arUsers[i];
+ if (p.wszUsername == pwszUsername && p.iDiscriminator == iDiscriminator)
+ return &p;
+ }
+
+ return NULL;
+}
+
+CDiscordUser* CDiscordProto::PrepareUser(const JSONNode &user)
+{
+ SnowFlake id = _wtoi64(user["id"].as_mstring());
+ int iDiscriminator = _wtoi(user["discriminator"].as_mstring());
+ CMStringW avatar = user["avatar"].as_mstring();
+ CMStringW username = user["username"].as_mstring();
+
+ CDiscordUser *pUser = FindUser(id);
+ if (pUser == NULL)
+ pUser = FindUser(username, iDiscriminator);
+ if (pUser == NULL) {
+ pUser = new CDiscordUser(id);
+ pUser->wszUsername = username;
+ pUser->iDiscriminator = iDiscriminator;
+ arUsers.insert(pUser);
+ }
+
+ if (pUser->hContact == 0) {
+ MCONTACT hContact = db_add_contact();
+ Proto_AddToContact(hContact, m_szModuleName);
+
+ setId(hContact, DB_KEY_ID, id);
+ setWString(hContact, DB_KEY_NICK, username);
+ setDword(hContact, DB_KEY_DISCR, iDiscriminator);
+
+ pUser->hContact = hContact;
+ }
+
+ setWString(pUser->hContact, DB_KEY_AVHASH, avatar);
+ return pUser;
+}
diff --git a/protocols/Discord/src/version.h b/protocols/Discord/src/version.h
index 056cd06fa5..c4be71667a 100644
--- a/protocols/Discord/src/version.h
+++ b/protocols/Discord/src/version.h
@@ -1,7 +1,7 @@
#define __MAJOR_VERSION 0
#define __MINOR_VERSION 0
#define __RELEASE_NUM 0
-#define __BUILD_NUM 2
+#define __BUILD_NUM 3
#include <stdver.h>