diff options
Diffstat (limited to 'protocols/Teams/src/teams_contacts.cpp')
-rw-r--r-- | protocols/Teams/src/teams_contacts.cpp | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/protocols/Teams/src/teams_contacts.cpp b/protocols/Teams/src/teams_contacts.cpp new file mode 100644 index 0000000000..19c2817d6f --- /dev/null +++ b/protocols/Teams/src/teams_contacts.cpp @@ -0,0 +1,321 @@ +/* +Copyright (c) 2025 Miranda NG team (https://miranda-ng.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" + +void CTeamsProto::SetContactStatus(MCONTACT hContact, uint16_t status) +{ + uint16_t oldStatus = getWord(hContact, "Status", ID_STATUS_OFFLINE); + if (oldStatus != status) { + setWord(hContact, "Status", status); + if (status == ID_STATUS_OFFLINE) + delSetting(hContact, "MirVer"); + } +} + +void CTeamsProto::SetChatStatus(MCONTACT hContact, int iStatus) +{ + ptrW tszChatID(getWStringA(hContact, DBKEY_ID)); + if (tszChatID != NULL) + Chat_Control(Chat_Find(tszChatID, m_szModuleName), (iStatus == ID_STATUS_OFFLINE) ? SESSION_OFFLINE : SESSION_ONLINE); +} + +MCONTACT CTeamsProto::GetContactFromAuthEvent(MEVENT hEvent) +{ + uint32_t body[3]; + DBEVENTINFO dbei = {}; + dbei.cbBlob = sizeof(uint32_t) * 2; + dbei.pBlob = (char *)&body; + + if (db_event_get(hEvent, &dbei)) + return INVALID_CONTACT_ID; + + if (dbei.eventType != EVENTTYPE_AUTHREQUEST) + return INVALID_CONTACT_ID; + + if (mir_strcmp(dbei.szModule, m_szModuleName) != 0) + return INVALID_CONTACT_ID; + return DbGetAuthEventContact(&dbei); +} + +MCONTACT CTeamsProto::FindContact(const char *skypeId) +{ + for (auto &hContact : AccContacts()) + if (!mir_strcmpi(skypeId, ptrA(getUStringA(hContact, DBKEY_ID)))) + return hContact; + + return 0; +} + +MCONTACT CTeamsProto::FindContact(const wchar_t *skypeId) +{ + for (auto &hContact : AccContacts()) + if (!mir_wstrcmpi(skypeId, getMStringW(hContact, DBKEY_ID))) + return hContact; + + return 0; +} + +MCONTACT CTeamsProto::AddContact(const char *skypeId, const char *nick, bool isTemporary) +{ + MCONTACT hContact = FindContact(skypeId); + if (hContact) + return hContact; + + hContact = db_add_contact(); + Proto_AddToContact(hContact, m_szModuleName); + + setString(hContact, DBKEY_ID, skypeId); + setUString(hContact, "Nick", (nick) ? nick : GetSkypeNick(skypeId)); + + if (m_wstrCListGroup) { + Clist_GroupCreate(0, m_wstrCListGroup); + Clist_SetGroup(hContact, m_wstrCListGroup); + } + + setByte(hContact, "Auth", 1); + setByte(hContact, "Grant", 1); + + if (isTemporary) + Contact::RemoveFromList(hContact); + return hContact; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CTeamsProto::LoadContactsAuth(MHttpResponse *response, AsyncHttpRequest*) +{ + TeamsReply reply(response); + if (reply.error()) + return; + + auto &root = reply.data(); + for (auto &item : root["invite_list"]) { + std::string skypeId = item["mri"].as_string(); + std::string reason = item["greeting"].as_string(); + + time_t eventTime = 0; + for (auto &it : item["invites"]) + eventTime = Utils_IsoToUnixTime(it["time"].as_string()); + + std::string displayName = item["displayname"].as_string(); + const char *szNick = (displayName.empty()) ? nullptr : displayName.c_str(); + + MCONTACT hContact = AddContact(skypeId.c_str(), szNick); + time_t lastEventTime = getDword(hContact, "LastAuthRequestTime"); + if (lastEventTime && lastEventTime >= eventTime) + continue; + + setUString(hContact, "Nick", displayName.c_str()); + + setDword(hContact, "LastAuthRequestTime", eventTime); + delSetting(hContact, "Auth"); + + DB::AUTH_BLOB blob(hContact, displayName.c_str(), nullptr, nullptr, skypeId.c_str(), reason.c_str()); + + DB::EventInfo dbei; + dbei.iTimestamp = time(0); + dbei.cbBlob = blob.size(); + dbei.pBlob = blob; + ProtoChainRecv(hContact, PSR_AUTH, 0, (LPARAM)&dbei); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CTeamsProto::RefreshContactsInfo() +{ + PushRequest(new AsyncHttpRequest(REQUEST_GET, HOST_CONTACTS, "/users/SELF/contacts", &CTeamsProto::OnGotContactsInfo)); +} + +void CTeamsProto::OnGotContactsInfo(MHttpResponse *response, AsyncHttpRequest*) +{ + TeamsReply reply(response); + if (reply.error()) + return; + + auto &root = reply.data(); + for (auto &item : root["contacts"]) { + CMStringA szSkypeId = item["person_id"].as_mstring(); + if (!IsPossibleUserType(szSkypeId)) + continue; + + MCONTACT hContact = AddContact(szSkypeId, nullptr); + if (szSkypeId == "28:e7a9407c-2467-4a04-9546-70081f4ea80d") + m_hMyContact = hContact; + + std::string displayName = item["display_name"].as_string(); + if (!displayName.empty()) { + if (m_hMyContact == hContact) { + displayName = getMStringU("Nick"); + displayName += " "; + displayName += TranslateU("(You)"); + + setWord(hContact, "Status", ID_STATUS_ONLINE); + } + setUString(hContact, "Nick", displayName.c_str()); + } + + if (item["authorized"].as_bool()) { + delSetting(hContact, "Auth"); + delSetting(hContact, "Grant"); + } + else setByte(hContact, "Grant", 1); + + if (item["blocked"].as_bool()) + setByte(hContact, "IsBlocked", 1); + else + delSetting(hContact, "IsBlocked"); + + ptrW wszGroup(Clist_GetGroup(hContact)); + if (wszGroup == nullptr && m_wstrCListGroup) { + Clist_GroupCreate(0, m_wstrCListGroup); + Clist_SetGroup(hContact, m_wstrCListGroup); + } + + auto &profile = item["profile"]; + SetString(hContact, "Homepage", profile["website"]); + + auto wstr = profile["birthday"].as_mstring(); + if (!wstr.IsEmpty() ) { + int nYear, nMonth, nDay; + if (swscanf(wstr, L"%d-%d-%d", &nYear, &nMonth, &nDay) == 3) + Contact::SetBirthday(hContact, nDay, nMonth, nYear); + } + + wstr = profile["gender"].as_mstring(); + if (wstr == "male") + setByte(hContact, "Gender", 'M'); + else if (wstr == "female") + setByte(hContact, "Gender", 'F'); + + auto &name = profile["name"]; + SetString(hContact, "FirstName", name["first"]); + SetString(hContact, "LastName", name["surname"]); + + if (auto &pMood = profile["mood"]) + db_set_ws(hContact, "CList", "StatusMsg", RemoveHtml(pMood.as_mstring())); + + SetAvatarUrl(hContact, profile["avatar_url"].as_mstring()); + ReloadAvatarInfo(hContact); + + for (auto &phone : profile["phones"]) { + CMStringW number = phone["number"].as_mstring(); + + auto wszType = phone["type"].as_mstring(); + if (wszType == L"mobile") + setWString(hContact, "Cellular", number); + else if (wszType == L"phone") + setWString(hContact, "Phone", number); + } + } + + PushRequest(new AsyncHttpRequest(REQUEST_GET, HOST_CONTACTS, "/users/SELF/invites", &CTeamsProto::LoadContactsAuth)); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CTeamsProto::GetShortInfo(const OBJLIST<char> &ids) +{ + auto *pReq = new AsyncHttpRequest(REQUEST_POST, HOST_TEAMS_API, "/users/fetchShortProfile?isMailAddress=false&canBeSmtpAddress=false&enableGuest=true&includeIBBarredUsers=true&skypeTeamsInfo=true&includeBots=true"); + + for (auto &it : ids) { + if (pReq->m_szParam.IsEmpty()) + pReq->m_szParam = "["; + else + pReq->m_szParam += ","; + pReq->m_szParam.AppendFormat("\"%s\"", it); + } + pReq->m_szParam += "]"; + + PushRequest(pReq); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +INT_PTR CTeamsProto::OnRequestAuth(WPARAM hContact, LPARAM) +{ + return AuthRequest(hContact, 0); +} + +INT_PTR CTeamsProto::OnGrantAuth(WPARAM hContact, LPARAM) +{ + if (hContact == INVALID_CONTACT_ID) + return 1; + + PushRequest(new AsyncHttpRequest(REQUEST_POST, HOST_CONTACTS, "/users/SELF/invites/" + mir_urlEncode(getId(hContact)) + "/accept")); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CTeamsProto::OnContactDeleted(MCONTACT hContact, uint32_t flags) +{ + if (IsOnline() && hContact && (flags & CDF_DEL_CONTACT)) { + CMStringA szId(getId(hContact)); + AsyncHttpRequest *pReq = (isChatRoom(hContact)) + ? new AsyncHttpRequest(REQUEST_DELETE, HOST_GROUPS, "/threads/" + mir_urlEncode(szId)) + : new AsyncHttpRequest(REQUEST_DELETE, HOST_CONTACTS, "/users/SELF/contacts/" + mir_urlEncode(szId)); + PushRequest(pReq); + } + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CTeamsProto::OnBlockContact(MHttpResponse *response, AsyncHttpRequest *pRequest) +{ + MCONTACT hContact = (DWORD_PTR)pRequest->pUserInfo; + if (response != nullptr) + Contact::Hide(hContact); +} + +INT_PTR CTeamsProto::BlockContact(WPARAM hContact, LPARAM) +{ + if (!IsOnline()) return 1; + + if (IDYES == MessageBox(NULL, TranslateT("Are you sure?"), TranslateT("Warning"), MB_YESNO | MB_ICONQUESTION)) { + auto *pReq = new AsyncHttpRequest(REQUEST_PUT, HOST_CONTACTS, "/users/SELF/contacts/blocklist/" + mir_urlEncode(getId(hContact)), &CTeamsProto::OnBlockContact); + pReq->m_szParam = "{\"report_abuse\":\"false\",\"ui_version\":\"skype.com\"}"; + pReq->pUserInfo = (void *)hContact; + PushRequest(pReq); + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CTeamsProto::OnUnblockContact(MHttpResponse *response, AsyncHttpRequest *pRequest) +{ + if (response == nullptr) + return; + + MCONTACT hContact = (DWORD_PTR)pRequest->pUserInfo; + Contact::Hide(hContact, false); + delSetting(hContact, "IsBlocked"); +} + +INT_PTR CTeamsProto::UnblockContact(WPARAM hContact, LPARAM) +{ + if (!IsOnline()) return 1; + + auto *pReq = new AsyncHttpRequest(REQUEST_DELETE, HOST_CONTACTS, "/users/SELF/contacts/blocklist/" + mir_urlEncode(getId(hContact)), &CTeamsProto::OnUnblockContact); + pReq->pUserInfo = (void *)hContact; + pReq << CHAR_PARAM("reporterIp", "123.123.123.123") << CHAR_PARAM("uiVersion", g_szMirVer); // TODO: user ip address + PushRequest(pReq); + return 0; +} |