From 9c5bcfa55b13b5df3703d4ba8ab9d70527a2587a Mon Sep 17 00:00:00 2001 From: George Hazan Date: Mon, 13 Feb 2023 20:53:50 +0300 Subject: fixes #3329 (Telegram: implement search and add contacts) --- protocols/Telegram/src/proto.cpp | 84 +++++++++++++++++++++++++++++++++++---- protocols/Telegram/src/proto.h | 43 +++++++++++++------- protocols/Telegram/src/server.cpp | 69 +++++++++++++++++++++----------- protocols/Telegram/src/stdafx.h | 1 + protocols/Telegram/src/utils.cpp | 78 +++++++++++++++++++++++++++++++----- protocols/Telegram/src/utils.h | 3 +- 6 files changed, 223 insertions(+), 55 deletions(-) diff --git a/protocols/Telegram/src/proto.cpp b/protocols/Telegram/src/proto.cpp index 3ac7dcb924..c823679106 100644 --- a/protocols/Telegram/src/proto.cpp +++ b/protocols/Telegram/src/proto.cpp @@ -16,6 +16,10 @@ static int CompareRequests(const TG_REQUEST_BASE *p1, const TG_REQUEST_BASE *p2) return (p1->requestId < p2->requestId) ? -1 : 1; } +static int CompareChats(const TG_USER *p1, const TG_USER *p2) +{ return CompareId(p1->chatId, p2->chatId); +} + static int CompareUsers(const TG_USER *p1, const TG_USER *p2) { return CompareId(p1->id, p2->id); } @@ -32,7 +36,8 @@ CTelegramProto::CTelegramProto(const char* protoName, const wchar_t* userName) : PROTO(protoName, userName), m_impl(*this), m_arFiles(1), - m_arUsers(10, CompareUsers), + m_arChats(100, CompareChats), + m_arUsers(100, CompareUsers), m_arRequests(10, CompareRequests), m_arBasicGroups(10, CompareBasicGroups), m_arSuperGroups(10, CompareSuperGroups), @@ -60,8 +65,6 @@ CTelegramProto::CTelegramProto(const char* protoName, const wchar_t* userName) : CreateDirectoryTreeW(GetAvatarPath()); // default contacts group - if (m_wszDefaultGroup == NULL) - m_wszDefaultGroup = mir_wstrdup(L"WhatsApp"); m_iBaseGroup = Clist_GroupCreate(0, m_wszDefaultGroup); // create standard network connection @@ -99,8 +102,11 @@ void CTelegramProto::OnContactDeleted(MCONTACT hContact) void CTelegramProto::OnModulesLoaded() { CMStringA szId(getMStringA(DBKEY_ID)); - if (!szId.IsEmpty()) - m_arUsers.insert(new TG_USER(_atoi64(szId.c_str()), 0)); + if (!szId.IsEmpty()) { + auto *pUser = new TG_USER(_atoi64(szId.c_str()), 0); + m_arUsers.insert(pUser); + m_arChats.insert(pUser); + } for (auto &cc : AccContacts()) { ptrA szPath(getStringA(cc, "AvatarPath")); @@ -115,6 +121,8 @@ void CTelegramProto::OnModulesLoaded() auto *pUser = new TG_USER(_atoi64(szId.c_str()), cc, isGroupChat); pUser->szAvatarHash = getMStringA(cc, DBKEY_AVATAR_HASH); m_arUsers.insert(pUser); + if (!isGroupChat) + m_arChats.insert(pUser); } } @@ -164,11 +172,32 @@ void CTelegramProto::OnMarkRead(MCONTACT hContact, MEVENT hDbEvent) } } +///////////////////////////////////////////////////////////////////////////////////////// + +MCONTACT CTelegramProto::AddToList(int flags, PROTOSEARCHRESULT *psr) +{ + if (psr->cbSize != sizeof(PROTOSEARCHRESULT) && psr->id.w == nullptr) + return 0; + + auto id = _wtoi64(psr->id.w); + if (auto *pUser = FindUser(id)) + if (pUser->hContact != INVALID_CONTACT_ID) + return pUser->hContact; + + auto *pUser = AddUser(id, false); + if (flags & PALF_TEMPORARY) + Contact::RemoveFromList(pUser->hContact); + + auto cc = TD::make_object(); cc->user_id_ = id; + SendQuery(new TD::addContact(std::move(cc), false)); + return pUser->hContact; +} + INT_PTR CTelegramProto::GetCaps(int type, MCONTACT) { switch (type) { case PFLAGNUM_1: - return PF1_IM | PF1_FILE | PF1_CHAT | PF1_EXTSEARCH | PF1_ADDSEARCHRES | PF1_MODEMSGRECV | PF1_SERVERCLIST; + return PF1_IM | PF1_FILE | PF1_CHAT | PF1_SEARCHBYNAME | PF1_ADDSEARCHRES | PF1_MODEMSGRECV | PF1_SERVERCLIST; case PFLAGNUM_2: return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY; case PFLAGNUM_4: @@ -176,12 +205,53 @@ INT_PTR CTelegramProto::GetCaps(int type, MCONTACT) case PFLAGNUM_5: return PF2_SHORTAWAY | PF2_LONGAWAY; case PFLAG_UNIQUEIDTEXT: - return (INT_PTR)L"Phone"; + return (INT_PTR)L"ID"; default: return 0; } } +///////////////////////////////////////////////////////////////////////////////////////// + +void CTelegramProto::OnSearchResults(td::ClientManager::Response &response) +{ + m_searchIds.clear(); + + if (!response.object) + return; + + if (response.object->get_id() != TD::chats::ID) { + debugLogA("Gotten class ID %d instead of %d, exiting", response.object->get_id(), TD::chats::ID); + return; + } + + auto *pChats = ((TD::chats*)response.object.get()); + if (pChats->total_count_) { + for (auto &it : pChats->chat_ids_) { + if (auto *pUser = FindChat(it)) + ReportSearchUser(pUser); + else + m_searchIds.push_back(it); + } + } + + if (m_searchIds.empty()) + ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, this); +} + +HANDLE CTelegramProto::SearchByName(const wchar_t *nick, const wchar_t *firstName, const wchar_t *lastName) +{ + CMStringA szQuery(FORMAT, "%s %s %s", T2Utf(nick).get(), T2Utf(firstName).get(), T2Utf(lastName).get()); + if (szQuery.GetLength() == 2) + return nullptr; + + szQuery.Trim(); + SendQuery(new TD::searchPublicChats(szQuery.c_str()), &CTelegramProto::OnSearchResults); + return this; +} + +///////////////////////////////////////////////////////////////////////////////////////// + int CTelegramProto::SendMsg(MCONTACT hContact, int, const char *pszMessage) { ptrA szId(getStringA(hContact, DBKEY_ID)); diff --git a/protocols/Telegram/src/proto.h b/protocols/Telegram/src/proto.h index 2c0fe18116..b0dc9645a0 100644 --- a/protocols/Telegram/src/proto.h +++ b/protocols/Telegram/src/proto.h @@ -80,13 +80,15 @@ struct TG_USER id(_1), hContact(_2), isGroupChat(_3) - {} + { + chatId = (isGroupChat) ? -1 :id; + } - int64_t id; + int64_t id, chatId; MCONTACT hContact; bool isGroupChat; CMStringA szAvatarHash; - CMStringW wszNick; + CMStringW wszNick, wszFirstName, wszLastName; time_t m_timer1 = 0, m_timer2 = 0; SESSION_INFO *m_si = nullptr; }; @@ -168,6 +170,7 @@ class CTelegramProto : public PROTO } void OnEndSession(td::ClientManager::Response &response); + void OnSearchResults(td::ClientManager::Response &response); void OnSendMessage(td::ClientManager::Response &response, void *pUserInfo); void OnUpdateAuth(td::ClientManager::Response &response); @@ -212,13 +215,22 @@ class CTelegramProto : public PROTO void InitGroupChat(TG_USER *pUser, const TD::chat *pChat, bool bUpdateMembers); void StartGroupChat(td::ClientManager::Response &response, void *pUserData); + // Search + TD::array m_searchIds; + + bool CheckSearchUser(TG_USER *pUser); + void ReportSearchUser(TG_USER *pUser); + // Users int64_t m_iOwnId; MGROUP m_iBaseGroup; + LIST m_arChats; OBJLIST m_arUsers; + TG_USER* FindChat(int64_t id); TG_USER* FindUser(int64_t id); TG_USER* AddUser(int64_t id, bool bIsChat); + TG_USER* AddFakeUser(int64_t id, bool bIsChat); // Popups HANDLE m_hPopupClass; @@ -236,17 +248,20 @@ public: ////////////////////////////////////////////////////////////////////////////////////// // Virtual functions - INT_PTR GetCaps(int type, MCONTACT hContact = NULL) override; - - int SendMsg(MCONTACT hContact, int flags, const char *pszMessage) override; - int SetStatus(int iNewStatus) override; - - void OnContactDeleted(MCONTACT hContact) override; - MWindow OnCreateAccMgrUI(MWindow) override; - void OnMarkRead(MCONTACT, MEVENT) override; - void OnModulesLoaded() override; - void OnShutdown() override; - void OnErase() override; + MCONTACT AddToList(int flags, PROTOSEARCHRESULT *psr); + + INT_PTR GetCaps(int type, MCONTACT hContact = NULL) override; + + HANDLE SearchByName(const wchar_t *nick, const wchar_t *firstName, const wchar_t *lastName) override; + int SendMsg(MCONTACT hContact, int flags, const char *pszMessage) override; + int SetStatus(int iNewStatus) override; + + void OnContactDeleted(MCONTACT hContact) override; + MWindow OnCreateAccMgrUI(MWindow hwndParent) override; + void OnMarkRead(MCONTACT, MEVENT) override; + void OnModulesLoaded() override; + void OnShutdown() override; + void OnErase() override; // Events //////////////////////////////////////////////////////////////////////////// diff --git a/protocols/Telegram/src/server.cpp b/protocols/Telegram/src/server.cpp index 34c8ff5936..291cf9e056 100644 --- a/protocols/Telegram/src/server.cpp +++ b/protocols/Telegram/src/server.cpp @@ -183,7 +183,7 @@ void CTelegramProto::OnSendMessage(td::ClientManager::Response &response, void * } auto *pMessage = ((TD::message *)response.object.get()); - auto *pUser = FindUser(pMessage->chat_id_); + auto *pUser = FindChat(pMessage->chat_id_); if (pUser) { char szMsgId[100]; _i64toa(pMessage->id_, szMsgId, 10); @@ -256,9 +256,11 @@ void CTelegramProto::ProcessBasicGroup(TD::updateBasicGroup *pObj) else pGroup->group = std::move(pObj->basic_group_); - auto *pUser = AddUser(tmp.id, true); - if (iStatusId == TD::chatMemberStatusLeft::ID) - Contact::Hide(pUser->hContact); + if (iStatusId == TD::chatMemberStatusLeft::ID) { + auto *pUser = AddFakeUser(tmp.id, true); + pUser->wszFirstName.Format(TranslateT("%d member(s)"), pGroup->group->member_count_); + } + else AddUser(tmp.id, true); } void CTelegramProto::ProcessChat(TD::updateNewChat *pObj) @@ -288,10 +290,22 @@ void CTelegramProto::ProcessChat(TD::updateNewChat *pObj) } if (auto *pUser = FindUser(chatId)) { - if (!pChat->title_.empty() && pUser->hContact != INVALID_CONTACT_ID) - setUString(pUser->hContact, "Nick", pChat->title_.c_str()); + pUser->chatId = pChat->id_; + + if (!m_arChats.find(pUser)) + m_arChats.insert(pUser); + + if (!pChat->title_.empty()) { + if (pUser->hContact != INVALID_CONTACT_ID) + setUString(pUser->hContact, "Nick", pChat->title_.c_str()); + else + pUser->wszNick = Utf2T(pChat->title_.c_str()); + } - if (pUser->isGroupChat) + if (CheckSearchUser(pUser)) + return; + + if (pUser->isGroupChat && pUser->hContact != INVALID_CONTACT_ID) InitGroupChat(pUser, pChat, bIsBasicGroup); } else debugLogA("Unknown chat id %lld, ignoring", chatId); @@ -304,7 +318,7 @@ void CTelegramProto::ProcessChatPosition(TD::updateChatPosition *pObj) return; } - auto *pUser = FindUser(pObj->chat_id_); + auto *pUser = FindChat(pObj->chat_id_); if (pUser == nullptr) { debugLogA("Unknown chat, skipping"); return; @@ -359,7 +373,7 @@ void CTelegramProto::ProcessGroups(TD::updateChatFilters *pObj) void CTelegramProto::ProcessMarkRead(TD::updateChatReadInbox *pObj) { - auto *pUser = FindUser(pObj->chat_id_); + auto *pUser = FindChat(pObj->chat_id_); if (pUser == nullptr) { debugLogA("message from unknown chat/user, ignored"); return; @@ -393,7 +407,7 @@ void CTelegramProto::ProcessMessage(TD::updateNewMessage *pObj) { auto &pMessage = pObj->message_; - auto *pUser = FindUser(pMessage->chat_id_); + auto *pUser = FindChat(pMessage->chat_id_); if (pUser == nullptr) { debugLogA("message from unknown chat/user, ignored"); return; @@ -446,14 +460,18 @@ void CTelegramProto::ProcessSuperGroup(TD::updateSupergroup *pObj) TG_SUPER_GROUP tmp(pObj->supergroup_->id_, 0); auto *pGroup = m_arSuperGroups.find(&tmp); - if (pGroup == nullptr) - m_arSuperGroups.insert(new TG_SUPER_GROUP(tmp.id, std::move(pObj->supergroup_))); - else - pGroup->group = std::move(pObj->supergroup_); + if (pGroup == nullptr) { + pGroup = new TG_SUPER_GROUP(tmp.id, std::move(pObj->supergroup_)); + m_arSuperGroups.insert(pGroup); + } + else pGroup->group = std::move(pObj->supergroup_); - auto *pUser = AddUser(tmp.id, true); - if (iStatusId == TD::chatMemberStatusLeft::ID) - Contact::Hide(pUser->hContact); + if (iStatusId == TD::chatMemberStatusLeft::ID) { + auto *pUser = AddFakeUser(tmp.id, true); + pUser->wszNick = getName(pGroup->group->usernames_.get()); + pUser->wszFirstName.Format(TranslateT("%d member(s)"), pGroup->group->member_count_); + } + else AddUser(tmp.id, true); } void CTelegramProto::ProcessUser(TD::updateUser *pObj) @@ -468,15 +486,18 @@ void CTelegramProto::ProcessUser(TD::updateUser *pObj) } if (!pUser->is_contact_) { - auto *pu = FindUser(pUser->id_); - if (pu == nullptr) { - pu = new TG_USER(pUser->id_, INVALID_CONTACT_ID, false); - m_arUsers.insert(pu); + auto *pu = AddFakeUser(pUser->id_, false); + pu->wszFirstName = Utf2T(pUser->first_name_.c_str()); + pu->wszLastName = Utf2T(pUser->last_name_.c_str()); + if (pUser->usernames_) + pu->wszNick = Utf2T(pUser->usernames_->editable_username_.c_str()); + else { + pu->wszNick = Utf2T(pUser->first_name_.c_str()); + if (!pUser->last_name_.empty()) + pu->wszNick.AppendFormat(L" %s", Utf2T(pUser->last_name_.c_str()).get()); } - pu->wszNick = Utf2T(pUser->first_name_.c_str()); - if (!pUser->last_name_.empty()) - pu->wszNick.AppendFormat(L" %s", Utf2T(pUser->last_name_.c_str()).get()); + CheckSearchUser(pu); debugLogA("User doesn't belong to your contacts, skipping"); return; diff --git a/protocols/Telegram/src/stdafx.h b/protocols/Telegram/src/stdafx.h index bce763709d..b16b91840c 100644 --- a/protocols/Telegram/src/stdafx.h +++ b/protocols/Telegram/src/stdafx.h @@ -1,6 +1,7 @@ #ifndef _COMMON_H_ #define _COMMON_H_ +#include #include #include diff --git a/protocols/Telegram/src/utils.cpp b/protocols/Telegram/src/utils.cpp index b725ba5f90..7dfe0c3096 100644 --- a/protocols/Telegram/src/utils.cpp +++ b/protocols/Telegram/src/utils.cpp @@ -17,7 +17,12 @@ along with this program. If not, see . #include "stdafx.h" -char* getSender(const TD::MessageSender *pSender, char *pDest, size_t cbSize) +const char *getName(const TD::usernames *pName) +{ + return (pName == nullptr) ? TranslateU("none") : pName->editable_username_.c_str(); +} + +const char* getSender(const TD::MessageSender *pSender, char *pDest, size_t cbSize) { switch (pSender->get_id()) { case TD::messageSenderChat::ID: @@ -34,6 +39,49 @@ char* getSender(const TD::MessageSender *pSender, char *pDest, size_t cbSize) ///////////////////////////////////////////////////////////////////////////////////////// +bool CTelegramProto::CheckSearchUser(TG_USER *pUser) +{ + auto pSearchId = std::find(m_searchIds.begin(), m_searchIds.end(), pUser->chatId); + if (pSearchId == m_searchIds.end()) + return false; + + ReportSearchUser(pUser); + + m_searchIds.erase(pSearchId); + if (m_searchIds.empty()) + ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, this); + return true; +} + +void CTelegramProto::ReportSearchUser(TG_USER *pUser) +{ + CMStringW wszId(FORMAT, L"%lld", pUser->id); + + PROTOSEARCHRESULT psr = {}; + psr.cbSize = sizeof(psr); + psr.flags = PSR_UNICODE; + psr.id.w = wszId.GetBuffer(); + + if (pUser->hContact != INVALID_CONTACT_ID) { + CMStringW wszNick = getMStringW(pUser->hContact, "Nick"); + CMStringW wszLastName = getMStringW(pUser->hContact, "LastName"); + CMStringW wszFirstName = getMStringW(pUser->hContact, "FirstName"); + + psr.nick.w = wszNick.GetBuffer(); + psr.lastName.w = wszLastName.GetBuffer(); + psr.firstName.w = wszFirstName.GetBuffer(); + } + else { + psr.firstName.w = pUser->wszFirstName.GetBuffer(); + psr.lastName.w = pUser->wszLastName.GetBuffer(); + psr.nick.w = pUser->wszNick.GetBuffer(); + } + + ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_DATA, this, (LPARAM)&psr); +} + +///////////////////////////////////////////////////////////////////////////////////////// + void CTelegramProto::UpdateString(MCONTACT hContact, const char *pszSetting, const std::string &str) { if (str.empty()) @@ -45,18 +93,28 @@ void CTelegramProto::UpdateString(MCONTACT hContact, const char *pszSetting, con ///////////////////////////////////////////////////////////////////////////////////////// // Users +TG_USER* CTelegramProto::FindChat(int64_t id) +{ + auto *tmp = (TG_USER *)_alloca(sizeof(TG_USER)); + tmp->chatId = id; + return m_arChats.find(tmp); +} + TG_USER* CTelegramProto::FindUser(int64_t id) { - if (auto *pCache = m_arUsers.find((TG_USER *)&id)) - return pCache; + return m_arUsers.find((TG_USER *)&id); +} - if (id < 0) { - id = -id; - if (auto *pCache = m_arUsers.find((TG_USER *)&id)) - return pCache; +TG_USER* CTelegramProto::AddFakeUser(int64_t id, bool bIsChat) +{ + auto *pu = FindUser(id); + if (pu == nullptr) { + pu = new TG_USER(id, INVALID_CONTACT_ID, bIsChat); + m_arUsers.insert(pu); + if (!bIsChat) + m_arChats.insert(pu); } - - return nullptr; + return pu; } TG_USER* CTelegramProto::AddUser(int64_t id, bool bIsChat) @@ -81,6 +139,8 @@ TG_USER* CTelegramProto::AddUser(int64_t id, bool bIsChat) pUser = new TG_USER(id, hContact, bIsChat); m_arUsers.insert(pUser); + if (!bIsChat) + m_arChats.insert(pUser); return pUser; } diff --git a/protocols/Telegram/src/utils.h b/protocols/Telegram/src/utils.h index 846428a086..d563350585 100644 --- a/protocols/Telegram/src/utils.h +++ b/protocols/Telegram/src/utils.h @@ -1,3 +1,4 @@ #pragma once -char *getSender(const TD::MessageSender *pSender, char *pDest, size_t cbSize); +const char *getName(const TD::usernames *pName); +const char *getSender(const TD::MessageSender *pSender, char *pDest, size_t cbSize); -- cgit v1.2.3