summaryrefslogtreecommitdiff
path: root/protocols
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2022-12-13 21:13:42 +0300
committerGeorge Hazan <ghazan@miranda.im>2022-12-13 21:13:42 +0300
commit367fc21050725d43fe38eaed2b2474a6f0a42a51 (patch)
treeb704c3c118f12490bea999eca827a13cb917e0cd /protocols
parent1113b5c3a26280a3c2a330361579c84f533be468 (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.vcxproj1
-rw-r--r--protocols/Telegram/Telegram.vcxproj.filters3
-rw-r--r--protocols/Telegram/src/auth.cpp127
-rw-r--r--protocols/Telegram/src/main.cpp2
-rw-r--r--protocols/Telegram/src/mt_proto.cpp23
-rw-r--r--protocols/Telegram/src/mt_proto.h30
-rw-r--r--protocols/Telegram/src/server.cpp163
-rw-r--r--protocols/Telegram/src/stdafx.h2
-rw-r--r--protocols/Telegram/src/utils.cpp46
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