diff options
author | George Hazan <ghazan@miranda.im> | 2016-12-30 00:49:15 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2016-12-30 00:49:15 +0300 |
commit | 37ae1c46680e624dddddfee816f19cf920f95348 (patch) | |
tree | 0a32c5252055340cc8b11c6833173706902eee1d /protocols | |
parent | 50e87bcbf1b3a716f155e504a09df1c0ff1a66f5 (diff) |
Discord:
- user search works;
- friend list support;
- channel list support;
- various fixes
Diffstat (limited to 'protocols')
-rw-r--r-- | protocols/Discord/res/discord.rc | 9 | ||||
-rw-r--r-- | protocols/Discord/src/connection.cpp | 3 | ||||
-rw-r--r-- | protocols/Discord/src/options.cpp | 4 | ||||
-rw-r--r-- | protocols/Discord/src/proto.cpp | 145 | ||||
-rw-r--r-- | protocols/Discord/src/proto.h | 55 | ||||
-rw-r--r-- | protocols/Discord/src/resource.h | 4 | ||||
-rw-r--r-- | protocols/Discord/src/server.cpp | 88 | ||||
-rw-r--r-- | protocols/Discord/src/stdafx.h | 11 | ||||
-rw-r--r-- | protocols/Discord/src/utils.cpp | 70 | ||||
-rw-r--r-- | protocols/Discord/src/version.h | 2 |
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 ¶m); ///////////////////////////////////////////////////////////////////////////////////////// +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 ¶m) 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> |