diff options
author | George Hazan <ghazan@miranda.im> | 2022-12-13 21:13:42 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2022-12-13 21:13:42 +0300 |
commit | 367fc21050725d43fe38eaed2b2474a6f0a42a51 (patch) | |
tree | b704c3c118f12490bea999eca827a13cb917e0cd /protocols | |
parent | 1113b5c3a26280a3c2a330361579c84f533be468 (diff) |
Telegram: - the first version of contact list reading
- the phone number is not a primary key anymore
Diffstat (limited to 'protocols')
-rw-r--r-- | protocols/Telegram/Telegram.vcxproj | 1 | ||||
-rw-r--r-- | protocols/Telegram/Telegram.vcxproj.filters | 3 | ||||
-rw-r--r-- | protocols/Telegram/src/auth.cpp | 127 | ||||
-rw-r--r-- | protocols/Telegram/src/main.cpp | 2 | ||||
-rw-r--r-- | protocols/Telegram/src/mt_proto.cpp | 23 | ||||
-rw-r--r-- | protocols/Telegram/src/mt_proto.h | 30 | ||||
-rw-r--r-- | protocols/Telegram/src/server.cpp | 163 | ||||
-rw-r--r-- | protocols/Telegram/src/stdafx.h | 2 | ||||
-rw-r--r-- | protocols/Telegram/src/utils.cpp | 46 |
9 files changed, 272 insertions, 125 deletions
diff --git a/protocols/Telegram/Telegram.vcxproj b/protocols/Telegram/Telegram.vcxproj index 2928b017a3..d1db70ba72 100644 --- a/protocols/Telegram/Telegram.vcxproj +++ b/protocols/Telegram/Telegram.vcxproj @@ -26,6 +26,7 @@ <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" /> </ImportGroup> <ItemGroup> + <ClCompile Include="src\auth.cpp" /> <ClCompile Include="src\main.cpp" /> <ClCompile Include="src\mt_proto.cpp" /> <ClCompile Include="src\options.cpp" /> diff --git a/protocols/Telegram/Telegram.vcxproj.filters b/protocols/Telegram/Telegram.vcxproj.filters index 4a38c95a4b..6c83ece5dd 100644 --- a/protocols/Telegram/Telegram.vcxproj.filters +++ b/protocols/Telegram/Telegram.vcxproj.filters @@ -17,6 +17,9 @@ <ClCompile Include="src\utils.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="src\auth.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClCompile Include="src\stdafx.cxx"> diff --git a/protocols/Telegram/src/auth.cpp b/protocols/Telegram/src/auth.cpp new file mode 100644 index 0000000000..a2ff59713c --- /dev/null +++ b/protocols/Telegram/src/auth.cpp @@ -0,0 +1,127 @@ +/* +Copyright (C) 2012-22 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" + +/////////////////////////////////////////////////////////////////////////////// + +INT_PTR CALLBACK CMTProto::EnterPhoneCode(void *param) +{ + auto *ppro = (CMTProto *)param; + + ENTER_STRING es = {}; + es.szModuleName = ppro->m_szModuleName; + es.caption = TranslateT("Enter secret code sent to your phone"); + if (EnterString(&es)) { + ppro->SendQuery(new td::td_api::checkAuthenticationCode(_T2A(es.ptszResult).get()), &CMTProto::OnUpdateAuth); + mir_free(es.ptszResult); + } + else ppro->LogOut(); + return 0; +} + +INT_PTR CALLBACK CMTProto::EnterPassword(void *param) +{ + auto *ppro = (CMTProto *)param; + CMStringW wszTitle(TranslateT("Enter password")); + + auto *pAuth = (td::td_api::authorizationStateWaitPassword *)ppro->pAuthState.get(); + if (!pAuth->password_hint_.empty()) + wszTitle.AppendFormat(TranslateT(" (hint: %s)"), Utf2T(pAuth->password_hint_.c_str()).get()); + + ENTER_STRING es = {}; + es.szModuleName = ppro->m_szModuleName; + es.caption = wszTitle; + es.type = ESF_PASSWORD; + if (EnterString(&es)) { + ppro->SendQuery(new td::td_api::checkAuthenticationPassword(_T2A(es.ptszResult).get()), &CMTProto::OnUpdateAuth); + mir_free(es.ptszResult); + } + else ppro->LogOut(); + return 0; +} + +void CMTProto::ProcessAuth(td::td_api::updateAuthorizationState *pObj) +{ + pAuthState = std::move(pObj->authorization_state_); + switch (pAuthState->get_id()) { + case td::td_api::authorizationStateWaitTdlibParameters::ID: + { + char text[100]; + Miranda_GetVersionText(text, sizeof(text)); + + CMStringW wszPath(GetProtoFolder()); + + auto *request = new td::td_api::setTdlibParameters(); + request->database_directory_ = T2Utf(wszPath).get(); + request->use_message_database_ = false; + request->use_secret_chats_ = true; + request->api_id_ = 94575; + request->api_hash_ = "a3406de8d171bb422bb6ddf3bbd800e2"; + request->system_language_code_ = "en"; + request->device_model_ = "Miranda NG"; + request->application_version_ = text; + request->enable_storage_optimizer_ = true; + SendQuery(request, &CMTProto::OnUpdateAuth); + } + break; + + case td::td_api::authorizationStateWaitPhoneNumber::ID: + SendQuery(new td::td_api::setAuthenticationPhoneNumber(_T2A(m_szOwnPhone).get(), nullptr), &CMTProto::OnUpdateAuth); + break; + + case td::td_api::authorizationStateWaitCode::ID: + CallFunctionSync(EnterPhoneCode, this); + break; + + case td::td_api::authorizationStateWaitPassword::ID: + CallFunctionSync(EnterPassword, this); + break; + + case td::td_api::authorizationStateReady::ID: + OnLoggedIn(); + break; + + case td::td_api::authorizationStateLoggingOut::ID: + debugLogA("Server required us to log out, exiting"); + LogOut(); + break; + + case td::td_api::authorizationStateClosing::ID: + debugLogA("Connection terminated, exiting"); + LogOut(); + break; + } +} + +void CMTProto::OnUpdateAuth(td::ClientManager::Response &response) +{ + if (response.object->get_id() == td::td_api::error::ID) { + auto *pError = (td::td_api::error *)response.object.get(); + debugLogA("error happened: %s", to_string(*pError).c_str()); + + if (pError->message_ == "PHONE_CODE_EXPIRED") + Popup(0, TranslateT("Phone code expired"), TranslateT("Error")); + else if (pError->message_ == "INVALID_PHONE_CODE") + Popup(0, TranslateT("Invalid phone code"), TranslateT("Error")); + else if (pError->message_ == "PASSWORD_HASH_INVALID") + Popup(0, TranslateT("Invalid password"), TranslateT("Error")); + + pAuthState = std::move(nullptr); + LogOut(); + } +} diff --git a/protocols/Telegram/src/main.cpp b/protocols/Telegram/src/main.cpp index 5e03db9f29..2cc1146b2a 100644 --- a/protocols/Telegram/src/main.cpp +++ b/protocols/Telegram/src/main.cpp @@ -29,7 +29,7 @@ PLUGININFOEX pluginInfo = CMPlugin::CMPlugin() : ACCPROTOPLUGIN<CMTProto>("Telegram", pluginInfo) { - SetUniqueId("Phone"); + SetUniqueId(DBKEY_ID); } ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/protocols/Telegram/src/mt_proto.cpp b/protocols/Telegram/src/mt_proto.cpp index 8f8476636b..eb5c7be0ee 100644 --- a/protocols/Telegram/src/mt_proto.cpp +++ b/protocols/Telegram/src/mt_proto.cpp @@ -1,8 +1,17 @@ #include "stdafx.h" +static int CompareUsers(const TG_USER *p1, const TG_USER *p2) +{ + if (p1->id == p2->id) + return 0; + + return (p1->id < p2->id) ? -1 : 1; +} + CMTProto::CMTProto(const char* protoName, const wchar_t* userName) : PROTO<CMTProto>(protoName, userName), m_pClientMmanager(std::make_unique<td::ClientManager>()), + m_arUsers(10, CompareUsers), m_arRequests(10, NumericKeySortT), m_szOwnPhone(this, "Phone"), m_wszDefaultGroup(this, "DefaultGroup", L"Telegram"), @@ -20,6 +29,20 @@ CMTProto::~CMTProto() { } +void CMTProto::OnModulesLoaded() +{ + CMStringA szId(getMStringA(DBKEY_ID)); + if (!szId.IsEmpty()) + m_arUsers.insert(new TG_USER(_atoi64(szId.c_str()), 0)); + + for (auto &cc : AccContacts()) { + bool isGroupChat = isChatRoom(cc); + szId = getMStringA(cc, isGroupChat ? "ChatRoomID" : DBKEY_ID); + if (!szId.IsEmpty()) + m_arUsers.insert(new TG_USER(_atoi64(szId.c_str()), cc, isGroupChat)); + } +} + void CMTProto::OnErase() { DeleteDirectoryTreeW(GetProtoFolder(), false); diff --git a/protocols/Telegram/src/mt_proto.h b/protocols/Telegram/src/mt_proto.h index 63de7bbcab..45e89bdc55 100644 --- a/protocols/Telegram/src/mt_proto.h +++ b/protocols/Telegram/src/mt_proto.h @@ -1,5 +1,7 @@ #pragma once +#define DBKEY_ID "id" + class CMTProto; typedef void (CMTProto::*TG_QUERY_HANDLER)(td::ClientManager::Response &response); @@ -14,6 +16,19 @@ struct TG_REQUEST TG_QUERY_HANDLER pHandler; }; +struct TG_USER +{ + TG_USER(uint64_t _1, MCONTACT _2, bool _3 = false) : + id(_1), + hContact(_2), + isGroupChat(_3) + {} + + uint64_t id; + MCONTACT hContact; + bool isGroupChat; +}; + class CMTProto : public PROTO<CMTProto> { std::unique_ptr<td::ClientManager> m_pClientMmanager; @@ -36,11 +51,21 @@ class CMTProto : public PROTO<CMTProto> void LogOut(void); void OnLoggedIn(void); - void ProcessAuth(td::td_api::updateAuthorizationState *pObj); - void ProcessGroups(td::td_api::updateChatFilters *pObj); void ProcessResponse(td::ClientManager::Response); void SendQuery(td::td_api::Function *pFunc, TG_QUERY_HANDLER pHandler = nullptr); + void ProcessAuth(td::td_api::updateAuthorizationState *pObj); + void ProcessGroups(td::td_api::updateChatFilters *pObj); + void ProcessUser(td::td_api::updateUser *pObj); + + void UpdateString(MCONTACT hContact, const char *pszSetting, const std::string &str); + + // Users + OBJLIST<TG_USER> m_arUsers; + + MCONTACT FindUser(uint64_t id); + MCONTACT AddUser(uint64_t id, bool bIsChat); + // Popups HANDLE m_hPopupClass; @@ -61,6 +86,7 @@ public: int SetStatus(int iNewStatus) override; + void OnModulesLoaded() override; void OnErase() override; // Services ////////////////////////////////////////////////////////////////////////// diff --git a/protocols/Telegram/src/server.cpp b/protocols/Telegram/src/server.cpp index a852c1ac93..6700034f60 100644 --- a/protocols/Telegram/src/server.cpp +++ b/protocols/Telegram/src/server.cpp @@ -54,113 +54,51 @@ void CMTProto::OnLoggedIn() ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, m_iDesiredStatus); m_iStatus = m_iDesiredStatus; + + SendQuery(new td::td_api::getChats(td::tl::unique_ptr<td::td_api::chatListMain>(), 1000)); } /////////////////////////////////////////////////////////////////////////////// -INT_PTR CALLBACK CMTProto::EnterPhoneCode(void *param) +void CMTProto::ProcessResponse(td::ClientManager::Response response) { - auto *ppro = (CMTProto *)param; - - ENTER_STRING es = {}; - es.szModuleName = ppro->m_szModuleName; - es.caption = TranslateT("Enter secret code sent to your phone"); - if (EnterString(&es)) { - ppro->SendQuery(new td::td_api::checkAuthenticationCode(_T2A(es.ptszResult).get()), &CMTProto::OnUpdateAuth); - mir_free(es.ptszResult); - } - else ppro->LogOut(); - return 0; -} + if (!response.object) + return; -INT_PTR CALLBACK CMTProto::EnterPassword(void *param) -{ - auto *ppro = (CMTProto *)param; - CMStringW wszTitle(TranslateT("Enter password")); - - auto *pAuth = (td::td_api::authorizationStateWaitPassword *)ppro->pAuthState.get(); - if (!pAuth->password_hint_.empty()) - wszTitle.AppendFormat(TranslateT(" (hint: %s)"), Utf2T(pAuth->password_hint_.c_str()).get()); - - ENTER_STRING es = {}; - es.szModuleName = ppro->m_szModuleName; - es.caption = wszTitle; - es.type = ESF_PASSWORD; - if (EnterString(&es)) { - ppro->SendQuery(new td::td_api::checkAuthenticationPassword(_T2A(es.ptszResult).get()), &CMTProto::OnUpdateAuth); - mir_free(es.ptszResult); - } - else ppro->LogOut(); - return 0; -} + debugLogA("ProcessResponse: id=%d (%s)", int(response.request_id), to_string(response.object).c_str()); -void CMTProto::ProcessAuth(td::td_api::updateAuthorizationState *pObj) -{ - pAuthState = std::move(pObj->authorization_state_); - switch (pAuthState->get_id()) { - case td::td_api::authorizationStateWaitTdlibParameters::ID: - { - char text[100]; - Miranda_GetVersionText(text, sizeof(text)); - - CMStringW wszPath(GetProtoFolder()); - - auto *request = new td::td_api::setTdlibParameters(); - request->database_directory_ = T2Utf(wszPath).get(); - request->use_message_database_ = false; - request->use_secret_chats_ = true; - request->api_id_ = 94575; - request->api_hash_ = "a3406de8d171bb422bb6ddf3bbd800e2"; - request->system_language_code_ = "en"; - request->device_model_ = "Miranda NG"; - request->application_version_ = text; - request->enable_storage_optimizer_ = true; - SendQuery(request, &CMTProto::OnUpdateAuth); + if (response.request_id) { + auto *p = m_arRequests.find((TG_REQUEST *)&response.request_id); + if (p) { + (this->*p->pHandler)(response); + m_arRequests.remove(p); } - break; - - case td::td_api::authorizationStateWaitPhoneNumber::ID: - SendQuery(new td::td_api::setAuthenticationPhoneNumber(_T2A(m_szOwnPhone).get(), nullptr), &CMTProto::OnUpdateAuth); - break; - - case td::td_api::authorizationStateWaitCode::ID: - CallFunctionSync(EnterPhoneCode, this); - break; + return; + } - case td::td_api::authorizationStateWaitPassword::ID: - CallFunctionSync(EnterPassword, this); + switch (response.object->get_id()) { + case td::td_api::updateAuthorizationState::ID: + ProcessAuth((td::td_api::updateAuthorizationState *)response.object.get()); break; - case td::td_api::authorizationStateReady::ID: - OnLoggedIn(); + case td::td_api::updateChatFilters::ID: + ProcessGroups((td::td_api::updateChatFilters *)response.object.get()); break; - case td::td_api::authorizationStateLoggingOut::ID: - debugLogA("Server required us to log out, exiting"); - LogOut(); + case td::td_api::updateUser::ID: + ProcessUser((td::td_api::updateUser *)response.object.get()); break; - case td::td_api::authorizationStateClosing::ID: - debugLogA("Connection terminated, exiting"); - LogOut(); - break; } } -void CMTProto::OnUpdateAuth(td::ClientManager::Response &response) +void CMTProto::SendQuery(td::td_api::Function *pFunc, TG_QUERY_HANDLER pHandler) { - if (response.object->get_id() == td::td_api::error::ID) { - auto *pError = (td::td_api::error*)response.object.get(); - debugLogA("error happened: %s", to_string(*pError).c_str()); - - if (pError->message_ == "PHONE_CODE_EXPIRED") - Popup(0, TranslateT("Phone code expired"), TranslateT("Error")); - else if(pError->message_ == "INVALID_PHONE_CODE") - Popup(0, TranslateT("Invalid phone code"), TranslateT("Error")); - - pAuthState = std::move(nullptr); - LogOut(); - } + int queryId = ++m_iQueryId; + m_pClientMmanager->send(m_iClientId, queryId, td::td_api::object_ptr<td::td_api::Function>(pFunc)); + + if (pHandler) + m_arRequests.insert(new TG_REQUEST(queryId, pHandler)); } /////////////////////////////////////////////////////////////////////////////// @@ -171,7 +109,7 @@ void CMTProto::ProcessGroups(td::td_api::updateChatFilters *pObj) if (grp->icon_name_ != "Custom") continue; - CMStringA szSetting("ChatFilter%d", grp->id_); + CMStringA szSetting(FORMAT, "ChatFilter%d", grp->id_); CMStringW wszOldValue(getMStringW(szSetting)); Utf2T wszNewValue(grp->title_.c_str()); if (wszOldValue.IsEmpty()) { @@ -189,40 +127,21 @@ void CMTProto::ProcessGroups(td::td_api::updateChatFilters *pObj) } } -/////////////////////////////////////////////////////////////////////////////// - -void CMTProto::ProcessResponse(td::ClientManager::Response response) +void CMTProto::ProcessUser(td::td_api::updateUser *pObj) { - if (!response.object) - return; - - debugLogA("ProcessResponse: id=%d (%s)", int(response.request_id), to_string(response.object).c_str()); - - if (response.request_id) { - auto *p = m_arRequests.find((TG_REQUEST *)&response.request_id); - if (p) { - (this->*p->pHandler)(response); - m_arRequests.remove(p); + auto *pUser = pObj->user_.get(); + + MCONTACT hContact = AddUser(pUser->id_, false); + UpdateString(hContact, "FirstName", pUser->first_name_); + UpdateString(hContact, "LastName", pUser->last_name_); + UpdateString(hContact, "Phone", pUser->phone_number_); + if (pUser->usernames_) + UpdateString(hContact, "Nick", pUser->usernames_->editable_username_); + + if (pUser->status_) { + if (pUser->status_->get_id() == td::td_api::userStatusOffline::ID) { + auto *pOffline = (td::td_api::userStatusOffline *)pUser->status_.get(); + setDword(hContact, "LastSeen", pOffline->was_online_); } - return; } - - switch (response.object->get_id()) { - case td::td_api::updateAuthorizationState::ID: - ProcessAuth((td::td_api::updateAuthorizationState *)response.object.get()); - break; - - case td::td_api::updateChatFilters::ID: - ProcessGroups((td::td_api::updateChatFilters *)response.object.get()); - break; - } -} - -void CMTProto::SendQuery(td::td_api::Function *pFunc, TG_QUERY_HANDLER pHandler) -{ - int queryId = ++m_iQueryId; - m_pClientMmanager->send(m_iClientId, queryId, td::td_api::object_ptr<td::td_api::Function>(pFunc)); - - if (pHandler) - m_arRequests.insert(new TG_REQUEST(queryId, pHandler)); } diff --git a/protocols/Telegram/src/stdafx.h b/protocols/Telegram/src/stdafx.h index dd58e471ee..c5a21971fb 100644 --- a/protocols/Telegram/src/stdafx.h +++ b/protocols/Telegram/src/stdafx.h @@ -3,6 +3,7 @@ #include <windows.h> +#include <map> #include <memory> #include <newpluginapi.h> @@ -11,6 +12,7 @@ #include <m_protosvc.h> #include <m_clist.h> +#include <m_contacts.h> #include <m_database.h> #include <m_icolib.h> #include <m_langpack.h> diff --git a/protocols/Telegram/src/utils.cpp b/protocols/Telegram/src/utils.cpp index 0228dc3756..7d16c34246 100644 --- a/protocols/Telegram/src/utils.cpp +++ b/protocols/Telegram/src/utils.cpp @@ -17,6 +17,52 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include "stdafx.h" +void CMTProto::UpdateString(MCONTACT hContact, const char *pszSetting, const std::string &str) +{ + if (str.empty()) + delSetting(hContact, pszSetting); + else + setUString(hContact, pszSetting, str.c_str()); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Users + +MCONTACT CMTProto::FindUser(uint64_t id) +{ + if (auto *pCache = m_arUsers.find((TG_USER *)&id)) + return pCache->hContact; + + return INVALID_CONTACT_ID; +} + +MCONTACT CMTProto::AddUser(uint64_t id, bool bIsChat) +{ + MCONTACT hContact = FindUser(id); + if (hContact == INVALID_CONTACT_ID) { + hContact = db_add_contact(); + Proto_AddToContact(hContact, m_szModuleName); + + char szId[100]; + _i64toa(id, szId, 10); + + if (bIsChat) { + Clist_SetGroup(hContact, TranslateT("Chat rooms")); + setByte(hContact, "ChatRoom", 1); + setString(hContact, "ChatRoomID", szId); + } + else { + setString(hContact, DBKEY_ID, szId); + if (mir_wstrlen(m_wszDefaultGroup)) + Clist_SetGroup(hContact, m_wszDefaultGroup); + } + + m_arUsers.insert(new TG_USER(id, hContact, bIsChat)); + } + + return hContact; +} + ///////////////////////////////////////////////////////////////////////////////////////// // Popups |