summaryrefslogtreecommitdiff
path: root/protocols/Teams/src/teams_contacts.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Teams/src/teams_contacts.cpp')
-rw-r--r--protocols/Teams/src/teams_contacts.cpp321
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;
+}